summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Android.mk21
-rw-r--r--apct-tests/perftests/core/AndroidManifest.xml6
-rw-r--r--apct-tests/perftests/core/src/android/os/PackageManagerPerfTest.java114
-rw-r--r--apct-tests/perftests/core/src/android/os/PermissionTest.java66
-rw-r--r--apct-tests/perftests/core/src/android/text/StaticLayoutPerfTest.java8
-rw-r--r--api/current.txt231
-rw-r--r--api/system-current.txt76
-rw-r--r--cmds/incident_helper/src/TextParserBase.h2
-rw-r--r--cmds/incidentd/README.md4
-rw-r--r--cmds/incidentd/incidentd.rc2
-rw-r--r--cmds/incidentd/src/FdBuffer.cpp4
-rw-r--r--cmds/incidentd/src/IncidentService.cpp27
-rw-r--r--cmds/incidentd/src/Reporter.cpp2
-rw-r--r--cmds/incidentd/src/Section.cpp52
-rw-r--r--cmds/incidentd/src/io_util.cpp2
-rw-r--r--cmds/incidentd/src/report_directory.cpp26
-rw-r--r--cmds/statsd/Android.mk3
-rw-r--r--cmds/statsd/src/anomaly/AnomalyTracker.cpp3
-rw-r--r--cmds/statsd/src/atoms.proto94
-rw-r--r--cmds/statsd/src/condition/SimpleConditionTracker.cpp23
-rw-r--r--cmds/statsd/src/condition/condition_util.cpp8
-rw-r--r--cmds/statsd/src/config/ConfigManager.cpp32
-rw-r--r--cmds/statsd/src/dimension.cpp8
-rw-r--r--cmds/statsd/src/external/CpuTimePerUidFreqPuller.cpp2
-rw-r--r--cmds/statsd/src/external/KernelUidCpuActiveTimeReader.cpp89
-rw-r--r--cmds/statsd/src/external/KernelUidCpuActiveTimeReader.h34
-rw-r--r--cmds/statsd/src/external/KernelUidCpuClusterTimeReader.cpp88
-rw-r--r--cmds/statsd/src/external/KernelUidCpuClusterTimeReader.h42
-rw-r--r--cmds/statsd/src/external/Perfetto.cpp111
-rw-r--r--cmds/statsd/src/external/Perfetto.h35
-rw-r--r--cmds/statsd/src/external/StatsPullerManagerImpl.cpp2
-rw-r--r--cmds/statsd/src/metrics/ValueMetricProducer.cpp9
-rw-r--r--cmds/statsd/src/packages/UidMap.cpp6
-rw-r--r--cmds/statsd/src/packages/UidMap.h4
-rw-r--r--cmds/statsd/src/perfetto/perfetto_config.proto61
-rw-r--r--cmds/statsd/src/statsd_config.proto32
-rw-r--r--cmds/statsd/statsd.rc1
-rw-r--r--cmds/statsd/tests/e2e/GaugeMetric_e2e_test.cpp4
-rw-r--r--cmds/statsd/tests/e2e/MetricConditionLink_e2e_test.cpp10
-rw-r--r--cmds/statsd/tests/metrics/CountMetricProducer_test.cpp4
-rw-r--r--cmds/statsd/tests/metrics/EventMetricProducer_test.cpp4
-rw-r--r--cmds/statsd/tools/dogfood/Android.mk2
-rw-r--r--cmds/statsd/tools/loadtest/Android.mk1
-rw-r--r--core/java/android/accessibilityservice/AccessibilityService.java5
-rw-r--r--core/java/android/app/admin/DeviceAdminReceiver.java74
-rw-r--r--core/java/android/app/admin/DevicePolicyManager.java46
-rw-r--r--core/java/android/app/admin/IDevicePolicyManager.aidl4
-rw-r--r--core/java/android/app/job/JobInfo.java27
-rw-r--r--core/java/android/app/usage/UsageStatsManagerInternal.java6
-rw-r--r--core/java/android/content/Intent.java71
-rw-r--r--core/java/android/content/pm/PackageManagerInternal.java5
-rw-r--r--core/java/android/hardware/HardwareBuffer.java56
-rw-r--r--core/java/android/hardware/camera2/CameraDevice.java19
-rw-r--r--core/java/android/hardware/camera2/CameraMetadata.java14
-rw-r--r--core/java/android/hardware/camera2/CaptureRequest.java2
-rw-r--r--core/java/android/hardware/camera2/CaptureResult.java10
-rw-r--r--core/java/android/hardware/radio/ProgramSelector.java125
-rw-r--r--core/java/android/net/INetworkPolicyListener.aidl3
-rw-r--r--core/java/android/net/INetworkPolicyManager.aidl1
-rw-r--r--core/java/android/net/INetworkStatsService.aidl3
-rw-r--r--core/java/android/net/IpSecManager.java128
-rw-r--r--core/java/android/net/IpSecTransform.java16
-rw-r--r--core/java/android/net/NetworkIdentity.java24
-rw-r--r--core/java/android/net/NetworkPolicyManager.java12
-rw-r--r--core/java/android/net/NetworkStats.java88
-rw-r--r--core/java/android/os/BatteryStats.java70
-rw-r--r--core/java/android/os/IPermissionController.aidl1
-rw-r--r--core/java/android/os/Process.java6
-rw-r--r--core/java/android/os/RecoverySystem.java30
-rw-r--r--core/java/android/os/connectivity/GpsBatteryStats.aidl20
-rw-r--r--core/java/android/os/connectivity/GpsBatteryStats.java108
-rw-r--r--core/java/android/provider/Settings.java912
-rw-r--r--core/java/android/provider/SettingsValidators.java249
-rw-r--r--core/java/android/security/keystore/KeychainSnapshot.java84
-rw-r--r--core/java/android/service/autofill/AutofillFieldClassificationService.java125
-rw-r--r--core/java/android/service/autofill/FieldClassification.java27
-rw-r--r--core/java/android/service/autofill/IAutofillFieldClassificationService.aidl4
-rw-r--r--core/java/android/service/autofill/UserData.java9
-rw-r--r--core/java/android/text/style/BackgroundColorSpan.java54
-rw-r--r--core/java/android/text/style/ForegroundColorSpan.java49
-rw-r--r--core/java/android/util/DataUnit.java11
-rw-r--r--core/java/android/util/apk/ApkSignatureSchemeV2Verifier.java57
-rw-r--r--core/java/android/util/apk/ApkSignatureSchemeV3Verifier.java26
-rw-r--r--core/java/android/util/apk/ApkSignatureVerifier.java49
-rw-r--r--core/java/android/util/apk/ApkSigningBlockUtils.java20
-rw-r--r--core/java/android/util/apk/ApkVerityBuilder.java6
-rw-r--r--core/java/android/view/DisplayCutout.java43
-rw-r--r--core/java/android/view/IWindowSession.aidl32
-rw-r--r--core/java/android/view/SurfaceControl.aidl19
-rw-r--r--core/java/android/view/View.java130
-rw-r--r--core/java/android/view/accessibility/AccessibilityNodeInfo.java88
-rw-r--r--core/java/android/view/autofill/AutofillManager.java77
-rw-r--r--core/java/android/view/autofill/IAutoFillManager.aidl4
-rw-r--r--core/java/android/widget/MediaControlView2.java (renamed from core/java/android/widget/MediaController2.java)127
-rw-r--r--core/java/android/widget/TextView.java30
-rw-r--r--core/java/android/widget/VideoView2.java149
-rw-r--r--core/java/com/android/internal/app/IBatteryStats.aidl5
-rw-r--r--core/java/com/android/internal/net/NetworkStatsFactory.java2
-rw-r--r--core/java/com/android/internal/os/BatteryStatsHelper.java8
-rw-r--r--core/java/com/android/internal/os/BatteryStatsImpl.java213
-rw-r--r--core/java/com/android/internal/os/CpuPowerCalculator.java24
-rw-r--r--core/java/com/android/internal/os/KernelUidCpuActiveTimeReader.java146
-rw-r--r--core/java/com/android/internal/os/KernelUidCpuClusterTimeReader.java178
-rw-r--r--core/java/com/android/internal/os/PowerProfile.java198
-rw-r--r--core/java/com/android/internal/os/WakelockPowerCalculator.java2
-rw-r--r--core/java/com/android/internal/statusbar/IStatusBar.aidl2
-rw-r--r--core/java/com/android/internal/util/ArrayUtils.java4
-rw-r--r--core/java/com/android/internal/util/ConcurrentUtils.java25
-rw-r--r--core/java/com/android/internal/util/DumpUtils.java1
-rw-r--r--core/java/com/android/internal/util/ScreenshotHelper.java13
-rw-r--r--core/jni/android/opengl/util.cpp26
-rw-r--r--core/jni/android_media_AudioFormat.h30
-rw-r--r--core/jni/android_media_AudioSystem.cpp19
-rw-r--r--core/jni/android_media_AudioTrack.cpp72
-rw-r--r--core/jni/android_os_HwParcel.cpp4
-rw-r--r--core/jni/com_android_internal_net_NetworkStatsFactory.cpp9
-rw-r--r--core/res/AndroidManifest.xml10
-rw-r--r--core/res/res/values/attrs.xml2
-rw-r--r--core/res/res/values/config.xml26
-rw-r--r--core/res/res/values/ids.xml5
-rw-r--r--core/res/res/values/public.xml3
-rw-r--r--core/res/res/values/strings.xml8
-rw-r--r--core/res/res/values/symbols.xml8
-rw-r--r--core/res/res/xml/power_profile_test.xml116
-rw-r--r--core/tests/coretests/src/android/graphics/TypefaceSystemFallbackTest.java80
-rw-r--r--core/tests/coretests/src/android/provider/SettingsBackupTest.java5
-rw-r--r--core/tests/coretests/src/android/provider/SettingsValidatorsTest.java89
-rw-r--r--core/tests/coretests/src/com/android/internal/os/BatteryStatsCpuTimesTest.java186
-rw-r--r--core/tests/coretests/src/com/android/internal/os/BatteryStatsTests.java5
-rw-r--r--core/tests/coretests/src/com/android/internal/os/KernelUidCpuActiveTimeReaderTest.java240
-rw-r--r--core/tests/coretests/src/com/android/internal/os/KernelUidCpuClusterTimeReaderTest.java245
-rw-r--r--core/tests/coretests/src/com/android/internal/os/MockBatteryStatsImpl.java10
-rw-r--r--core/tests/coretests/src/com/android/internal/os/PowerProfileTest.java58
-rw-r--r--data/etc/platform.xml3
-rw-r--r--docs/html/reference/images/text/style/backgroundcolorspan.pngbin0 -> 16410 bytes
-rw-r--r--docs/html/reference/images/text/style/foregroundcolorspan.pngbin0 -> 18636 bytes
-rw-r--r--graphics/java/android/graphics/ImageDecoder.java140
-rw-r--r--graphics/java/android/graphics/Typeface.java4
-rw-r--r--graphics/java/android/graphics/drawable/AnimatedImageDrawable.java21
-rw-r--r--graphics/java/android/graphics/drawable/BitmapDrawable.java85
-rw-r--r--graphics/java/android/graphics/drawable/Drawable.java43
-rw-r--r--location/java/com/android/internal/location/gnssmetrics/GnssMetrics.java86
-rw-r--r--media/java/android/media/AudioFormat.java53
-rw-r--r--media/java/android/media/AudioManager.java42
-rw-r--r--media/java/android/media/AudioSystem.java12
-rw-r--r--media/java/android/media/AudioTrack.java145
-rw-r--r--media/java/android/media/IAudioService.aidl3
-rw-r--r--media/java/android/media/update/ApiLoader.java20
-rw-r--r--media/java/android/media/update/MediaControlView2Provider.java (renamed from media/java/android/media/update/MediaController2Provider.java)9
-rw-r--r--media/java/android/media/update/StaticProvider.java12
-rw-r--r--media/java/android/media/update/VideoView2Provider.java16
-rw-r--r--media/java/android/media/update/ViewProvider.java4
-rw-r--r--native/graphics/jni/Android.bp7
-rw-r--r--packages/ExtServices/AndroidManifest.xml6
-rw-r--r--packages/ExtServices/res/values/strings.xml5
-rw-r--r--packages/ExtServices/src/android/ext/services/autofill/AutofillFieldClassificationServiceImpl.java22
-rw-r--r--packages/SettingsLib/src/com/android/settingslib/core/instrumentation/EventLogWriter.java110
-rw-r--r--packages/SettingsLib/src/com/android/settingslib/core/instrumentation/Instrumentable.java28
-rw-r--r--packages/SettingsLib/src/com/android/settingslib/core/instrumentation/LogWriter.java84
-rw-r--r--packages/SettingsLib/src/com/android/settingslib/core/instrumentation/MetricsFeatureProvider.java159
-rw-r--r--packages/SettingsLib/src/com/android/settingslib/core/instrumentation/SharedPreferencesLogger.java259
-rw-r--r--packages/SettingsLib/src/com/android/settingslib/core/instrumentation/VisibilityLoggerMixin.java96
-rw-r--r--packages/SettingsLib/tests/robotests/src/com/android/settingslib/core/instrumentation/MetricsFeatureProviderTest.java132
-rw-r--r--packages/SettingsLib/tests/robotests/src/com/android/settingslib/core/instrumentation/SharedPreferenceLoggerTest.java181
-rw-r--r--packages/SettingsLib/tests/robotests/src/com/android/settingslib/core/instrumentation/VisibilityLoggerMixinTest.java122
-rw-r--r--packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java60
-rw-r--r--packages/Shell/AndroidManifest.xml3
-rw-r--r--packages/SystemUI/res-keyguard/layout/keyguard_pin_view.xml2
-rw-r--r--packages/SystemUI/res-keyguard/layout/keyguard_sim_pin_view.xml2
-rw-r--r--packages/SystemUI/res-keyguard/layout/keyguard_sim_puk_view.xml2
-rw-r--r--packages/SystemUI/res/layout/volume_dialog.xml3
-rw-r--r--packages/SystemUI/res/values-af/strings.xml42
-rw-r--r--packages/SystemUI/res/values-ar/strings.xml50
-rw-r--r--packages/SystemUI/res/values-az/strings.xml42
-rw-r--r--packages/SystemUI/res/values-b+sr+Latn/strings.xml44
-rw-r--r--packages/SystemUI/res/values-be/strings.xml46
-rw-r--r--packages/SystemUI/res/values-bg/strings.xml42
-rw-r--r--packages/SystemUI/res/values-bn/strings.xml60
-rw-r--r--packages/SystemUI/res/values-bs/strings.xml44
-rw-r--r--packages/SystemUI/res/values-ca/strings.xml42
-rw-r--r--packages/SystemUI/res/values-da/strings.xml39
-rw-r--r--packages/SystemUI/res/values-de/strings.xml54
-rw-r--r--packages/SystemUI/res/values-el/strings.xml42
-rw-r--r--packages/SystemUI/res/values-es-rUS/strings.xml42
-rw-r--r--packages/SystemUI/res/values-es/strings.xml39
-rw-r--r--packages/SystemUI/res/values-et/strings.xml42
-rw-r--r--packages/SystemUI/res/values-eu/strings.xml54
-rw-r--r--packages/SystemUI/res/values-fa/strings.xml39
-rw-r--r--packages/SystemUI/res/values-fi/strings.xml42
-rw-r--r--packages/SystemUI/res/values-gl/strings.xml42
-rw-r--r--packages/SystemUI/res/values-hi/strings.xml54
-rw-r--r--packages/SystemUI/res/values-hr/strings.xml44
-rw-r--r--packages/SystemUI/res/values-hu/strings.xml42
-rw-r--r--packages/SystemUI/res/values-hy/strings.xml42
-rw-r--r--packages/SystemUI/res/values-is/strings.xml42
-rw-r--r--packages/SystemUI/res/values-iw/strings.xml46
-rw-r--r--packages/SystemUI/res/values-ka/strings.xml42
-rw-r--r--packages/SystemUI/res/values-kk/strings.xml42
-rw-r--r--packages/SystemUI/res/values-km/strings.xml42
-rw-r--r--packages/SystemUI/res/values-ko/strings.xml42
-rw-r--r--packages/SystemUI/res/values-ky/strings.xml42
-rw-r--r--packages/SystemUI/res/values-lo/strings.xml42
-rw-r--r--packages/SystemUI/res/values-lv/strings.xml44
-rw-r--r--packages/SystemUI/res/values-mk/strings.xml42
-rw-r--r--packages/SystemUI/res/values-mn/strings.xml42
-rw-r--r--packages/SystemUI/res/values-ms/strings.xml42
-rw-r--r--packages/SystemUI/res/values-nb/strings.xml54
-rw-r--r--packages/SystemUI/res/values-ne/strings.xml54
-rw-r--r--packages/SystemUI/res/values-nl/strings.xml42
-rw-r--r--packages/SystemUI/res/values-pl/strings.xml46
-rw-r--r--packages/SystemUI/res/values-sk/strings.xml46
-rw-r--r--packages/SystemUI/res/values-sq/strings.xml42
-rw-r--r--packages/SystemUI/res/values-sr/strings.xml44
-rw-r--r--packages/SystemUI/res/values-sv/strings.xml42
-rw-r--r--packages/SystemUI/res/values-sw/strings.xml4
-rw-r--r--packages/SystemUI/res/values-ta/strings.xml60
-rw-r--r--packages/SystemUI/res/values-th/strings.xml42
-rw-r--r--packages/SystemUI/res/values-tl/strings.xml42
-rw-r--r--packages/SystemUI/res/values-tr/strings.xml42
-rw-r--r--packages/SystemUI/res/values-ur/strings.xml54
-rw-r--r--packages/SystemUI/res/values-vi/strings.xml42
-rw-r--r--packages/SystemUI/res/values-zh-rCN/strings.xml60
-rw-r--r--packages/SystemUI/res/values-zh-rHK/strings.xml42
-rw-r--r--packages/SystemUI/res/values-zh-rTW/strings.xml42
-rw-r--r--packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java20
-rw-r--r--packages/SystemUI/src/com/android/systemui/RecentsComponent.java2
-rw-r--r--packages/SystemUI/src/com/android/systemui/SwipeHelper.java16
-rw-r--r--packages/SystemUI/src/com/android/systemui/analytics/DataCollector.java4
-rw-r--r--packages/SystemUI/src/com/android/systemui/classifier/FalsingManager.java3
-rw-r--r--packages/SystemUI/src/com/android/systemui/recents/IRecentsNonSystemUserCallbacks.aidl2
-rw-r--r--packages/SystemUI/src/com/android/systemui/recents/Recents.java7
-rw-r--r--packages/SystemUI/src/com/android/systemui/recents/RecentsActivity.java20
-rw-r--r--packages/SystemUI/src/com/android/systemui/recents/RecentsImpl.java18
-rw-r--r--packages/SystemUI/src/com/android/systemui/recents/RecentsImplProxy.java9
-rw-r--r--packages/SystemUI/src/com/android/systemui/recents/misc/SystemServicesProxy.java17
-rw-r--r--packages/SystemUI/src/com/android/systemui/recents/views/TaskStackView.java15
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/CommandQueue.java10
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/KeyguardIndicationController.java23
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarTransitions.java23
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimController.java8
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java7
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/policy/DataSaverControllerImpl.java16
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/stack/AmbientState.java2
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/stack/StackScrollAlgorithm.java11
-rw-r--r--packages/SystemUI/src/com/android/systemui/volume/VolumeDialogImpl.java7
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/CommandQueueTest.java4
-rw-r--r--packages/VpnDialogs/res/values-hi/strings.xml2
-rw-r--r--packages/overlays/DisplayCutoutEmulationOverlay/res/values/config.xml31
-rw-r--r--proto/src/metrics_constants.proto13
-rw-r--r--proto/src/system_messages.proto3
-rw-r--r--services/accessibility/java/com/android/server/accessibility/GlobalActionPerformer.java27
-rw-r--r--services/autofill/java/com/android/server/autofill/AutofillManagerService.java17
-rw-r--r--services/autofill/java/com/android/server/autofill/AutofillManagerServiceImpl.java12
-rw-r--r--services/autofill/java/com/android/server/autofill/AutofillManagerServiceShellCommand.java5
-rw-r--r--services/autofill/java/com/android/server/autofill/FieldClassificationStrategy.java98
-rw-r--r--services/autofill/java/com/android/server/autofill/Session.java9
-rw-r--r--services/backup/java/com/android/server/backup/RefactoredBackupManagerService.java59
-rw-r--r--services/backup/java/com/android/server/backup/TransportManager.java28
-rw-r--r--services/backup/java/com/android/server/backup/transport/TransportClient.java55
-rw-r--r--services/backup/java/com/android/server/backup/transport/TransportClientManager.java32
-rw-r--r--services/backup/java/com/android/server/backup/transport/TransportUtils.java23
-rw-r--r--services/core/java/com/android/server/BatteryService.java8
-rw-r--r--services/core/java/com/android/server/BluetoothManagerService.java10
-rw-r--r--services/core/java/com/android/server/ConnectivityService.java33
-rw-r--r--services/core/java/com/android/server/ForceAppStandbyTracker.java17
-rw-r--r--services/core/java/com/android/server/am/ActivityManagerService.java10
-rw-r--r--services/core/java/com/android/server/am/ActivityStack.java2
-rw-r--r--services/core/java/com/android/server/am/BatteryStatsService.java17
-rw-r--r--services/core/java/com/android/server/am/GlobalSettingsToPropertiesMapper.java2
-rw-r--r--services/core/java/com/android/server/am/TaskRecord.java7
-rw-r--r--services/core/java/com/android/server/am/UserController.java12
-rw-r--r--services/core/java/com/android/server/audio/AudioService.java76
-rw-r--r--services/core/java/com/android/server/broadcastradio/hal2/TunerSession.java2
-rw-r--r--services/core/java/com/android/server/display/LocalDisplayAdapter.java11
-rwxr-xr-x[-rw-r--r--]services/core/java/com/android/server/hdmi/DeviceDiscoveryAction.java23
-rw-r--r--services/core/java/com/android/server/hdmi/HdmiCecLocalDeviceTv.java18
-rw-r--r--services/core/java/com/android/server/hdmi/HdmiControlService.java8
-rw-r--r--services/core/java/com/android/server/hdmi/HdmiUtils.java26
-rw-r--r--services/core/java/com/android/server/hdmi/SystemAudioStatusAction.java4
-rw-r--r--services/core/java/com/android/server/hdmi/VolumeControlAction.java4
-rw-r--r--services/core/java/com/android/server/job/controllers/ConnectivityController.java120
-rw-r--r--services/core/java/com/android/server/job/controllers/JobStatus.java53
-rw-r--r--services/core/java/com/android/server/location/GnssLocationProvider.java2
-rw-r--r--services/core/java/com/android/server/locksettings/recoverablekeystore/KeySyncTask.java20
-rw-r--r--services/core/java/com/android/server/locksettings/recoverablekeystore/KeySyncUtils.java2
-rw-r--r--services/core/java/com/android/server/net/NetworkIdentitySet.java28
-rw-r--r--services/core/java/com/android/server/net/NetworkPolicyManagerInternal.java24
-rw-r--r--services/core/java/com/android/server/net/NetworkPolicyManagerService.java260
-rw-r--r--services/core/java/com/android/server/net/NetworkStatsCollection.java4
-rw-r--r--services/core/java/com/android/server/net/NetworkStatsService.java41
-rw-r--r--services/core/java/com/android/server/net/watchlist/NetworkWatchlistService.java16
-rw-r--r--services/core/java/com/android/server/net/watchlist/PrivacyUtils.java103
-rw-r--r--services/core/java/com/android/server/net/watchlist/ReportEncoder.java126
-rw-r--r--services/core/java/com/android/server/net/watchlist/WatchlistConfig.java245
-rw-r--r--services/core/java/com/android/server/net/watchlist/WatchlistLoggingHandler.java131
-rw-r--r--services/core/java/com/android/server/net/watchlist/WatchlistReportDbHelper.java31
-rw-r--r--services/core/java/com/android/server/net/watchlist/WatchlistSettings.java202
-rw-r--r--services/core/java/com/android/server/pm/PackageManagerService.java15
-rw-r--r--services/core/java/com/android/server/policy/PhoneWindowManager.java12
-rw-r--r--services/core/java/com/android/server/policy/WindowManagerPolicy.java2
-rw-r--r--services/core/java/com/android/server/stats/StatsCompanionService.java15
-rw-r--r--services/core/java/com/android/server/statusbar/StatusBarManagerInternal.java2
-rw-r--r--services/core/java/com/android/server/statusbar/StatusBarManagerService.java4
-rw-r--r--services/core/java/com/android/server/vr/VrManagerService.java36
-rw-r--r--services/core/java/com/android/server/wm/DisplayContent.java90
-rw-r--r--services/core/java/com/android/server/wm/DockedStackDividerController.java2
-rw-r--r--services/core/java/com/android/server/wm/DragDropController.java150
-rw-r--r--services/core/java/com/android/server/wm/Session.java19
-rw-r--r--services/core/java/com/android/server/wm/WindowManagerService.java4
-rw-r--r--services/devicepolicy/java/com/android/server/devicepolicy/BaseIDevicePolicyManager.java21
-rw-r--r--services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java143
-rw-r--r--services/print/java/com/android/server/print/PrintManagerService.java33
-rw-r--r--services/robotests/src/com/android/server/backup/TransportManagerTest.java40
-rw-r--r--services/tests/servicestests/assets/NetworkWatchlistTest/watchlist_config_test1.xml27
-rw-r--r--services/tests/servicestests/assets/NetworkWatchlistTest/watchlist_settings_test1.xml29
-rw-r--r--services/tests/servicestests/assets/NetworkWatchlistTest/watchlist_settings_test2.xml4
-rw-r--r--services/tests/servicestests/src/com/android/server/ForceAppStandbyTrackerTest.java48
-rw-r--r--services/tests/servicestests/src/com/android/server/NetworkPolicyManagerServiceTest.java75
-rw-r--r--services/tests/servicestests/src/com/android/server/accessibility/GlobalActionPerformerTest.java18
-rw-r--r--services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerServiceTestable.java11
-rw-r--r--services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java21
-rw-r--r--services/tests/servicestests/src/com/android/server/devicepolicy/MockSystemServices.java4
-rw-r--r--services/tests/servicestests/src/com/android/server/job/JobStoreTest.java13
-rw-r--r--services/tests/servicestests/src/com/android/server/job/controllers/ConnectivityControllerTest.java169
-rw-r--r--services/tests/servicestests/src/com/android/server/job/controllers/JobStatusTest.java76
-rw-r--r--services/tests/servicestests/src/com/android/server/locksettings/recoverablekeystore/KeySyncTaskTest.java12
-rw-r--r--services/tests/servicestests/src/com/android/server/locksettings/recoverablekeystore/KeySyncUtilsTest.java5
-rw-r--r--services/tests/servicestests/src/com/android/server/locksettings/recoverablekeystore/RecoverableKeyStoreManagerTest.java2
-rw-r--r--services/tests/servicestests/src/com/android/server/locksettings/recoverablekeystore/storage/RecoverySessionStorageTest.java2
-rw-r--r--services/tests/servicestests/src/com/android/server/net/watchlist/PrivacyUtilsTests.java105
-rw-r--r--services/tests/servicestests/src/com/android/server/net/watchlist/ReportUtilsTests.java119
-rw-r--r--services/tests/servicestests/src/com/android/server/net/watchlist/WatchlistConfigTests.java147
-rw-r--r--services/tests/servicestests/src/com/android/server/net/watchlist/WatchlistLoggingHandlerTests.java8
-rw-r--r--services/tests/servicestests/src/com/android/server/net/watchlist/WatchlistSettingsTests.java101
-rw-r--r--services/tests/servicestests/src/com/android/server/wm/DragDropControllerTests.java42
-rw-r--r--services/tests/servicestests/src/com/android/server/wm/TestWindowManagerPolicy.java2
-rw-r--r--services/tests/servicestests/src/com/android/server/wm/ZOrderingTests.java165
-rw-r--r--services/usage/java/com/android/server/usage/AppStandbyController.java24
-rw-r--r--services/usage/java/com/android/server/usage/UsageStatsService.java5
-rw-r--r--telephony/java/android/telephony/SubscriptionInfo.java42
-rw-r--r--telephony/java/android/telephony/SubscriptionManager.java83
-rw-r--r--telephony/java/android/telephony/TelephonyManager.java90
-rw-r--r--telephony/java/com/android/internal/telephony/IccCardConstants.java14
-rw-r--r--tests/UiBench/src/com/android/test/uibench/leanback/BrowseFragment.java1
-rw-r--r--tests/UiBench/src/com/android/test/uibench/leanback/TestHelper.java9
-rw-r--r--tests/net/java/android/net/NetworkStatsTest.java460
-rw-r--r--tests/net/java/com/android/internal/net/NetworkStatsFactoryTest.java7
-rw-r--r--tests/net/java/com/android/server/ConnectivityServiceTest.java26
-rw-r--r--tests/net/java/com/android/server/net/NetworkStatsCollectionTest.java4
-rw-r--r--tests/net/java/com/android/server/net/NetworkStatsObserversTest.java67
-rw-r--r--tests/net/java/com/android/server/net/NetworkStatsServiceTest.java152
-rw-r--r--tests/permission/src/com/android/framework/permission/tests/ServiceManagerPermissionTests.java5
-rw-r--r--tools/aapt2/ResourceTable.cpp23
-rw-r--r--tools/aapt2/ResourceTable.h8
-rw-r--r--tools/aapt2/Resources.proto21
-rw-r--r--tools/aapt2/format/proto/ProtoDeserialize.cpp66
-rw-r--r--tools/aapt2/format/proto/ProtoSerialize.cpp47
-rw-r--r--tools/aapt2/format/proto/ProtoSerialize_test.cpp105
-rw-r--r--tools/aapt2/link/ManifestFixer.cpp1
-rwxr-xr-xtools/fonts/fontchain_linter.py3
-rw-r--r--wifi/java/android/net/wifi/WifiConfiguration.java9
361 files changed, 12509 insertions, 4019 deletions
diff --git a/Android.mk b/Android.mk
index 73c1ccdd05fa..d823be2ef9f3 100644
--- a/Android.mk
+++ b/Android.mk
@@ -72,12 +72,6 @@ non_base_dirs := \
../opt/net/voip/src/java/android/net/rtp \
../opt/net/voip/src/java/android/net/sip \
-framework_base_android_test_base_src_files := \
- $(call all-java-files-under, test-base/src/junit)
-
-framework_base_android_test_runner_src_files := \
- $(call all-java-files-under, test-runner/src/junit)
-
# Find all files in specific directories (relative to frameworks/base)
# to document and check apis
files_to_check_apis := \
@@ -126,8 +120,6 @@ framework_docs_LOCAL_SRC_FILES := \
# These are relative to frameworks/base
framework_docs_LOCAL_API_CHECK_SRC_FILES := \
- $(framework_base_android_test_base_src_files) \
- $(framework_base_android_test_runner_src_files) \
$(files_to_check_apis) \
$(common_src_files) \
@@ -339,6 +331,8 @@ LOCAL_DROIDDOC_OPTIONS:=\
$(framework_docs_LOCAL_DROIDDOC_OPTIONS) \
-referenceonly \
-api $(INTERNAL_PLATFORM_API_FILE) \
+ -privateApi $(INTERNAL_PLATFORM_PRIVATE_API_FILE) \
+ -privateDexApi $(INTERNAL_PLATFORM_PRIVATE_DEX_API_FILE) \
-removedApi $(INTERNAL_PLATFORM_REMOVED_API_FILE) \
-nodocs
@@ -348,7 +342,9 @@ LOCAL_UNINSTALLABLE_MODULE := true
include $(BUILD_DROIDDOC)
-$(INTERNAL_PLATFORM_API_FILE): $(full_target)
+$(full_target): .KATI_IMPLICIT_OUTPUTS := $(INTERNAL_PLATFORM_API_FILE) \
+ $(INTERNAL_PLATFORM_PRIVATE_API_FILE) \
+ $(INTERNAL_PLATFORM_PRIVATE_DEX_API_FILE)
$(call dist-for-goals,sdk,$(INTERNAL_PLATFORM_API_FILE))
# ==== the system api stubs ===================================
@@ -373,6 +369,8 @@ LOCAL_DROIDDOC_OPTIONS:=\
-referenceonly \
-showAnnotation android.annotation.SystemApi \
-api $(INTERNAL_PLATFORM_SYSTEM_API_FILE) \
+ -privateApi $(INTERNAL_PLATFORM_SYSTEM_PRIVATE_API_FILE) \
+ -privateDexApi $(INTERNAL_PLATFORM_SYSTEM_PRIVATE_DEX_API_FILE) \
-removedApi $(INTERNAL_PLATFORM_SYSTEM_REMOVED_API_FILE) \
-exactApi $(INTERNAL_PLATFORM_SYSTEM_EXACT_API_FILE) \
-nodocs
@@ -383,7 +381,9 @@ LOCAL_UNINSTALLABLE_MODULE := true
include $(BUILD_DROIDDOC)
-$(INTERNAL_PLATFORM_SYSTEM_API_FILE): $(full_target)
+$(full_target): .KATI_IMPLICIT_OUTPUTS := $(INTERNAL_PLATFORM_SYSTEM_API_FILE) \
+ $(INTERNAL_PLATFORM_SYSTEM_PRIVATE_API_FILE) \
+ $(INTERNAL_PLATFORM_SYSTEM_PRIVATE_DEX_API_FILE)
$(call dist-for-goals,sdk,$(INTERNAL_PLATFORM_SYSTEM_API_FILE))
# ==== the test api stubs ===================================
@@ -789,6 +789,7 @@ LOCAL_PROTOC_FLAGS := \
LOCAL_SOURCE_FILES_ALL_GENERATED := true
LOCAL_SRC_FILES := \
cmds/am/proto/instrumentation_data.proto \
+ cmds/statsd/src/perfetto/perfetto_config.proto \
$(call all-proto-files-under, core/proto) \
$(call all-proto-files-under, libs/incident/proto) \
$(call all-proto-files-under, cmds/statsd/src)
diff --git a/apct-tests/perftests/core/AndroidManifest.xml b/apct-tests/perftests/core/AndroidManifest.xml
index bd0b944e1233..132a2f9b2d0c 100644
--- a/apct-tests/perftests/core/AndroidManifest.xml
+++ b/apct-tests/perftests/core/AndroidManifest.xml
@@ -10,7 +10,11 @@
<application>
<uses-library android:name="android.test.runner" />
- <activity android:name="android.perftests.utils.StubActivity" />
+ <activity android:name="android.perftests.utils.StubActivity">
+ <intent-filter>
+ <action android:name="com.android.perftests.core.PERFTEST" />
+ </intent-filter>
+ </activity>
<service android:name="android.os.SomeService" android:exported="false" android:process=":some_service" />
</application>
diff --git a/apct-tests/perftests/core/src/android/os/PackageManagerPerfTest.java b/apct-tests/perftests/core/src/android/os/PackageManagerPerfTest.java
new file mode 100644
index 000000000000..145fbcd2d5d7
--- /dev/null
+++ b/apct-tests/perftests/core/src/android/os/PackageManagerPerfTest.java
@@ -0,0 +1,114 @@
+/*
+ * 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.os;
+
+import static android.content.pm.PackageManager.PERMISSION_DENIED;
+import static android.content.pm.PackageManager.PERMISSION_GRANTED;
+
+import android.content.ComponentName;
+import android.content.Context;
+import android.content.Intent;
+import android.content.pm.PackageManager;
+import android.perftests.utils.BenchmarkState;
+import android.perftests.utils.PerfStatusReporter;
+import android.support.test.InstrumentationRegistry;
+import android.support.test.filters.LargeTest;
+import android.support.test.runner.AndroidJUnit4;
+
+import org.junit.Assert;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+@RunWith(AndroidJUnit4.class)
+@LargeTest
+public class PackageManagerPerfTest {
+ private static final String PERMISSION_NAME_EXISTS =
+ "com.android.perftests.core.TestPermission";
+ private static final String PERMISSION_NAME_DOESNT_EXIST =
+ "com.android.perftests.core.TestBadPermission";
+ private static final ComponentName TEST_ACTIVITY =
+ new ComponentName("com.android.perftests.core", "android.perftests.utils.StubActivity");
+
+ @Rule
+ public PerfStatusReporter mPerfStatusReporter = new PerfStatusReporter();
+
+ @Test
+ public void testCheckPermissionExists() {
+ final BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
+ final PackageManager pm = InstrumentationRegistry.getTargetContext().getPackageManager();
+ final String packageName = TEST_ACTIVITY.getPackageName();
+
+ while (state.keepRunning()) {
+ int ret = pm.checkPermission(PERMISSION_NAME_EXISTS, packageName);
+ }
+ }
+
+ @Test
+ public void testCheckPermissionDoesntExist() {
+ final BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
+ final PackageManager pm = InstrumentationRegistry.getTargetContext().getPackageManager();
+ final String packageName = TEST_ACTIVITY.getPackageName();
+
+ while (state.keepRunning()) {
+ int ret = pm.checkPermission(PERMISSION_NAME_DOESNT_EXIST, packageName);
+ }
+ }
+
+ @Test
+ public void testQueryIntentActivities() {
+ final BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
+ final PackageManager pm = InstrumentationRegistry.getTargetContext().getPackageManager();
+ final Intent intent = new Intent("com.android.perftests.core.PERFTEST");
+
+ while (state.keepRunning()) {
+ pm.queryIntentActivities(intent, 0);
+ }
+ }
+
+ @Test
+ public void testGetPackageInfo() throws Exception {
+ final BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
+ final PackageManager pm = InstrumentationRegistry.getTargetContext().getPackageManager();
+ final String packageName = TEST_ACTIVITY.getPackageName();
+
+ while (state.keepRunning()) {
+ pm.getPackageInfo(packageName, 0);
+ }
+ }
+
+ @Test
+ public void testGetApplicationInfo() throws Exception {
+ final BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
+ final PackageManager pm = InstrumentationRegistry.getTargetContext().getPackageManager();
+ final String packageName = TEST_ACTIVITY.getPackageName();
+
+ while (state.keepRunning()) {
+ pm.getApplicationInfo(packageName, 0);
+ }
+ }
+
+ @Test
+ public void testGetActivityInfo() throws Exception {
+ final BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
+ final PackageManager pm = InstrumentationRegistry.getTargetContext().getPackageManager();
+
+ while (state.keepRunning()) {
+ pm.getActivityInfo(TEST_ACTIVITY, 0);
+ }
+ }
+}
diff --git a/apct-tests/perftests/core/src/android/os/PermissionTest.java b/apct-tests/perftests/core/src/android/os/PermissionTest.java
deleted file mode 100644
index d292e7dc3b96..000000000000
--- a/apct-tests/perftests/core/src/android/os/PermissionTest.java
+++ /dev/null
@@ -1,66 +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 android.os;
-
-import static android.content.pm.PackageManager.PERMISSION_DENIED;
-import static android.content.pm.PackageManager.PERMISSION_GRANTED;
-
-import android.content.Context;
-import android.perftests.utils.BenchmarkState;
-import android.perftests.utils.PerfStatusReporter;
-import android.support.test.InstrumentationRegistry;
-import android.support.test.filters.LargeTest;
-import android.support.test.runner.AndroidJUnit4;
-
-import org.junit.Assert;
-import org.junit.Rule;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-
-@RunWith(AndroidJUnit4.class)
-@LargeTest
-public class PermissionTest {
- private static final String PERMISSION_HAS_NAME = "com.android.perftests.core.TestPermission";
- private static final String PERMISSION_DOESNT_HAVE_NAME =
- "com.android.perftests.core.TestBadPermission";
- private static final String THIS_PACKAGE_NAME = "com.android.perftests.core";
-
- @Rule
- public PerfStatusReporter mPerfStatusReporter = new PerfStatusReporter();
-
- @Test
- public void testHasPermission() {
- final BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
- final Context context = InstrumentationRegistry.getTargetContext();
- while (state.keepRunning()) {
- int ret = context.getPackageManager().checkPermission(PERMISSION_HAS_NAME,
- THIS_PACKAGE_NAME);
- }
- }
-
- @Test
- public void testDoesntHavePermission() {
- final BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
- final Context context = InstrumentationRegistry.getTargetContext();
-
- while (state.keepRunning()) {
- int ret = context.getPackageManager().checkPermission(PERMISSION_DOESNT_HAVE_NAME,
- THIS_PACKAGE_NAME);
- }
- }
-
-}
diff --git a/apct-tests/perftests/core/src/android/text/StaticLayoutPerfTest.java b/apct-tests/perftests/core/src/android/text/StaticLayoutPerfTest.java
index 0ac167f73d16..6975609d990a 100644
--- a/apct-tests/perftests/core/src/android/text/StaticLayoutPerfTest.java
+++ b/apct-tests/perftests/core/src/android/text/StaticLayoutPerfTest.java
@@ -29,6 +29,7 @@ import android.graphics.Typeface;
import android.text.Layout;
import android.text.style.TextAppearanceSpan;
+import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;
@@ -52,7 +53,7 @@ public class StaticLayoutPerfTest {
private static final boolean NO_STYLE_TEXT = false;
private static final boolean STYLE_TEXT = true;
- private final Random mRandom = new Random(31415926535L);
+ private Random mRandom;
private static final String ALPHABET = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
private static final int ALPHABET_LENGTH = ALPHABET.length();
@@ -98,6 +99,11 @@ public class StaticLayoutPerfTest {
return ssb;
}
+ @Before
+ public void setUp() {
+ mRandom = new Random(0);
+ }
+
@Test
public void testCreate_FixedText_NoStyle_Greedy_NoHyphenation() {
final BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
diff --git a/api/current.txt b/api/current.txt
index 06f3b2ac8f1c..3e4dfd217dcc 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -211,6 +211,7 @@ package android {
field public static final int accessibilityEventTypes = 16843648; // 0x1010380
field public static final int accessibilityFeedbackType = 16843650; // 0x1010382
field public static final int accessibilityFlags = 16843652; // 0x1010384
+ field public static final int accessibilityHeading = 16844160; // 0x1010580
field public static final int accessibilityLiveRegion = 16843758; // 0x10103ee
field public static final int accessibilityPaneTitle = 16844156; // 0x101057c
field public static final int accessibilityTraversalAfter = 16843986; // 0x10104d2
@@ -1808,6 +1809,7 @@ package android {
public static final class R.id {
ctor public R.id();
field public static final int accessibilityActionContextClick = 16908348; // 0x102003c
+ field public static final int accessibilityActionHideTooltip = 16908357; // 0x1020045
field public static final int accessibilityActionMoveWindow = 16908354; // 0x1020042
field public static final int accessibilityActionScrollDown = 16908346; // 0x102003a
field public static final int accessibilityActionScrollLeft = 16908345; // 0x1020039
@@ -1816,6 +1818,7 @@ package android {
field public static final int accessibilityActionScrollUp = 16908344; // 0x1020038
field public static final int accessibilityActionSetProgress = 16908349; // 0x102003d
field public static final int accessibilityActionShowOnScreen = 16908342; // 0x1020036
+ field public static final int accessibilityActionShowTooltip = 16908356; // 0x1020044
field public static final int addToDictionary = 16908330; // 0x102002a
field public static final int autofill = 16908355; // 0x1020043
field public static final int background = 16908288; // 0x1020000
@@ -2795,6 +2798,7 @@ package android.accessibilityservice {
field public static final int GLOBAL_ACTION_POWER_DIALOG = 6; // 0x6
field public static final int GLOBAL_ACTION_QUICK_SETTINGS = 5; // 0x5
field public static final int GLOBAL_ACTION_RECENTS = 3; // 0x3
+ field public static final int GLOBAL_ACTION_TAKE_SCREENSHOT = 9; // 0x9
field public static final int GLOBAL_ACTION_TOGGLE_SPLIT_SCREEN = 7; // 0x7
field public static final java.lang.String SERVICE_INTERFACE = "android.accessibilityservice.AccessibilityService";
field public static final java.lang.String SERVICE_META_DATA = "android.accessibilityservice";
@@ -6345,6 +6349,9 @@ package android.app.admin {
method public void onTransferOwnershipComplete(android.content.Context, android.os.PersistableBundle);
method public void onUserAdded(android.content.Context, android.content.Intent, android.os.UserHandle);
method public void onUserRemoved(android.content.Context, android.content.Intent, android.os.UserHandle);
+ method public void onUserStarted(android.content.Context, android.content.Intent, android.os.UserHandle);
+ method public void onUserStopped(android.content.Context, android.content.Intent, android.os.UserHandle);
+ method public void onUserSwitched(android.content.Context, android.content.Intent, android.os.UserHandle);
field public static final java.lang.String ACTION_DEVICE_ADMIN_DISABLED = "android.app.action.DEVICE_ADMIN_DISABLED";
field public static final java.lang.String ACTION_DEVICE_ADMIN_DISABLE_REQUESTED = "android.app.action.DEVICE_ADMIN_DISABLE_REQUESTED";
field public static final java.lang.String ACTION_DEVICE_ADMIN_ENABLED = "android.app.action.DEVICE_ADMIN_ENABLED";
@@ -6991,6 +6998,7 @@ package android.app.job {
method public android.app.job.JobInfo.Builder setEstimatedNetworkBytes(long);
method public android.app.job.JobInfo.Builder setExtras(android.os.PersistableBundle);
method public android.app.job.JobInfo.Builder setImportantWhileForeground(boolean);
+ method public android.app.job.JobInfo.Builder setIsPrefetch(boolean);
method public android.app.job.JobInfo.Builder setMinimumLatency(long);
method public android.app.job.JobInfo.Builder setOverrideDeadline(long);
method public android.app.job.JobInfo.Builder setPeriodic(long);
@@ -15228,18 +15236,26 @@ package android.hardware {
method public void writeToParcel(android.os.Parcel, int);
field public static final int BLOB = 33; // 0x21
field public static final android.os.Parcelable.Creator<android.hardware.HardwareBuffer> CREATOR;
+ field public static final int DS_24UI8 = 50; // 0x32
+ field public static final int DS_FP32UI8 = 52; // 0x34
+ field public static final int D_16 = 48; // 0x30
+ field public static final int D_24 = 49; // 0x31
+ field public static final int D_FP32 = 51; // 0x33
field public static final int RGBA_1010102 = 43; // 0x2b
field public static final int RGBA_8888 = 1; // 0x1
field public static final int RGBA_FP16 = 22; // 0x16
field public static final int RGBX_8888 = 2; // 0x2
field public static final int RGB_565 = 4; // 0x4
field public static final int RGB_888 = 3; // 0x3
+ field public static final int S_UI8 = 53; // 0x35
field public static final long USAGE_CPU_READ_OFTEN = 3L; // 0x3L
field public static final long USAGE_CPU_READ_RARELY = 2L; // 0x2L
field public static final long USAGE_CPU_WRITE_OFTEN = 48L; // 0x30L
field public static final long USAGE_CPU_WRITE_RARELY = 32L; // 0x20L
field public static final long USAGE_GPU_COLOR_OUTPUT = 512L; // 0x200L
+ field public static final long USAGE_GPU_CUBE_MAP = 33554432L; // 0x2000000L
field public static final long USAGE_GPU_DATA_BUFFER = 16777216L; // 0x1000000L
+ field public static final long USAGE_GPU_MIPMAP_COMPLETE = 67108864L; // 0x4000000L
field public static final long USAGE_GPU_SAMPLED_IMAGE = 256L; // 0x100L
field public static final long USAGE_PROTECTED_CONTENT = 16384L; // 0x4000L
field public static final long USAGE_SENSOR_DIRECT_DATA = 8388608L; // 0x800000L
@@ -15725,6 +15741,7 @@ package android.hardware.camera2 {
field public static final int CONTROL_AE_MODE_ON_ALWAYS_FLASH = 3; // 0x3
field public static final int CONTROL_AE_MODE_ON_AUTO_FLASH = 2; // 0x2
field public static final int CONTROL_AE_MODE_ON_AUTO_FLASH_REDEYE = 4; // 0x4
+ field public static final int CONTROL_AE_MODE_ON_EXTERNAL_FLASH = 5; // 0x5
field public static final int CONTROL_AE_PRECAPTURE_TRIGGER_CANCEL = 2; // 0x2
field public static final int CONTROL_AE_PRECAPTURE_TRIGGER_IDLE = 0; // 0x0
field public static final int CONTROL_AE_PRECAPTURE_TRIGGER_START = 1; // 0x1
@@ -37904,7 +37921,6 @@ package android.service.autofill {
}
public static final class FieldClassification.Match {
- method public java.lang.String getAlgorithm();
method public java.lang.String getRemoteId();
method public float getScore();
}
@@ -44081,6 +44097,18 @@ package android.util {
field public static final deprecated boolean RELEASE = true;
}
+ public class DataUnit extends java.lang.Enum {
+ method public long toBytes(long);
+ method public static android.util.DataUnit valueOf(java.lang.String);
+ method public static final android.util.DataUnit[] values();
+ enum_constant public static final android.util.DataUnit GIBIBYTES;
+ enum_constant public static final android.util.DataUnit GIGABYTES;
+ enum_constant public static final android.util.DataUnit KIBIBYTES;
+ enum_constant public static final android.util.DataUnit KILOBYTES;
+ enum_constant public static final android.util.DataUnit MEBIBYTES;
+ enum_constant public static final android.util.DataUnit MEGABYTES;
+ }
+
public class DebugUtils {
method public static boolean isObjectSelected(java.lang.Object);
}
@@ -48185,6 +48213,7 @@ package android.view.accessibility {
method public java.lang.CharSequence getText();
method public int getTextSelectionEnd();
method public int getTextSelectionStart();
+ method public java.lang.CharSequence getTooltipText();
method public android.view.accessibility.AccessibilityNodeInfo getTraversalAfter();
method public android.view.accessibility.AccessibilityNodeInfo getTraversalBefore();
method public java.lang.String getViewIdResourceName();
@@ -48201,6 +48230,7 @@ package android.view.accessibility {
method public boolean isEnabled();
method public boolean isFocusable();
method public boolean isFocused();
+ method public boolean isHeading();
method public boolean isImportantForAccessibility();
method public boolean isLongClickable();
method public boolean isMultiLine();
@@ -48244,6 +48274,7 @@ package android.view.accessibility {
method public void setError(java.lang.CharSequence);
method public void setFocusable(boolean);
method public void setFocused(boolean);
+ method public void setHeading(boolean);
method public void setHintText(java.lang.CharSequence);
method public void setImportantForAccessibility(boolean);
method public void setInputType(int);
@@ -48270,6 +48301,7 @@ package android.view.accessibility {
method public void setSource(android.view.View, int);
method public void setText(java.lang.CharSequence);
method public void setTextSelection(int, int);
+ method public void setTooltipText(java.lang.CharSequence);
method public void setTraversalAfter(android.view.View);
method public void setTraversalAfter(android.view.View, int);
method public void setTraversalBefore(android.view.View);
@@ -48339,6 +48371,7 @@ package android.view.accessibility {
field public static final android.view.accessibility.AccessibilityNodeInfo.AccessibilityAction ACTION_DISMISS;
field public static final android.view.accessibility.AccessibilityNodeInfo.AccessibilityAction ACTION_EXPAND;
field public static final android.view.accessibility.AccessibilityNodeInfo.AccessibilityAction ACTION_FOCUS;
+ field public static final android.view.accessibility.AccessibilityNodeInfo.AccessibilityAction ACTION_HIDE_TOOLTIP;
field public static final android.view.accessibility.AccessibilityNodeInfo.AccessibilityAction ACTION_LONG_CLICK;
field public static final android.view.accessibility.AccessibilityNodeInfo.AccessibilityAction ACTION_MOVE_WINDOW;
field public static final android.view.accessibility.AccessibilityNodeInfo.AccessibilityAction ACTION_NEXT_AT_MOVEMENT_GRANULARITY;
@@ -48358,6 +48391,7 @@ package android.view.accessibility {
field public static final android.view.accessibility.AccessibilityNodeInfo.AccessibilityAction ACTION_SET_SELECTION;
field public static final android.view.accessibility.AccessibilityNodeInfo.AccessibilityAction ACTION_SET_TEXT;
field public static final android.view.accessibility.AccessibilityNodeInfo.AccessibilityAction ACTION_SHOW_ON_SCREEN;
+ field public static final android.view.accessibility.AccessibilityNodeInfo.AccessibilityAction ACTION_SHOW_TOOLTIP;
}
public static final class AccessibilityNodeInfo.CollectionInfo {
@@ -48377,7 +48411,7 @@ package android.view.accessibility {
method public int getColumnSpan();
method public int getRowIndex();
method public int getRowSpan();
- method public boolean isHeading();
+ method public deprecated boolean isHeading();
method public boolean isSelected();
method public static android.view.accessibility.AccessibilityNodeInfo.CollectionItemInfo obtain(int, int, int, int, boolean);
method public static android.view.accessibility.AccessibilityNodeInfo.CollectionItemInfo obtain(int, int, int, int, boolean, boolean);
@@ -52602,6 +52636,7 @@ package android.widget {
method public android.graphics.Typeface getTypeface();
method public android.text.style.URLSpan[] getUrls();
method public boolean hasSelection();
+ method public boolean isAccessibilityHeading();
method public boolean isAllCaps();
method public boolean isCursorVisible();
method public boolean isElegantTextHeight();
@@ -52624,6 +52659,7 @@ package android.widget {
method protected void onTextChanged(java.lang.CharSequence, int, int, int);
method public boolean onTextContextMenuItem(int);
method public void removeTextChangedListener(android.text.TextWatcher);
+ method public void setAccessibilityHeading(boolean);
method public void setAllCaps(boolean);
method public final void setAutoLinkMask(int);
method public void setAutoSizeTextTypeUniformWithConfiguration(int, int, int, int);
@@ -72425,197 +72461,6 @@ package javax.xml.xpath {
}
-package junit.framework {
-
- public class Assert {
- ctor protected Assert();
- method public static void assertEquals(java.lang.String, java.lang.Object, java.lang.Object);
- method public static void assertEquals(java.lang.Object, java.lang.Object);
- method public static void assertEquals(java.lang.String, java.lang.String, java.lang.String);
- method public static void assertEquals(java.lang.String, java.lang.String);
- method public static void assertEquals(java.lang.String, double, double, double);
- method public static void assertEquals(double, double, double);
- method public static void assertEquals(java.lang.String, float, float, float);
- method public static void assertEquals(float, float, float);
- method public static void assertEquals(java.lang.String, long, long);
- method public static void assertEquals(long, long);
- method public static void assertEquals(java.lang.String, boolean, boolean);
- method public static void assertEquals(boolean, boolean);
- method public static void assertEquals(java.lang.String, byte, byte);
- method public static void assertEquals(byte, byte);
- method public static void assertEquals(java.lang.String, char, char);
- method public static void assertEquals(char, char);
- method public static void assertEquals(java.lang.String, short, short);
- method public static void assertEquals(short, short);
- method public static void assertEquals(java.lang.String, int, int);
- method public static void assertEquals(int, int);
- method public static void assertFalse(java.lang.String, boolean);
- method public static void assertFalse(boolean);
- method public static void assertNotNull(java.lang.Object);
- method public static void assertNotNull(java.lang.String, java.lang.Object);
- method public static void assertNotSame(java.lang.String, java.lang.Object, java.lang.Object);
- method public static void assertNotSame(java.lang.Object, java.lang.Object);
- method public static void assertNull(java.lang.Object);
- method public static void assertNull(java.lang.String, java.lang.Object);
- method public static void assertSame(java.lang.String, java.lang.Object, java.lang.Object);
- method public static void assertSame(java.lang.Object, java.lang.Object);
- method public static void assertTrue(java.lang.String, boolean);
- method public static void assertTrue(boolean);
- method public static void fail(java.lang.String);
- method public static void fail();
- method public static void failNotEquals(java.lang.String, java.lang.Object, java.lang.Object);
- method public static void failNotSame(java.lang.String, java.lang.Object, java.lang.Object);
- method public static void failSame(java.lang.String);
- method public static java.lang.String format(java.lang.String, java.lang.Object, java.lang.Object);
- }
-
- public class AssertionFailedError extends java.lang.AssertionError {
- ctor public AssertionFailedError();
- ctor public AssertionFailedError(java.lang.String);
- }
-
- public class ComparisonFailure extends junit.framework.AssertionFailedError {
- ctor public ComparisonFailure(java.lang.String, java.lang.String, java.lang.String);
- method public java.lang.String getActual();
- method public java.lang.String getExpected();
- }
-
- public abstract interface Protectable {
- method public abstract void protect() throws java.lang.Throwable;
- }
-
- public abstract interface Test {
- method public abstract int countTestCases();
- method public abstract void run(junit.framework.TestResult);
- }
-
- public abstract class TestCase extends junit.framework.Assert implements junit.framework.Test {
- ctor public TestCase();
- ctor public TestCase(java.lang.String);
- method public int countTestCases();
- method protected junit.framework.TestResult createResult();
- method public java.lang.String getName();
- method public junit.framework.TestResult run();
- method public void run(junit.framework.TestResult);
- method public void runBare() throws java.lang.Throwable;
- method protected void runTest() throws java.lang.Throwable;
- method public void setName(java.lang.String);
- method protected void setUp() throws java.lang.Exception;
- method protected void tearDown() throws java.lang.Exception;
- }
-
- public class TestFailure {
- ctor public TestFailure(junit.framework.Test, java.lang.Throwable);
- method public java.lang.String exceptionMessage();
- method public junit.framework.Test failedTest();
- method public boolean isFailure();
- method public java.lang.Throwable thrownException();
- method public java.lang.String trace();
- field protected junit.framework.Test fFailedTest;
- field protected java.lang.Throwable fThrownException;
- }
-
- public abstract interface TestListener {
- method public abstract void addError(junit.framework.Test, java.lang.Throwable);
- method public abstract void addFailure(junit.framework.Test, junit.framework.AssertionFailedError);
- method public abstract void endTest(junit.framework.Test);
- method public abstract void startTest(junit.framework.Test);
- }
-
- public class TestResult {
- ctor public TestResult();
- method public synchronized void addError(junit.framework.Test, java.lang.Throwable);
- method public synchronized void addFailure(junit.framework.Test, junit.framework.AssertionFailedError);
- method public synchronized void addListener(junit.framework.TestListener);
- method public void endTest(junit.framework.Test);
- method public synchronized int errorCount();
- method public synchronized java.util.Enumeration<junit.framework.TestFailure> errors();
- method public synchronized int failureCount();
- method public synchronized java.util.Enumeration<junit.framework.TestFailure> failures();
- method public synchronized void removeListener(junit.framework.TestListener);
- method protected void run(junit.framework.TestCase);
- method public synchronized int runCount();
- method public void runProtected(junit.framework.Test, junit.framework.Protectable);
- method public synchronized boolean shouldStop();
- method public void startTest(junit.framework.Test);
- method public synchronized void stop();
- method public synchronized boolean wasSuccessful();
- field protected java.util.Vector<junit.framework.TestFailure> fErrors;
- field protected java.util.Vector<junit.framework.TestFailure> fFailures;
- field protected java.util.Vector<junit.framework.TestListener> fListeners;
- field protected int fRunTests;
- }
-
- public class TestSuite implements junit.framework.Test {
- ctor public TestSuite();
- ctor public TestSuite(java.lang.Class<?>);
- ctor public TestSuite(java.lang.Class<? extends junit.framework.TestCase>, java.lang.String);
- ctor public TestSuite(java.lang.String);
- ctor public TestSuite(java.lang.Class<?>...);
- ctor public TestSuite(java.lang.Class<? extends junit.framework.TestCase>[], java.lang.String);
- method public void addTest(junit.framework.Test);
- method public void addTestSuite(java.lang.Class<? extends junit.framework.TestCase>);
- method public int countTestCases();
- method public static junit.framework.Test createTest(java.lang.Class<?>, java.lang.String);
- method public java.lang.String getName();
- method public static java.lang.reflect.Constructor<?> getTestConstructor(java.lang.Class<?>) throws java.lang.NoSuchMethodException;
- method public void run(junit.framework.TestResult);
- method public void runTest(junit.framework.Test, junit.framework.TestResult);
- method public void setName(java.lang.String);
- method public junit.framework.Test testAt(int);
- method public int testCount();
- method public java.util.Enumeration<junit.framework.Test> tests();
- method public static junit.framework.Test warning(java.lang.String);
- }
-
-}
-
-package junit.runner {
-
- public abstract class BaseTestRunner implements junit.framework.TestListener {
- ctor public BaseTestRunner();
- method public synchronized void addError(junit.framework.Test, java.lang.Throwable);
- method public synchronized void addFailure(junit.framework.Test, junit.framework.AssertionFailedError);
- method protected void clearStatus();
- method public java.lang.String elapsedTimeAsString(long);
- method public synchronized void endTest(junit.framework.Test);
- method public java.lang.String extractClassName(java.lang.String);
- method public static java.lang.String getFilteredTrace(java.lang.Throwable);
- method public static java.lang.String getFilteredTrace(java.lang.String);
- method public deprecated junit.runner.TestSuiteLoader getLoader();
- method public static java.lang.String getPreference(java.lang.String);
- method public static int getPreference(java.lang.String, int);
- method protected static java.util.Properties getPreferences();
- method public junit.framework.Test getTest(java.lang.String);
- method public static deprecated boolean inVAJava();
- method protected java.lang.Class<?> loadSuiteClass(java.lang.String) throws java.lang.ClassNotFoundException;
- method protected java.lang.String processArguments(java.lang.String[]);
- method protected abstract void runFailed(java.lang.String);
- method public static void savePreferences() throws java.io.IOException;
- method public void setLoading(boolean);
- method public void setPreference(java.lang.String, java.lang.String);
- method protected static void setPreferences(java.util.Properties);
- method protected static boolean showStackRaw();
- method public synchronized void startTest(junit.framework.Test);
- method public abstract void testEnded(java.lang.String);
- method public abstract void testFailed(int, junit.framework.Test, java.lang.Throwable);
- method public abstract void testStarted(java.lang.String);
- method public static java.lang.String truncate(java.lang.String);
- method protected boolean useReloadingTestSuiteLoader();
- field public static final java.lang.String SUITE_METHODNAME = "suite";
- }
-
- public abstract interface TestSuiteLoader {
- method public abstract java.lang.Class load(java.lang.String) throws java.lang.ClassNotFoundException;
- method public abstract java.lang.Class reload(java.lang.Class) throws java.lang.ClassNotFoundException;
- }
-
- public class Version {
- method public static java.lang.String id();
- }
-
-}
-
package org.apache.http.conn {
public deprecated class ConnectTimeoutException extends java.io.InterruptedIOException {
diff --git a/api/system-current.txt b/api/system-current.txt
index 6539d1ded395..66b6d990ec0c 100644
--- a/api/system-current.txt
+++ b/api/system-current.txt
@@ -790,7 +790,9 @@ package android.content {
field public static final java.lang.String ACTION_QUERY_PACKAGE_RESTART = "android.intent.action.QUERY_PACKAGE_RESTART";
field public static final java.lang.String ACTION_RESOLVE_INSTANT_APP_PACKAGE = "android.intent.action.RESOLVE_INSTANT_APP_PACKAGE";
field public static final java.lang.String ACTION_REVIEW_PERMISSIONS = "android.intent.action.REVIEW_PERMISSIONS";
- field public static final java.lang.String ACTION_SIM_STATE_CHANGED = "android.intent.action.SIM_STATE_CHANGED";
+ field public static final java.lang.String ACTION_SIM_APPLICATION_STATE_CHANGED = "android.intent.action.SIM_APPLICATION_STATE_CHANGED";
+ field public static final java.lang.String ACTION_SIM_CARD_STATE_CHANGED = "android.intent.action.SIM_CARD_STATE_CHANGED";
+ field public static final deprecated java.lang.String ACTION_SIM_STATE_CHANGED = "android.intent.action.SIM_STATE_CHANGED";
field public static final java.lang.String ACTION_UPGRADE_SETUP = "android.intent.action.UPGRADE_SETUP";
field public static final java.lang.String ACTION_USER_REMOVED = "android.intent.action.USER_REMOVED";
field public static final java.lang.String ACTION_VOICE_ASSIST = "android.intent.action.VOICE_ASSIST";
@@ -1775,9 +1777,9 @@ package android.hardware.radio {
method public android.hardware.radio.ProgramSelector.Identifier[] getAllIds(int);
method public long getFirstId(int);
method public android.hardware.radio.ProgramSelector.Identifier getPrimaryId();
- method public int getProgramType();
+ method public deprecated int getProgramType();
method public android.hardware.radio.ProgramSelector.Identifier[] getSecondaryIds();
- method public long[] getVendorIds();
+ method public deprecated long[] getVendorIds();
method public void writeToParcel(android.os.Parcel, int);
field public static final android.os.Parcelable.Creator<android.hardware.radio.ProgramSelector> CREATOR;
field public static final int IDENTIFIER_TYPE_AMFM_FREQUENCY = 1; // 0x1
@@ -1785,27 +1787,31 @@ package android.hardware.radio {
field public static final int IDENTIFIER_TYPE_DAB_FREQUENCY = 8; // 0x8
field public static final int IDENTIFIER_TYPE_DAB_SCID = 7; // 0x7
field public static final int IDENTIFIER_TYPE_DAB_SIDECC = 5; // 0x5
+ field public static final int IDENTIFIER_TYPE_DAB_SID_EXT = 5; // 0x5
field public static final int IDENTIFIER_TYPE_DRMO_FREQUENCY = 10; // 0xa
- field public static final int IDENTIFIER_TYPE_DRMO_MODULATION = 11; // 0xb
+ field public static final deprecated int IDENTIFIER_TYPE_DRMO_MODULATION = 11; // 0xb
field public static final int IDENTIFIER_TYPE_DRMO_SERVICE_ID = 9; // 0x9
field public static final int IDENTIFIER_TYPE_HD_STATION_ID_EXT = 3; // 0x3
- field public static final int IDENTIFIER_TYPE_HD_SUBCHANNEL = 4; // 0x4
+ field public static final int IDENTIFIER_TYPE_HD_STATION_NAME = 10004; // 0x2714
+ field public static final deprecated int IDENTIFIER_TYPE_HD_SUBCHANNEL = 4; // 0x4
field public static final int IDENTIFIER_TYPE_INVALID = 0; // 0x0
field public static final int IDENTIFIER_TYPE_RDS_PI = 2; // 0x2
field public static final int IDENTIFIER_TYPE_SXM_CHANNEL = 13; // 0xd
field public static final int IDENTIFIER_TYPE_SXM_SERVICE_ID = 12; // 0xc
- field public static final int IDENTIFIER_TYPE_VENDOR_PRIMARY_END = 1999; // 0x7cf
- field public static final int IDENTIFIER_TYPE_VENDOR_PRIMARY_START = 1000; // 0x3e8
- field public static final int PROGRAM_TYPE_AM = 1; // 0x1
- field public static final int PROGRAM_TYPE_AM_HD = 3; // 0x3
- field public static final int PROGRAM_TYPE_DAB = 5; // 0x5
- field public static final int PROGRAM_TYPE_DRMO = 6; // 0x6
- field public static final int PROGRAM_TYPE_FM = 2; // 0x2
- field public static final int PROGRAM_TYPE_FM_HD = 4; // 0x4
- field public static final int PROGRAM_TYPE_INVALID = 0; // 0x0
- field public static final int PROGRAM_TYPE_SXM = 7; // 0x7
- field public static final int PROGRAM_TYPE_VENDOR_END = 1999; // 0x7cf
- field public static final int PROGRAM_TYPE_VENDOR_START = 1000; // 0x3e8
+ field public static final int IDENTIFIER_TYPE_VENDOR_END = 1999; // 0x7cf
+ field public static final deprecated int IDENTIFIER_TYPE_VENDOR_PRIMARY_END = 1999; // 0x7cf
+ field public static final deprecated int IDENTIFIER_TYPE_VENDOR_PRIMARY_START = 1000; // 0x3e8
+ field public static final int IDENTIFIER_TYPE_VENDOR_START = 1000; // 0x3e8
+ field public static final deprecated int PROGRAM_TYPE_AM = 1; // 0x1
+ field public static final deprecated int PROGRAM_TYPE_AM_HD = 3; // 0x3
+ field public static final deprecated int PROGRAM_TYPE_DAB = 5; // 0x5
+ field public static final deprecated int PROGRAM_TYPE_DRMO = 6; // 0x6
+ field public static final deprecated int PROGRAM_TYPE_FM = 2; // 0x2
+ field public static final deprecated int PROGRAM_TYPE_FM_HD = 4; // 0x4
+ field public static final deprecated int PROGRAM_TYPE_INVALID = 0; // 0x0
+ field public static final deprecated int PROGRAM_TYPE_SXM = 7; // 0x7
+ field public static final deprecated int PROGRAM_TYPE_VENDOR_END = 1999; // 0x7cf
+ field public static final deprecated int PROGRAM_TYPE_VENDOR_START = 1000; // 0x3e8
}
public static final class ProgramSelector.Identifier implements android.os.Parcelable {
@@ -1820,7 +1826,7 @@ package android.hardware.radio {
public static abstract class ProgramSelector.IdentifierType implements java.lang.annotation.Annotation {
}
- public static abstract class ProgramSelector.ProgramType implements java.lang.annotation.Annotation {
+ public static abstract deprecated class ProgramSelector.ProgramType implements java.lang.annotation.Annotation {
}
public class RadioManager {
@@ -2858,9 +2864,18 @@ package android.net {
method public void onTetheringStarted();
}
+ public final class IpSecManager {
+ method public android.net.IpSecManager.IpSecTunnelInterface createIpSecTunnelInterface(java.net.InetAddress, java.net.InetAddress, android.net.Network) throws java.io.IOException, android.net.IpSecManager.ResourceUnavailableException;
+ }
+
+ public static final class IpSecManager.IpSecTunnelInterface implements java.lang.AutoCloseable {
+ method public void close();
+ method public java.lang.String getInterfaceName();
+ }
+
public static class IpSecTransform.Builder {
+ method public android.net.IpSecTransform buildTunnelModeTransform(java.net.InetAddress, android.net.IpSecManager.SecurityParameterIndex) throws java.io.IOException, android.net.IpSecManager.ResourceUnavailableException, android.net.IpSecManager.SpiUnavailableException;
method public android.net.IpSecTransform.Builder setNattKeepalive(int);
- method public android.net.IpSecTransform.Builder setUnderlyingNetwork(android.net.Network);
}
public class NetworkKey implements android.os.Parcelable {
@@ -3860,20 +3875,10 @@ package android.service.autofill {
public abstract class AutofillFieldClassificationService extends android.app.Service {
method public android.os.IBinder onBind(android.content.Intent);
- method public java.util.List<java.lang.String> onGetAvailableAlgorithms();
- method public java.lang.String onGetDefaultAlgorithm();
- method public android.service.autofill.AutofillFieldClassificationService.Scores onGetScores(java.lang.String, android.os.Bundle, java.util.List<android.view.autofill.AutofillValue>, java.util.List<java.lang.String>);
+ method public float[][] onGetScores(java.lang.String, android.os.Bundle, java.util.List<android.view.autofill.AutofillValue>, java.util.List<java.lang.String>);
field public static final java.lang.String SERVICE_INTERFACE = "android.service.autofill.AutofillFieldClassificationService";
- }
-
- public static final class AutofillFieldClassificationService.Scores implements android.os.Parcelable {
- ctor public AutofillFieldClassificationService.Scores(java.lang.String, int, int);
- ctor public AutofillFieldClassificationService.Scores(android.os.Parcel);
- method public int describeContents();
- method public java.lang.String getAlgorithm();
- method public float[][] getScores();
- method public void writeToParcel(android.os.Parcel, int);
- field public static final android.os.Parcelable.Creator<android.service.autofill.AutofillFieldClassificationService.Scores> CREATOR;
+ field public static final java.lang.String SERVICE_META_DATA_KEY_AVAILABLE_ALGORITHMS = "android.autofill.field_classification.available_algorithms";
+ field public static final java.lang.String SERVICE_META_DATA_KEY_DEFAULT_ALGORITHM = "android.autofill.field_classification.default_algorithm";
}
}
@@ -4379,6 +4384,8 @@ package android.telephony {
public class SubscriptionManager {
method public java.util.List<android.telephony.SubscriptionPlan> getSubscriptionPlans(int);
+ method public void setSubscriptionOverrideCongested(int, boolean, long);
+ method public void setSubscriptionOverrideUnmetered(int, boolean, long);
method public void setSubscriptionPlans(int, java.util.List<android.telephony.SubscriptionPlan>);
field public static final java.lang.String ACTION_MANAGE_SUBSCRIPTION_PLANS = "android.telephony.action.MANAGE_SUBSCRIPTION_PLANS";
field public static final java.lang.String ACTION_REFRESH_SUBSCRIPTION_PLANS = "android.telephony.action.REFRESH_SUBSCRIPTION_PLANS";
@@ -4460,6 +4467,8 @@ package android.telephony {
method public deprecated boolean getDataEnabled();
method public deprecated boolean getDataEnabled(int);
method public boolean getEmergencyCallbackMode();
+ method public int getSimApplicationState();
+ method public int getSimCardState();
method public java.util.List<android.telephony.TelephonyHistogram> getTelephonyHistograms();
method public android.os.Bundle getVisualVoicemailSettings();
method public int getVoiceActivationState();
@@ -4493,6 +4502,7 @@ package android.telephony {
field public static final int CARRIER_PRIVILEGE_STATUS_HAS_ACCESS = 1; // 0x1
field public static final int CARRIER_PRIVILEGE_STATUS_NO_ACCESS = 0; // 0x0
field public static final int CARRIER_PRIVILEGE_STATUS_RULES_NOT_LOADED = -1; // 0xffffffff
+ field public static final java.lang.String EXTRA_SIM_STATE = "android.telephony.extra.SIM_STATE";
field public static final java.lang.String EXTRA_VISUAL_VOICEMAIL_ENABLED_BY_USER_BOOL = "android.telephony.extra.VISUAL_VOICEMAIL_ENABLED_BY_USER_BOOL";
field public static final java.lang.String EXTRA_VOICEMAIL_SCRAMBLED_PIN_STRING = "android.telephony.extra.VOICEMAIL_SCRAMBLED_PIN_STRING";
field public static final int SIM_ACTIVATION_STATE_ACTIVATED = 2; // 0x2
@@ -4500,6 +4510,8 @@ package android.telephony {
field public static final int SIM_ACTIVATION_STATE_DEACTIVATED = 3; // 0x3
field public static final int SIM_ACTIVATION_STATE_RESTRICTED = 4; // 0x4
field public static final int SIM_ACTIVATION_STATE_UNKNOWN = 0; // 0x0
+ field public static final int SIM_STATE_LOADED = 10; // 0xa
+ field public static final int SIM_STATE_PRESENT = 11; // 0xb
}
public abstract class VisualVoicemailService extends android.app.Service {
diff --git a/cmds/incident_helper/src/TextParserBase.h b/cmds/incident_helper/src/TextParserBase.h
index c41612de4eb3..166796673e25 100644
--- a/cmds/incident_helper/src/TextParserBase.h
+++ b/cmds/incident_helper/src/TextParserBase.h
@@ -68,4 +68,4 @@ public:
virtual status_t Parse(const int in, const int out) const;
};
-#endif // TEXT_PARSER_BASE_H \ No newline at end of file
+#endif // TEXT_PARSER_BASE_H
diff --git a/cmds/incidentd/README.md b/cmds/incidentd/README.md
index ad0fa08c7326..71c6deb18aac 100644
--- a/cmds/incidentd/README.md
+++ b/cmds/incidentd/README.md
@@ -12,8 +12,8 @@ Run the test on a device manually
```
root$ mmm -j frameworks/base/cmds/incidentd && \
-adb push $OUT/data/nativetest/incidentd_test/* /data/nativetest/incidentd_test/ && \
-adb shell /data/nativetest/incidentd_test/incidentd_test 2>/dev/null
+adb push $OUT/data/nativetest/incidentd_test/* /data/nativetest/ && \
+adb shell /data/nativetest/incidentd_test 2>/dev/null
```
Run the test via AndroidTest.xml
diff --git a/cmds/incidentd/incidentd.rc b/cmds/incidentd/incidentd.rc
index 66667dca2982..1bd146850ea9 100644
--- a/cmds/incidentd/incidentd.rc
+++ b/cmds/incidentd/incidentd.rc
@@ -19,4 +19,4 @@ service incidentd /system/bin/incidentd
on post-fs-data
# Create directory for incidentd
- mkdir /data/misc/incidents 0770 root root
+ mkdir /data/misc/incidents 0770 incidentd incidentd
diff --git a/cmds/incidentd/src/FdBuffer.cpp b/cmds/incidentd/src/FdBuffer.cpp
index 30dd339a629b..0fff4e6dc4a0 100644
--- a/cmds/incidentd/src/FdBuffer.cpp
+++ b/cmds/incidentd/src/FdBuffer.cpp
@@ -63,12 +63,14 @@ FdBuffer::read(int fd, int64_t timeout)
int64_t remainingTime = (mStartTime + timeout) - uptimeMillis();
if (remainingTime <= 0) {
+ if (DEBUG) ALOGD("timed out due to long read");
mTimedOut = true;
break;
}
int count = poll(&pfds, 1, remainingTime);
if (count == 0) {
+ if (DEBUG) ALOGD("timed out due to block calling poll");
mTimedOut = true;
break;
} else if (count < 0) {
@@ -129,6 +131,7 @@ FdBuffer::readProcessedDataInStream(int fd, int toFd, int fromFd, int64_t timeou
int64_t remainingTime = (mStartTime + timeoutMs) - uptimeMillis();
if (remainingTime <= 0) {
+ if (DEBUG) ALOGD("timed out due to long read");
mTimedOut = true;
break;
}
@@ -136,6 +139,7 @@ FdBuffer::readProcessedDataInStream(int fd, int toFd, int fromFd, int64_t timeou
// wait for any pfds to be ready to perform IO
int count = poll(pfds, 3, remainingTime);
if (count == 0) {
+ if (DEBUG) ALOGD("timed out due to block calling poll");
mTimedOut = true;
break;
} else if (count < 0) {
diff --git a/cmds/incidentd/src/IncidentService.cpp b/cmds/incidentd/src/IncidentService.cpp
index c4b54bbbc022..a97eb861578e 100644
--- a/cmds/incidentd/src/IncidentService.cpp
+++ b/cmds/incidentd/src/IncidentService.cpp
@@ -43,8 +43,9 @@ String16 const DUMP_PERMISSION("android.permission.DUMP");
String16 const USAGE_STATS_PERMISSION("android.permission.PACKAGE_USAGE_STATS");
static Status
-checkIncidentPermissions()
+checkIncidentPermissions(const IncidentReportArgs& args)
{
+ // checking calling permission.
if (!checkCallingPermission(DUMP_PERMISSION)) {
ALOGW("Calling pid %d and uid %d does not have permission: android.permission.DUMP",
IPCThreadState::self()->getCallingPid(), IPCThreadState::self()->getCallingUid());
@@ -57,10 +58,24 @@ checkIncidentPermissions()
return Status::fromExceptionCode(Status::EX_SECURITY,
"Calling process does not have permission: android.permission.USAGE_STATS");
}
+
+ // checking calling request uid permission.
+ uid_t callingUid = IPCThreadState::self()->getCallingUid();
+ switch (args.dest()) {
+ case DEST_LOCAL:
+ if (callingUid != AID_SHELL || callingUid != AID_ROOT) {
+ return Status::fromExceptionCode(Status::EX_SECURITY,
+ "Calling process does not have permission to get local data.");
+ }
+ case DEST_EXPLICIT:
+ if (callingUid != AID_SHELL || callingUid != AID_ROOT ||
+ callingUid != AID_STATSD || callingUid != AID_SYSTEM) {
+ return Status::fromExceptionCode(Status::EX_SECURITY,
+ "Calling process does not have permission to get explicit data.");
+ }
+ }
return Status::ok();
}
-
-
// ================================================================================
ReportRequestQueue::ReportRequestQueue()
{
@@ -71,7 +86,7 @@ ReportRequestQueue::~ReportRequestQueue()
}
void
-ReportRequestQueue::addRequest(const sp<ReportRequest>& request)
+ReportRequestQueue::addRequest(const sp<ReportRequest>& request)
{
unique_lock<mutex> lock(mLock);
mQueue.push_back(request);
@@ -196,7 +211,7 @@ IncidentService::reportIncident(const IncidentReportArgs& args)
{
ALOGI("reportIncident");
- Status status = checkIncidentPermissions();
+ Status status = checkIncidentPermissions(args);
if (!status.isOk()) {
return status;
}
@@ -212,7 +227,7 @@ IncidentService::reportIncidentToStream(const IncidentReportArgs& args,
{
ALOGI("reportIncidentToStream");
- Status status = checkIncidentPermissions();
+ Status status = checkIncidentPermissions(args);
if (!status.isOk()) {
return status;
}
diff --git a/cmds/incidentd/src/Reporter.cpp b/cmds/incidentd/src/Reporter.cpp
index 34930aa57321..bd559d6980f1 100644
--- a/cmds/incidentd/src/Reporter.cpp
+++ b/cmds/incidentd/src/Reporter.cpp
@@ -251,7 +251,7 @@ Reporter::create_file(int* fd)
// Override umask. Not super critical. If it fails go on with life.
chmod(filename, 0660);
- if (chown(filename, AID_SYSTEM, AID_SYSTEM)) {
+ if (chown(filename, AID_INCIDENTD, AID_INCIDENTD)) {
ALOGE("Unable to change ownership of incident file %s: %s\n", filename, strerror(errno));
status_t err = -errno;
unlink(mFilename.c_str());
diff --git a/cmds/incidentd/src/Section.cpp b/cmds/incidentd/src/Section.cpp
index 61d16f815e65..0827785811b6 100644
--- a/cmds/incidentd/src/Section.cpp
+++ b/cmds/incidentd/src/Section.cpp
@@ -19,6 +19,7 @@
#include "Section.h"
#include <errno.h>
+#include <sys/prctl.h>
#include <unistd.h>
#include <wait.h>
@@ -30,7 +31,6 @@
#include <log/log_event_list.h>
#include <log/logprint.h>
#include <log/log_read.h>
-#include <private/android_filesystem_config.h> // for AID_NOBODY
#include <private/android_logger.h>
#include "FdBuffer.h"
@@ -55,26 +55,20 @@ static pid_t
fork_execute_incident_helper(const int id, const char* name, Fpipe& p2cPipe, Fpipe& c2pPipe)
{
const char* ihArgs[] { INCIDENT_HELPER, "-s", String8::format("%d", id).string(), NULL };
-
// fork used in multithreaded environment, avoid adding unnecessary code in child process
pid_t pid = fork();
if (pid == 0) {
- // child process executes incident helper as nobody
- if (setgid(AID_NOBODY) == -1) {
- ALOGW("%s can't change gid: %s", name, strerror(errno));
- _exit(EXIT_FAILURE);
- }
- if (setuid(AID_NOBODY) == -1) {
- ALOGW("%s can't change uid: %s", name, strerror(errno));
- _exit(EXIT_FAILURE);
- }
-
- if (dup2(p2cPipe.readFd(), STDIN_FILENO) != 0 || !p2cPipe.close() ||
- dup2(c2pPipe.writeFd(), STDOUT_FILENO) != 1 || !c2pPipe.close()) {
+ if (TEMP_FAILURE_RETRY(dup2(p2cPipe.readFd(), STDIN_FILENO)) != 0
+ || !p2cPipe.close()
+ || TEMP_FAILURE_RETRY(dup2(c2pPipe.writeFd(), STDOUT_FILENO)) != 1
+ || !c2pPipe.close()) {
ALOGW("%s can't setup stdin and stdout for incident helper", name);
_exit(EXIT_FAILURE);
}
+ /* make sure the child dies when incidentd dies */
+ prctl(PR_SET_PDEATHSIG, SIGKILL);
+
execv(INCIDENT_HELPER, const_cast<char**>(ihArgs));
ALOGW("%s failed in incident helper process: %s", name, strerror(errno));
@@ -87,11 +81,23 @@ fork_execute_incident_helper(const int id, const char* name, Fpipe& p2cPipe, Fpi
}
// ================================================================================
+static status_t statusCode(int status) {
+ if (WIFSIGNALED(status)) {
+ ALOGD("return by signal: %s", strerror(WTERMSIG(status)));
+ return -WTERMSIG(status);
+ } else if (WIFEXITED(status) && WEXITSTATUS(status) > 0) {
+ ALOGD("return by exit: %s", strerror(WEXITSTATUS(status)));
+ return -WEXITSTATUS(status);
+ }
+ return NO_ERROR;
+}
+
static status_t kill_child(pid_t pid) {
int status;
+ ALOGD("try to kill child process %d", pid);
kill(pid, SIGKILL);
if (waitpid(pid, &status, 0) == -1) return -1;
- return WIFEXITED(status) == 0 ? NO_ERROR : -WEXITSTATUS(status);
+ return statusCode(status);
}
static status_t wait_child(pid_t pid) {
@@ -104,7 +110,7 @@ static status_t wait_child(pid_t pid) {
nanosleep(&WAIT_INTERVAL_NS, NULL);
}
if (!died) return kill_child(pid);
- return WIFEXITED(status) == 0 ? NO_ERROR : -WEXITSTATUS(status);
+ return statusCode(status);
}
// ================================================================================
static const Privacy*
@@ -275,9 +281,9 @@ FileSection::Execute(ReportRequestSet* requests) const
status_t readStatus = buffer.readProcessedDataInStream(fd, p2cPipe.writeFd(), c2pPipe.readFd(),
this->timeoutMs, mIsSysfs);
if (readStatus != NO_ERROR || buffer.timedOut()) {
- ALOGW("FileSection '%s' failed to read data from incident helper: %s, timedout: %s, kill: %s",
- this->name.string(), strerror(-readStatus), buffer.timedOut() ? "true" : "false",
- strerror(-kill_child(pid)));
+ ALOGW("FileSection '%s' failed to read data from incident helper: %s, timedout: %s",
+ this->name.string(), strerror(-readStatus), buffer.timedOut() ? "true" : "false");
+ kill_child(pid);
return readStatus;
}
@@ -543,10 +549,10 @@ CommandSection::Execute(ReportRequestSet* requests) const
close(cmdPipe.writeFd());
status_t readStatus = buffer.read(ihPipe.readFd(), this->timeoutMs);
if (readStatus != NO_ERROR || buffer.timedOut()) {
- ALOGW("CommandSection '%s' failed to read data from incident helper: %s, "
- "timedout: %s, kill command: %s, kill incident helper: %s",
- this->name.string(), strerror(-readStatus), buffer.timedOut() ? "true" : "false",
- strerror(-kill_child(cmdPid)), strerror(-kill_child(ihPid)));
+ ALOGW("CommandSection '%s' failed to read data from incident helper: %s, timedout: %s",
+ this->name.string(), strerror(-readStatus), buffer.timedOut() ? "true" : "false");
+ kill_child(cmdPid);
+ kill_child(ihPid);
return readStatus;
}
diff --git a/cmds/incidentd/src/io_util.cpp b/cmds/incidentd/src/io_util.cpp
index af4a35cc0015..90f543e30ff7 100644
--- a/cmds/incidentd/src/io_util.cpp
+++ b/cmds/incidentd/src/io_util.cpp
@@ -23,7 +23,7 @@
status_t write_all(int fd, uint8_t const* buf, size_t size)
{
while (size > 0) {
- ssize_t amt = ::write(fd, buf, size);
+ ssize_t amt = TEMP_FAILURE_RETRY(::write(fd, buf, size));
if (amt < 0) {
return -errno;
}
diff --git a/cmds/incidentd/src/report_directory.cpp b/cmds/incidentd/src/report_directory.cpp
index 65030b3a1799..20111d8ae89a 100644
--- a/cmds/incidentd/src/report_directory.cpp
+++ b/cmds/incidentd/src/report_directory.cpp
@@ -58,26 +58,9 @@ create_directory(const char* directory)
goto done;
}
} else {
- if (mkdir(dir, 0770)) {
- ALOGE("No incident reports today. "
- "Unable to create incident report dir %s: %s", dir,
- strerror(errno));
- err = -errno;
- goto done;
- }
- if (chmod(dir, 0770)) {
- ALOGE("No incident reports today. "
- "Unable to set permissions for incident report dir %s: %s", dir,
- strerror(errno));
- err = -errno;
- goto done;
- }
- if (chown(dir, AID_SYSTEM, AID_SYSTEM)) {
- ALOGE("No incident reports today. Unable to change ownership of dir %s: %s\n",
- dir, strerror(errno));
- err = -errno;
- goto done;
- }
+ ALOGE("No such directory %s, something wrong.", dir);
+ err = -1;
+ goto done;
}
if (!last) {
*d++ = '/';
@@ -97,8 +80,7 @@ create_directory(const char* directory)
err = BAD_VALUE;
goto done;
}
- if ((st.st_uid != AID_SYSTEM && st.st_uid != AID_ROOT) ||
- (st.st_gid != AID_SYSTEM && st.st_gid != AID_ROOT)) {
+ if (st.st_uid != AID_INCIDENTD || st.st_gid != AID_INCIDENTD) {
ALOGE("No incident reports today. Owner is %d and group is %d on report directory %s",
st.st_uid, st.st_gid, directory);
err = BAD_VALUE;
diff --git a/cmds/statsd/Android.mk b/cmds/statsd/Android.mk
index 5eff54887be1..01f4a84bbb93 100644
--- a/cmds/statsd/Android.mk
+++ b/cmds/statsd/Android.mk
@@ -34,6 +34,7 @@ statsd_common_src := \
src/config/ConfigKey.cpp \
src/config/ConfigListener.cpp \
src/config/ConfigManager.cpp \
+ src/external/Perfetto.cpp \
src/external/StatsPuller.cpp \
src/external/StatsCompanionServicePuller.cpp \
src/external/SubsystemSleepStatePuller.cpp \
@@ -57,6 +58,7 @@ statsd_common_src := \
src/metrics/MetricsManager.cpp \
src/metrics/metrics_manager_util.cpp \
src/packages/UidMap.cpp \
+ src/perfetto/perfetto_config.proto \
src/storage/StorageManager.cpp \
src/StatsLogProcessor.cpp \
src/StatsService.cpp \
@@ -209,6 +211,7 @@ LOCAL_MODULE := statsdprotolite
LOCAL_SRC_FILES := \
src/stats_log.proto \
src/statsd_config.proto \
+ src/perfetto/perfetto_config.proto \
src/atoms.proto
LOCAL_PROTOC_OPTIMIZE_TYPE := lite
diff --git a/cmds/statsd/src/anomaly/AnomalyTracker.cpp b/cmds/statsd/src/anomaly/AnomalyTracker.cpp
index f10b2cf618cd..9b65acf86604 100644
--- a/cmds/statsd/src/anomaly/AnomalyTracker.cpp
+++ b/cmds/statsd/src/anomaly/AnomalyTracker.cpp
@@ -18,6 +18,7 @@
#include "Log.h"
#include "AnomalyTracker.h"
+#include "external/Perfetto.h"
#include "guardrail/StatsdStats.h"
#include <android/os/IIncidentManager.h>
@@ -239,7 +240,7 @@ void AnomalyTracker::informSubscribers(const HashableDimensionKey& key) {
}
break;
case Subscription::SubscriberInformationCase::kPerfettoDetails:
- ALOGW("Perfetto reports not implemented.");
+ CollectPerfettoTraceAndUploadToDropbox(subscription.perfetto_details());
break;
default:
break;
diff --git a/cmds/statsd/src/atoms.proto b/cmds/statsd/src/atoms.proto
index 7d513cd01694..ef99c9f4d7e3 100644
--- a/cmds/statsd/src/atoms.proto
+++ b/cmds/statsd/src/atoms.proto
@@ -84,6 +84,7 @@ message Atom {
AppStartChanged app_start_changed = 48;
AppStartCancelChanged app_start_cancel_changed = 49;
AppStartFullyDrawnChanged app_start_fully_drawn_changed = 50;
+ LmkEventOccurred lmk_event_occurred = 51;
// TODO: Reorder the numbering so that the most frequent occur events occur in the first 15.
}
@@ -101,6 +102,11 @@ message Atom {
CpuTimePerUidFreq cpu_time_per_uid_freq = 10010;
WifiActivityEnergyInfo wifi_activity_energy_info = 10011;
ModemActivityInfo modem_activity_info = 10012;
+ MemoryStat memory_stat = 10013;
+ CpuSuspendTime cpu_suspend_time = 10014;
+ CpuIdleTime cpu_idle_time = 10015;
+ CpuActiveTime cpu_active_time = 10016;
+ CpuClusterTime cpu_cluster_time = 10017;
}
}
@@ -1177,3 +1183,91 @@ message ModemActivityInfo {
// product of current(mA), voltage(V) and time(ms)
optional uint64 energy_used = 10;
}
+
+/*
+ * Logs the memory stats for a process
+ */
+message MemoryStat {
+ // The uid if available. -1 means not available.
+ optional int32 uid = 1;
+
+ // The app package name.
+ optional string pkg_name = 2;
+
+ // # of page-faults
+ optional int64 pgfault = 3;
+
+ // # of major page-faults
+ optional int64 pgmajfault = 4;
+
+ // RSS+CACHE(+SWAP)
+ optional int64 usage_in_bytes = 5;
+}
+
+/*
+ * Logs the event when LMKD kills a process to reduce memory pressure
+ * Logged from:
+ * system/core/lmkd/lmkd.c
+ */
+message LmkEventOccurred {
+ // The uid if available. -1 means not available.
+ optional int32 uid = 1;
+
+ // The app package name.
+ optional string pkg_name = 2;
+
+ // oom adj score.
+ optional int32 oom_score = 3;
+
+ // Used as start/stop boundaries for the event
+ enum State {
+ UNKNOWN = 0;
+ START = 1;
+ END = 2;
+ }
+ optional State state = 4;
+}
+
+/*
+ * Cpu syspend time for cpu power calculation.
+ */
+message CpuSuspendTime {
+ optional uint64 time = 1;
+}
+
+/*
+ * Cpu idle time for cpu power calculation.
+ */
+message CpuIdleTime {
+ optional uint64 time = 1;
+}
+
+/*
+ * Reads from /proc/uid_concurrent_active_time which has the format:
+ * active: X (X is # cores)
+ * [uid0]: [time-0] [time-1] [time-2] ... (# entries = # cores)
+ * [uid1]: [time-0] [time-1] [time-2] ... ...
+ * ...
+ * Time-N means the CPU time a UID spent running concurrently with N other processes.
+ * The file contains a monotonically increasing count of time for a single boot.
+ */
+message CpuActiveTime {
+ optional uint64 uid = 1;
+ optional uint64 idx = 2;
+ optional uint64 time_ms = 3;
+}
+
+/**
+ * Reads from /proc/uid_concurrent_policy_time which has the format:
+ * policy0: X policy4: Y (there are X cores on policy0, Y cores on policy4)
+ * [uid0]: [time-0-0] [time-0-1] ... [time-1-0] [time-1-1] ...
+ * [uid1]: [time-0-0] [time-0-1] ... [time-1-0] [time-1-1] ...
+ * ...
+ * Time-X-Y means the time a UID spent on clusterX running concurrently with Y other processes.
+ * The file contains a monotonically increasing count of time for a single boot.
+ */
+message CpuClusterTime {
+ optional uint64 uid = 1;
+ optional uint64 idx = 2;
+ optional uint64 time_ms = 3;
+} \ No newline at end of file
diff --git a/cmds/statsd/src/condition/SimpleConditionTracker.cpp b/cmds/statsd/src/condition/SimpleConditionTracker.cpp
index 25257213a5d0..7a1bb0c71373 100644
--- a/cmds/statsd/src/condition/SimpleConditionTracker.cpp
+++ b/cmds/statsd/src/condition/SimpleConditionTracker.cpp
@@ -19,6 +19,7 @@
#include "SimpleConditionTracker.h"
#include "guardrail/StatsdStats.h"
+#include "dimension.h"
#include <log/logprint.h>
@@ -171,12 +172,12 @@ void SimpleConditionTracker::handleConditionEvent(const HashableDimensionKey& ou
// We get a new output key.
newCondition = matchStart ? ConditionState::kTrue : ConditionState::kFalse;
if (matchStart && mInitialValue != ConditionState::kTrue) {
- mSlicedConditionState[outputKey] = 1;
+ mSlicedConditionState.insert(std::make_pair(outputKey, 1));
changed = true;
} else if (mInitialValue != ConditionState::kFalse) {
// it's a stop and we don't have history about it.
// If the default condition is not false, it means this stop is valuable to us.
- mSlicedConditionState[outputKey] = 0;
+ mSlicedConditionState.insert(std::make_pair(outputKey, 0));
changed = true;
}
} else {
@@ -341,7 +342,23 @@ void SimpleConditionTracker::isConditionMet(
conditionState = conditionState |
(startedCountIt->second > 0 ? ConditionState::kTrue : ConditionState::kFalse);
} else {
- conditionState = conditionState | mInitialValue;
+ // For unseen key, check whether the require dimensions are subset of sliced condition
+ // output.
+ bool seenDimension = false;
+ for (const auto& slice : mSlicedConditionState) {
+ if (IsSubDimension(slice.first.getDimensionsValue(),
+ key.getDimensionsValue())) {
+ seenDimension = true;
+ conditionState = conditionState |
+ (slice.second > 0 ? ConditionState::kTrue : ConditionState::kFalse);
+ }
+ if (conditionState == ConditionState::kTrue) {
+ break;
+ }
+ }
+ if (!seenDimension) {
+ conditionState = conditionState | mInitialValue;
+ }
}
}
conditionCache[mIndex] = conditionState;
diff --git a/cmds/statsd/src/condition/condition_util.cpp b/cmds/statsd/src/condition/condition_util.cpp
index a5aee73ce84f..ddfb8d12a335 100644
--- a/cmds/statsd/src/condition/condition_util.cpp
+++ b/cmds/statsd/src/condition/condition_util.cpp
@@ -158,15 +158,15 @@ void flattenValueLeaves(const DimensionsValue& value,
std::vector<HashableDimensionKey> getDimensionKeysForCondition(
const LogEvent& event, const MetricConditionLink& link) {
std::vector<Field> whatFields;
- getFieldsFromFieldMatcher(link.dimensions_in_what(), &whatFields);
+ getFieldsFromFieldMatcher(link.fields_in_what(), &whatFields);
std::vector<Field> conditionFields;
- getFieldsFromFieldMatcher(link.dimensions_in_condition(), &conditionFields);
+ getFieldsFromFieldMatcher(link.fields_in_condition(), &conditionFields);
std::vector<HashableDimensionKey> hashableDimensionKeys;
// TODO(yanglu): here we could simplify the logic to get the leaf value node in what and
// directly construct the full condition value tree.
- std::vector<DimensionsValue> whatValues = getDimensionKeys(event, link.dimensions_in_what());
+ std::vector<DimensionsValue> whatValues = getDimensionKeys(event, link.fields_in_what());
for (size_t i = 0; i < whatValues.size(); ++i) {
std::vector<DimensionsValue> whatLeaves;
@@ -185,7 +185,7 @@ std::vector<HashableDimensionKey> getDimensionKeysForCondition(
conditionValueMap.insert(std::make_pair(conditionFields[j], whatLeaves[j]));
}
std::vector<DimensionsValue> conditionValues;
- findDimensionsValues(conditionValueMap, link.dimensions_in_condition(), &conditionValues);
+ findDimensionsValues(conditionValueMap, link.fields_in_condition(), &conditionValues);
if (conditionValues.size() != 1) {
ALOGE("Not able to find unambiguous field value in condition atom.");
continue;
diff --git a/cmds/statsd/src/config/ConfigManager.cpp b/cmds/statsd/src/config/ConfigManager.cpp
index 1481921d013a..42994b558208 100644
--- a/cmds/statsd/src/config/ConfigManager.cpp
+++ b/cmds/statsd/src/config/ConfigManager.cpp
@@ -296,10 +296,10 @@ StatsdConfig build_fake_config() {
metric->set_condition(204);
MetricConditionLink* link = metric->add_links();
link->set_condition(203);
- link->mutable_dimensions_in_what()->set_field(WAKE_LOCK_TAG_ID);
- link->mutable_dimensions_in_what()->add_child()->set_field(WAKE_LOCK_UID_KEY_ID);
- link->mutable_dimensions_in_condition()->set_field(APP_USAGE_TAG_ID);
- link->mutable_dimensions_in_condition()->add_child()->set_field(APP_USAGE_UID_KEY_ID);
+ link->mutable_fields_in_what()->set_field(WAKE_LOCK_TAG_ID);
+ link->mutable_fields_in_what()->add_child()->set_field(WAKE_LOCK_UID_KEY_ID);
+ link->mutable_fields_in_condition()->set_field(APP_USAGE_TAG_ID);
+ link->mutable_fields_in_condition()->add_child()->set_field(APP_USAGE_UID_KEY_ID);
// Duration of an app holding any wl, while screen on and app in background, slice by uid
DurationMetric* durationMetric = config.add_duration_metric();
@@ -313,10 +313,10 @@ StatsdConfig build_fake_config() {
durationMetric->set_condition(204);
link = durationMetric->add_links();
link->set_condition(203);
- link->mutable_dimensions_in_what()->set_field(WAKE_LOCK_TAG_ID);
- link->mutable_dimensions_in_what()->add_child()->set_field(WAKE_LOCK_UID_KEY_ID);
- link->mutable_dimensions_in_condition()->set_field(APP_USAGE_TAG_ID);
- link->mutable_dimensions_in_condition()->add_child()->set_field(APP_USAGE_UID_KEY_ID);
+ link->mutable_fields_in_what()->set_field(WAKE_LOCK_TAG_ID);
+ link->mutable_fields_in_what()->add_child()->set_field(WAKE_LOCK_UID_KEY_ID);
+ link->mutable_fields_in_condition()->set_field(APP_USAGE_TAG_ID);
+ link->mutable_fields_in_condition()->add_child()->set_field(APP_USAGE_UID_KEY_ID);
// max Duration of an app holding any wl, while screen on and app in background, slice by uid
durationMetric = config.add_duration_metric();
@@ -330,10 +330,10 @@ StatsdConfig build_fake_config() {
durationMetric->set_condition(204);
link = durationMetric->add_links();
link->set_condition(203);
- link->mutable_dimensions_in_what()->set_field(WAKE_LOCK_TAG_ID);
- link->mutable_dimensions_in_what()->add_child()->set_field(WAKE_LOCK_UID_KEY_ID);
- link->mutable_dimensions_in_condition()->set_field(APP_USAGE_TAG_ID);
- link->mutable_dimensions_in_condition()->add_child()->set_field(APP_USAGE_UID_KEY_ID);
+ link->mutable_fields_in_what()->set_field(WAKE_LOCK_TAG_ID);
+ link->mutable_fields_in_what()->add_child()->set_field(WAKE_LOCK_UID_KEY_ID);
+ link->mutable_fields_in_condition()->set_field(APP_USAGE_TAG_ID);
+ link->mutable_fields_in_condition()->add_child()->set_field(APP_USAGE_UID_KEY_ID);
// Duration of an app holding any wl, while screen on and app in background
durationMetric = config.add_duration_metric();
@@ -344,10 +344,10 @@ StatsdConfig build_fake_config() {
durationMetric->set_condition(204);
link = durationMetric->add_links();
link->set_condition(203);
- link->mutable_dimensions_in_what()->set_field(WAKE_LOCK_TAG_ID);
- link->mutable_dimensions_in_what()->add_child()->set_field(WAKE_LOCK_UID_KEY_ID);
- link->mutable_dimensions_in_condition()->set_field(APP_USAGE_TAG_ID);
- link->mutable_dimensions_in_condition()->add_child()->set_field(APP_USAGE_UID_KEY_ID);
+ link->mutable_fields_in_what()->set_field(WAKE_LOCK_TAG_ID);
+ link->mutable_fields_in_what()->add_child()->set_field(WAKE_LOCK_UID_KEY_ID);
+ link->mutable_fields_in_condition()->set_field(APP_USAGE_TAG_ID);
+ link->mutable_fields_in_condition()->add_child()->set_field(APP_USAGE_UID_KEY_ID);
// Duration of screen on time.
diff --git a/cmds/statsd/src/dimension.cpp b/cmds/statsd/src/dimension.cpp
index 09499b6406e7..bb7a044fa8ce 100644
--- a/cmds/statsd/src/dimension.cpp
+++ b/cmds/statsd/src/dimension.cpp
@@ -331,13 +331,15 @@ bool IsSubDimension(const DimensionsValue& dimension, const DimensionsValue& sub
case DimensionsValue::ValueCase::kValueFloat:
return dimension.value_float() == sub.value_float();
case DimensionsValue::ValueCase::kValueTuple: {
- if (dimension.value_tuple().dimensions_value_size() < sub.value_tuple().dimensions_value_size()) {
+ if (dimension.value_tuple().dimensions_value_size() <
+ sub.value_tuple().dimensions_value_size()) {
return false;
}
bool allSub = true;
- for (int i = 0; i < sub.value_tuple().dimensions_value_size(); ++i) {
+ for (int i = 0; allSub && i < sub.value_tuple().dimensions_value_size(); ++i) {
bool isSub = false;
- for (int j = 0; !isSub && j < dimension.value_tuple().dimensions_value_size(); ++j) {
+ for (int j = 0; !isSub &&
+ j < dimension.value_tuple().dimensions_value_size(); ++j) {
isSub |= IsSubDimension(dimension.value_tuple().dimensions_value(j),
sub.value_tuple().dimensions_value(i));
}
diff --git a/cmds/statsd/src/external/CpuTimePerUidFreqPuller.cpp b/cmds/statsd/src/external/CpuTimePerUidFreqPuller.cpp
index a61afb429f54..a75127324745 100644
--- a/cmds/statsd/src/external/CpuTimePerUidFreqPuller.cpp
+++ b/cmds/statsd/src/external/CpuTimePerUidFreqPuller.cpp
@@ -34,7 +34,7 @@ namespace android {
namespace os {
namespace statsd {
-static const string sProcFile = "/proc/uid_cputime/show_uid_stat";
+static const string sProcFile = "/proc/uid_time_in_state";
static const int kLineBufferSize = 1024;
/**
diff --git a/cmds/statsd/src/external/KernelUidCpuActiveTimeReader.cpp b/cmds/statsd/src/external/KernelUidCpuActiveTimeReader.cpp
new file mode 100644
index 000000000000..7a2d1991a538
--- /dev/null
+++ b/cmds/statsd/src/external/KernelUidCpuActiveTimeReader.cpp
@@ -0,0 +1,89 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define DEBUG true // STOPSHIP if true
+#include "Log.h"
+
+#include <fstream>
+
+#include "KernelUidCpuActiveTimeReader.h"
+#include "guardrail/StatsdStats.h"
+#include "logd/LogEvent.h"
+#include "statslog.h"
+
+using std::make_shared;
+using std::shared_ptr;
+using std::ifstream;
+
+namespace android {
+namespace os {
+namespace statsd {
+
+static const string sProcFile = "/proc/uid_concurrent_active_time";
+static const int kLineBufferSize = 1024;
+
+/**
+ * Reads /proc/uid_concurrent_active_time which has the format:
+ * active: X (X is # cores)
+ * [uid0]: [time-0] [time-1] [time-2] ... (# entries = # cores)
+ * [uid1]: [time-0] [time-1] [time-2] ... ...
+ * ...
+ * Time-N means the CPU time a UID spent running concurrently with N other processes.
+ * The file contains a monotonically increasing count of time for a single boot.
+ */
+KernelUidCpuActiveTimeReader::KernelUidCpuActiveTimeReader() : StatsPuller(android::util::CPU_ACTIVE_TIME) {
+}
+
+bool KernelUidCpuActiveTimeReader::PullInternal(vector<shared_ptr<LogEvent>>* data) {
+ data->clear();
+
+ ifstream fin;
+ fin.open(sProcFile);
+ if (!fin.good()) {
+ VLOG("Failed to read pseudo file %s", sProcFile.c_str());
+ return false;
+ }
+
+ uint64_t timestamp = time(nullptr) * NS_PER_SEC;
+ char buf[kLineBufferSize];
+ char* pch;
+ while (!fin.eof()) {
+ fin.getline(buf, kLineBufferSize);
+ pch = strtok(buf, " :");
+ if (pch == NULL) break;
+ uint64_t uid = std::stoull(pch);
+ pch = strtok(NULL, " ");
+ uint64_t timeMs;
+ int idx = 0;
+ do {
+ timeMs = std::stoull(pch);
+ auto ptr = make_shared<LogEvent>(mTagId, timestamp);
+ ptr->write(uid);
+ ptr->write(idx);
+ ptr->write(timeMs);
+ ptr->init();
+ data->push_back(ptr);
+ VLOG("uid %lld, freq idx %d, active time %lld", (long long)uid, idx, (long long)timeMs);
+ idx++;
+ pch = strtok(NULL, " ");
+ } while (pch != NULL);
+ }
+ return true;
+}
+
+} // namespace statsd
+} // namespace os
+} // namespace android
diff --git a/cmds/statsd/src/external/KernelUidCpuActiveTimeReader.h b/cmds/statsd/src/external/KernelUidCpuActiveTimeReader.h
new file mode 100644
index 000000000000..fcae35fa6eb5
--- /dev/null
+++ b/cmds/statsd/src/external/KernelUidCpuActiveTimeReader.h
@@ -0,0 +1,34 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include <utils/String16.h>
+#include "StatsPuller.h"
+
+namespace android {
+namespace os {
+namespace statsd {
+
+class KernelUidCpuActiveTimeReader : public StatsPuller {
+ public:
+ KernelUidCpuActiveTimeReader();
+ bool PullInternal(vector<std::shared_ptr<LogEvent>>* data) override;
+};
+
+} // namespace statsd
+} // namespace os
+} // namespace android
diff --git a/cmds/statsd/src/external/KernelUidCpuClusterTimeReader.cpp b/cmds/statsd/src/external/KernelUidCpuClusterTimeReader.cpp
new file mode 100644
index 000000000000..7426e743c40f
--- /dev/null
+++ b/cmds/statsd/src/external/KernelUidCpuClusterTimeReader.cpp
@@ -0,0 +1,88 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define DEBUG true // STOPSHIP if true
+#include "Log.h"
+
+#include <fstream>
+#include "KernelUidCpuClusterTimeReader.h"
+#include "guardrail/StatsdStats.h"
+#include "logd/LogEvent.h"
+#include "statslog.h"
+
+using std::make_shared;
+using std::shared_ptr;
+using std::ifstream;
+
+namespace android {
+namespace os {
+namespace statsd {
+
+static const string sProcFile = "/proc/uid_concurrent_policy_time";
+static const int kLineBufferSize = 1024;
+
+/**
+ * Reads /proc/uid_concurrent_policy_time which has the format:
+ * policy0: X policy4: Y (there are X cores on policy0, Y cores on policy4)
+ * [uid0]: [time-0-0] [time-0-1] ... [time-1-0] [time-1-1] ...
+ * [uid1]: [time-0-0] [time-0-1] ... [time-1-0] [time-1-1] ...
+ * ...
+ * Time-X-Y means the time a UID spent on clusterX running concurrently with Y other processes.
+ * The file contains a monotonically increasing count of time for a single boot.
+ */
+KernelUidCpuClusterTimeReader::KernelUidCpuClusterTimeReader() : StatsPuller(android::util::CPU_CLUSTER_TIME) {
+}
+
+bool KernelUidCpuClusterTimeReader::PullInternal(vector<shared_ptr<LogEvent>>* data) {
+ data->clear();
+
+ ifstream fin;
+ fin.open(sProcFile);
+ if (!fin.good()) {
+ VLOG("Failed to read pseudo file %s", sProcFile.c_str());
+ return false;
+ }
+
+ uint64_t timestamp = time(nullptr) * NS_PER_SEC;
+ char buf[kLineBufferSize];
+ char* pch;
+ while (!fin.eof()) {
+ fin.getline(buf, kLineBufferSize);
+ pch = strtok(buf, " :");
+ if (pch == NULL) break;
+ uint64_t uid = std::stoull(pch);
+ pch = strtok(NULL, " ");
+ uint64_t timeMs;
+ int idx = 0;
+ do {
+ timeMs = std::stoull(pch);
+ auto ptr = make_shared<LogEvent>(mTagId, timestamp);
+ ptr->write(uid);
+ ptr->write(idx);
+ ptr->write(timeMs);
+ ptr->init();
+ data->push_back(ptr);
+ VLOG("uid %lld, freq idx %d, cluster time %lld", (long long)uid, idx, (long long)timeMs);
+ idx++;
+ pch = strtok(NULL, " ");
+ } while (pch != NULL);
+ }
+ return true;
+}
+
+} // namespace statsd
+} // namespace os
+} // namespace android
diff --git a/cmds/statsd/src/external/KernelUidCpuClusterTimeReader.h b/cmds/statsd/src/external/KernelUidCpuClusterTimeReader.h
new file mode 100644
index 000000000000..90236ae00762
--- /dev/null
+++ b/cmds/statsd/src/external/KernelUidCpuClusterTimeReader.h
@@ -0,0 +1,42 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include <utils/String16.h>
+#include "StatsPuller.h"
+
+namespace android {
+namespace os {
+namespace statsd {
+
+/**
+ * Reads /proc/uid_cputime/show_uid_stat which has the line format:
+ *
+ * uid: user_time_micro_seconds system_time_micro_seconds
+ *
+ * This provides the time a UID's processes spent executing in user-space and kernel-space.
+ * The file contains a monotonically increasing count of time for a single boot.
+ */
+class KernelUidCpuClusterTimeReader : public StatsPuller {
+ public:
+ KernelUidCpuClusterTimeReader();
+ bool PullInternal(vector<std::shared_ptr<LogEvent>>* data) override;
+};
+
+} // namespace statsd
+} // namespace os
+} // namespace android
diff --git a/cmds/statsd/src/external/Perfetto.cpp b/cmds/statsd/src/external/Perfetto.cpp
new file mode 100644
index 000000000000..f7b33e77c557
--- /dev/null
+++ b/cmds/statsd/src/external/Perfetto.cpp
@@ -0,0 +1,111 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "Log.h"
+
+#include "frameworks/base/cmds/statsd/src/statsd_config.pb.h" // Alert
+
+#include <android-base/unique_fd.h>
+#include <errno.h>
+#include <sys/types.h>
+#include <sys/wait.h>
+#include <unistd.h>
+
+#include <string>
+
+namespace {
+const char kDropboxTag[] = "perfetto";
+}
+
+namespace android {
+namespace os {
+namespace statsd {
+
+bool CollectPerfettoTraceAndUploadToDropbox(const PerfettoDetails& config) {
+ ALOGD("Starting trace collection through perfetto");
+
+ if (!config.has_trace_config()) {
+ ALOGE("The perfetto trace config is empty, aborting");
+ return false;
+ }
+
+ android::base::unique_fd readPipe;
+ android::base::unique_fd writePipe;
+ if (!android::base::Pipe(&readPipe, &writePipe)) {
+ ALOGE("pipe() failed while calling the Perfetto client: %s", strerror(errno));
+ return false;
+ }
+
+ pid_t pid = fork();
+ if (pid < 0) {
+ ALOGE("fork() failed while calling the Perfetto client: %s", strerror(errno));
+ return false;
+ }
+
+ if (pid == 0) {
+ // Child process.
+
+ // No malloc calls or library calls after this point. Remember that even
+ // ALOGx (aka android_printLog()) can use dynamic memory for vsprintf().
+
+ writePipe.reset(); // Close the write end (owned by the main process).
+
+ // Replace stdin with |readPipe| so the main process can write into it.
+ if (dup2(readPipe.get(), STDIN_FILENO) < 0) _exit(1);
+ execl("/system/bin/perfetto", "perfetto", "--background", "--config", "-", "--dropbox",
+ kDropboxTag, nullptr);
+
+ // execl() doesn't return in case of success, if we get here something failed.
+ _exit(1);
+ }
+
+ // Main process.
+
+ readPipe.reset(); // Close the read end (owned by the child process).
+
+ // Using fopen() because fwrite() has the right logic to chunking write()
+ // over a pipe (see __sfvwrite()).
+ FILE* writePipeStream = fdopen(writePipe.get(), "wb");
+ if (!writePipeStream) {
+ ALOGE("fdopen() failed while calling the Perfetto client: %s", strerror(errno));
+ return false;
+ }
+
+ std::string cfgProto = config.trace_config().SerializeAsString();
+ size_t bytesWritten = fwrite(cfgProto.data(), 1, cfgProto.size(), writePipeStream);
+ fclose(writePipeStream);
+ if (bytesWritten != cfgProto.size() || cfgProto.size() == 0) {
+ ALOGE("fwrite() failed (ret: %zd) while calling the Perfetto client: %s", bytesWritten,
+ strerror(errno));
+ return false;
+ }
+
+ // This does NOT wait for the full duration of the trace. It just waits until the process
+ // has read the config from stdin and detached.
+ int childStatus = 0;
+ waitpid(pid, &childStatus, 0);
+ if (!WIFEXITED(childStatus) || WEXITSTATUS(childStatus) != 0) {
+ ALOGE("Child process failed (0x%x) while calling the Perfetto client", childStatus);
+ return false;
+ }
+
+ ALOGD("CollectPerfettoTraceAndUploadToDropbox() succeeded");
+ return true;
+}
+
+} // namespace statsd
+} // namespace os
+} // namespace android
diff --git a/cmds/statsd/src/external/Perfetto.h b/cmds/statsd/src/external/Perfetto.h
new file mode 100644
index 000000000000..e2e02533f17f
--- /dev/null
+++ b/cmds/statsd/src/external/Perfetto.h
@@ -0,0 +1,35 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+using android::os::StatsLogEventWrapper;
+
+namespace android {
+namespace os {
+namespace statsd {
+
+class PerfettoDetails; // Declared in statsd_config.pb.h
+
+// Starts the collection of a Perfetto trace with the given |config|.
+// The trace is uploaded to Dropbox by the perfetto cmdline util once done.
+// This method returns immediately after passing the config and does NOT wait
+// for the full duration of the trace.
+bool CollectPerfettoTraceAndUploadToDropbox(const PerfettoDetails& config);
+
+} // namespace statsd
+} // namespace os
+} // namespace android
diff --git a/cmds/statsd/src/external/StatsPullerManagerImpl.cpp b/cmds/statsd/src/external/StatsPullerManagerImpl.cpp
index bb2e8c08dfe6..79f1a5d84174 100644
--- a/cmds/statsd/src/external/StatsPullerManagerImpl.cpp
+++ b/cmds/statsd/src/external/StatsPullerManagerImpl.cpp
@@ -64,6 +64,8 @@ StatsPullerManagerImpl::StatsPullerManagerImpl()
mPullers.insert({android::util::CPU_TIME_PER_FREQ, make_shared<StatsCompanionServicePuller>(android::util::CPU_TIME_PER_FREQ)});
mPullers.insert({android::util::CPU_TIME_PER_UID, make_shared<CpuTimePerUidPuller>()});
mPullers.insert({android::util::CPU_TIME_PER_UID_FREQ, make_shared<CpuTimePerUidFreqPuller>()});
+ mPullers.insert({android::util::CPU_SUSPEND_TIME, make_shared<StatsCompanionServicePuller>(android::util::CPU_SUSPEND_TIME)});
+ mPullers.insert({android::util::CPU_IDLE_TIME, make_shared<StatsCompanionServicePuller>(android::util::CPU_IDLE_TIME)});
mStatsCompanionService = StatsService::getStatsCompanionService();
}
diff --git a/cmds/statsd/src/metrics/ValueMetricProducer.cpp b/cmds/statsd/src/metrics/ValueMetricProducer.cpp
index c7550f7d4711..e98587356857 100644
--- a/cmds/statsd/src/metrics/ValueMetricProducer.cpp
+++ b/cmds/statsd/src/metrics/ValueMetricProducer.cpp
@@ -285,8 +285,15 @@ void ValueMetricProducer::onMatchedLogEventInternalLocked(
interval.start = value;
interval.startUpdated = true;
} else {
+ // Generally we expect value to be monotonically increasing.
+ // If not, there was a reset event. We take the absolute value as
+ // diff in this case.
if (interval.startUpdated) {
- interval.sum += (value - interval.start);
+ if (value > interval.start) {
+ interval.sum += (value - interval.start);
+ } else {
+ interval.sum += value;
+ }
interval.startUpdated = false;
} else {
VLOG("No start for matching end %ld", value);
diff --git a/cmds/statsd/src/packages/UidMap.cpp b/cmds/statsd/src/packages/UidMap.cpp
index dcb8eed1479d..eefb7dc046ec 100644
--- a/cmds/statsd/src/packages/UidMap.cpp
+++ b/cmds/statsd/src/packages/UidMap.cpp
@@ -106,9 +106,9 @@ void UidMap::updateMap(const int64_t& timestamp, const vector<int32_t>& uid,
t->set_uid(uid[j]);
}
mBytesUsed += snapshot->ByteSize();
+ ensureBytesUsedBelowLimit();
StatsdStats::getInstance().setCurrentUidMapMemory(mBytesUsed);
StatsdStats::getInstance().setUidMapSnapshots(mOutput.snapshots_size());
- ensureBytesUsedBelowLimit();
getListenerListCopyLocked(&broadcastList);
}
// To avoid invoking callback while holding the internal lock. we get a copy of the listener
@@ -142,9 +142,9 @@ void UidMap::updateApp(const int64_t& timestamp, const String16& app_16, const i
log->set_uid(uid);
log->set_version(versionCode);
mBytesUsed += log->ByteSize();
+ ensureBytesUsedBelowLimit();
StatsdStats::getInstance().setCurrentUidMapMemory(mBytesUsed);
StatsdStats::getInstance().setUidMapChanges(mOutput.changes_size());
- ensureBytesUsedBelowLimit();
auto range = mMap.equal_range(int(uid));
bool found = false;
@@ -222,9 +222,9 @@ void UidMap::removeApp(const int64_t& timestamp, const String16& app_16, const i
log->set_app(app);
log->set_uid(uid);
mBytesUsed += log->ByteSize();
+ ensureBytesUsedBelowLimit();
StatsdStats::getInstance().setCurrentUidMapMemory(mBytesUsed);
StatsdStats::getInstance().setUidMapChanges(mOutput.changes_size());
- ensureBytesUsedBelowLimit();
auto range = mMap.equal_range(int(uid));
for (auto it = range.first; it != range.second; ++it) {
diff --git a/cmds/statsd/src/packages/UidMap.h b/cmds/statsd/src/packages/UidMap.h
index 4e37977dbf3b..3304f6c976aa 100644
--- a/cmds/statsd/src/packages/UidMap.h
+++ b/cmds/statsd/src/packages/UidMap.h
@@ -152,9 +152,9 @@ private:
// until the memory consumed by mOutput is below the specified limit.
void ensureBytesUsedBelowLimit();
- // Override used for testing the max memory allowed by uid map. -1 means we use the value
+ // Override used for testing the max memory allowed by uid map. 0 means we use the value
// specified in StatsdStats.h with the rest of the guardrails.
- size_t maxBytesOverride = -1;
+ size_t maxBytesOverride = 0;
// Cache the size of mOutput;
size_t mBytesUsed;
diff --git a/cmds/statsd/src/perfetto/perfetto_config.proto b/cmds/statsd/src/perfetto/perfetto_config.proto
new file mode 100644
index 000000000000..dc868f997a63
--- /dev/null
+++ b/cmds/statsd/src/perfetto/perfetto_config.proto
@@ -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.
+ */
+
+syntax = "proto2";
+option optimize_for = LITE_RUNTIME;
+
+package perfetto.protos;
+
+message DataSourceConfig {
+ message FtraceConfig {
+ repeated string event_names = 1;
+ }
+
+ optional string name = 1;
+
+ optional uint32 target_buffer = 2;
+
+ optional FtraceConfig ftrace_config = 100;
+}
+
+message TraceConfig {
+ message BufferConfig {
+ optional uint32 size_kb = 1;
+
+ enum OptimizeFor {
+ DEFAULT = 0;
+ ONE_SHOT_READ = 1;
+
+ }
+ optional OptimizeFor optimize_for = 3;
+
+ enum FillPolicy {
+ UNSPECIFIED = 0;
+ RING_BUFFER = 1;
+ }
+ optional FillPolicy fill_policy = 4;
+ }
+ repeated BufferConfig buffers = 1;
+
+ message DataSource {
+ optional protos.DataSourceConfig config = 1;
+
+ repeated string producer_name_filter = 2;
+ }
+ repeated DataSource data_sources = 2;
+
+ optional uint32 duration_ms = 3;
+}
diff --git a/cmds/statsd/src/statsd_config.proto b/cmds/statsd/src/statsd_config.proto
index ae8a835f0d12..cd60ee74e3ad 100644
--- a/cmds/statsd/src/statsd_config.proto
+++ b/cmds/statsd/src/statsd_config.proto
@@ -22,6 +22,8 @@ package android.os.statsd;
option java_package = "com.android.internal.os";
option java_outer_classname = "StatsdConfigProto";
+import "frameworks/base/cmds/statsd/src/perfetto/perfetto_config.proto";
+
enum Position {
POSITION_UNKNOWN = 0;
FIRST = 1;
@@ -151,9 +153,9 @@ message Bucket {
message MetricConditionLink {
optional int64 condition = 1;
- optional FieldMatcher dimensions_in_what = 2;
+ optional FieldMatcher fields_in_what = 2;
- optional FieldMatcher dimensions_in_condition = 3;
+ optional FieldMatcher fields_in_condition = 3;
}
message FieldFilter {
@@ -180,11 +182,11 @@ message CountMetric {
optional FieldMatcher dimensions_in_what = 4;
- optional FieldMatcher dimensions_in_condition = 5;
+ optional FieldMatcher dimensions_in_condition = 7;
- optional TimeUnit bucket = 6;
+ optional TimeUnit bucket = 5;
- repeated MetricConditionLink links = 7;
+ repeated MetricConditionLink links = 6;
}
message DurationMetric {
@@ -205,9 +207,9 @@ message DurationMetric {
optional FieldMatcher dimensions_in_what = 6;
- optional FieldMatcher dimensions_in_condition = 7;
+ optional FieldMatcher dimensions_in_condition = 8;
- optional TimeUnit bucket = 8;
+ optional TimeUnit bucket = 7;
}
message GaugeMetric {
@@ -221,11 +223,11 @@ message GaugeMetric {
optional FieldMatcher dimensions_in_what = 5;
- optional FieldMatcher dimensions_in_condition = 6;
+ optional FieldMatcher dimensions_in_condition = 8;
- optional TimeUnit bucket = 7;
+ optional TimeUnit bucket = 6;
- repeated MetricConditionLink links = 8;
+ repeated MetricConditionLink links = 7;
}
message ValueMetric {
@@ -239,14 +241,14 @@ message ValueMetric {
optional FieldMatcher dimensions_in_what = 5;
- optional FieldMatcher dimensions_in_condition = 6;
+ optional FieldMatcher dimensions_in_condition = 9;
- optional TimeUnit bucket = 7;
+ optional TimeUnit bucket = 6;
- repeated MetricConditionLink links = 8;
+ repeated MetricConditionLink links = 7;
enum AggregationType { SUM = 1; }
- optional AggregationType aggregation_type = 9 [default = SUM];
+ optional AggregationType aggregation_type = 8 [default = SUM];
}
message Alert {
@@ -272,7 +274,7 @@ message IncidentdDetails {
}
message PerfettoDetails {
- optional int32 perfetto_stuff = 1;
+ optional perfetto.protos.TraceConfig trace_config = 1;
}
message Subscription {
diff --git a/cmds/statsd/statsd.rc b/cmds/statsd/statsd.rc
index c260ae1aa6c8..920273b5dfaa 100644
--- a/cmds/statsd/statsd.rc
+++ b/cmds/statsd/statsd.rc
@@ -16,6 +16,7 @@ service statsd /system/bin/statsd
class main
user statsd
group statsd log
+ writepid /dev/cpuset/system-background/tasks
on post-fs-data
# Create directory for statsd
diff --git a/cmds/statsd/tests/e2e/GaugeMetric_e2e_test.cpp b/cmds/statsd/tests/e2e/GaugeMetric_e2e_test.cpp
index 82502976a383..e56a6c57848f 100644
--- a/cmds/statsd/tests/e2e/GaugeMetric_e2e_test.cpp
+++ b/cmds/statsd/tests/e2e/GaugeMetric_e2e_test.cpp
@@ -57,10 +57,10 @@ StatsdConfig CreateStatsdConfigForPushedEvent() {
auto links = gaugeMetric->add_links();
links->set_condition(isInBackgroundPredicate.id());
- auto dimensionWhat = links->mutable_dimensions_in_what();
+ auto dimensionWhat = links->mutable_fields_in_what();
dimensionWhat->set_field(android::util::APP_START_CHANGED);
dimensionWhat->add_child()->set_field(1); // uid field.
- auto dimensionCondition = links->mutable_dimensions_in_condition();
+ auto dimensionCondition = links->mutable_fields_in_condition();
dimensionCondition->set_field(android::util::ACTIVITY_FOREGROUND_STATE_CHANGED);
dimensionCondition->add_child()->set_field(1); // uid field.
return config;
diff --git a/cmds/statsd/tests/e2e/MetricConditionLink_e2e_test.cpp b/cmds/statsd/tests/e2e/MetricConditionLink_e2e_test.cpp
index 178dd71354c4..eda16a2ffbfd 100644
--- a/cmds/statsd/tests/e2e/MetricConditionLink_e2e_test.cpp
+++ b/cmds/statsd/tests/e2e/MetricConditionLink_e2e_test.cpp
@@ -46,7 +46,7 @@ StatsdConfig CreateStatsdConfig() {
auto isSyncingPredicate = CreateIsSyncingPredicate();
*isSyncingPredicate.mutable_simple_predicate()->mutable_dimensions() =
CreateDimensions(
- android::util::SYNC_STATE_CHANGED, {1 /* uid field */});
+ android::util::SYNC_STATE_CHANGED, {1 /* uid field */, 2 /* name field*/});
auto isInBackgroundPredicate = CreateIsInBackgroundPredicate();
*isInBackgroundPredicate.mutable_simple_predicate()->mutable_dimensions() =
@@ -75,20 +75,20 @@ StatsdConfig CreateStatsdConfig() {
// Links between crash atom and condition of app is in syncing.
auto links = countMetric->add_links();
links->set_condition(isSyncingPredicate.id());
- auto dimensionWhat = links->mutable_dimensions_in_what();
+ auto dimensionWhat = links->mutable_fields_in_what();
dimensionWhat->set_field(android::util::PROCESS_LIFE_CYCLE_STATE_CHANGED);
dimensionWhat->add_child()->set_field(1); // uid field.
- auto dimensionCondition = links->mutable_dimensions_in_condition();
+ auto dimensionCondition = links->mutable_fields_in_condition();
dimensionCondition->set_field(android::util::SYNC_STATE_CHANGED);
dimensionCondition->add_child()->set_field(1); // uid field.
// Links between crash atom and condition of app is in background.
links = countMetric->add_links();
links->set_condition(isInBackgroundPredicate.id());
- dimensionWhat = links->mutable_dimensions_in_what();
+ dimensionWhat = links->mutable_fields_in_what();
dimensionWhat->set_field(android::util::PROCESS_LIFE_CYCLE_STATE_CHANGED);
dimensionWhat->add_child()->set_field(1); // uid field.
- dimensionCondition = links->mutable_dimensions_in_condition();
+ dimensionCondition = links->mutable_fields_in_condition();
dimensionCondition->set_field(android::util::ACTIVITY_FOREGROUND_STATE_CHANGED);
dimensionCondition->add_child()->set_field(1); // uid field.
return config;
diff --git a/cmds/statsd/tests/metrics/CountMetricProducer_test.cpp b/cmds/statsd/tests/metrics/CountMetricProducer_test.cpp
index c39151313c55..897328d4635e 100644
--- a/cmds/statsd/tests/metrics/CountMetricProducer_test.cpp
+++ b/cmds/statsd/tests/metrics/CountMetricProducer_test.cpp
@@ -149,8 +149,8 @@ TEST(CountMetricProducerTest, TestEventsWithSlicedCondition) {
metric.set_condition(StringToId("APP_IN_BACKGROUND_PER_UID_AND_SCREEN_ON"));
MetricConditionLink* link = metric.add_links();
link->set_condition(StringToId("APP_IN_BACKGROUND_PER_UID"));
- *link->mutable_dimensions_in_what() = buildSimpleAtomFieldMatcher(tagId, 1);
- *link->mutable_dimensions_in_condition() = buildSimpleAtomFieldMatcher(conditionTagId, 2);
+ *link->mutable_fields_in_what() = buildSimpleAtomFieldMatcher(tagId, 1);
+ *link->mutable_fields_in_condition() = buildSimpleAtomFieldMatcher(conditionTagId, 2);
LogEvent event1(tagId, bucketStartTimeNs + 1);
event1.write("111"); // uid
diff --git a/cmds/statsd/tests/metrics/EventMetricProducer_test.cpp b/cmds/statsd/tests/metrics/EventMetricProducer_test.cpp
index 7171de939c62..34cde607988e 100644
--- a/cmds/statsd/tests/metrics/EventMetricProducer_test.cpp
+++ b/cmds/statsd/tests/metrics/EventMetricProducer_test.cpp
@@ -98,8 +98,8 @@ TEST(EventMetricProducerTest, TestEventsWithSlicedCondition) {
metric.set_condition(StringToId("APP_IN_BACKGROUND_PER_UID_AND_SCREEN_ON"));
MetricConditionLink* link = metric.add_links();
link->set_condition(StringToId("APP_IN_BACKGROUND_PER_UID"));
- *link->mutable_dimensions_in_what() = buildSimpleAtomFieldMatcher(tagId, 1);
- *link->mutable_dimensions_in_condition() = buildSimpleAtomFieldMatcher(conditionTagId, 2);
+ *link->mutable_fields_in_what() = buildSimpleAtomFieldMatcher(tagId, 1);
+ *link->mutable_fields_in_condition() = buildSimpleAtomFieldMatcher(conditionTagId, 2);
LogEvent event1(tagId, bucketStartTimeNs + 1);
EXPECT_TRUE(event1.write("111"));
diff --git a/cmds/statsd/tools/dogfood/Android.mk b/cmds/statsd/tools/dogfood/Android.mk
index a4c080063284..73fbaa4e2ad0 100644
--- a/cmds/statsd/tools/dogfood/Android.mk
+++ b/cmds/statsd/tools/dogfood/Android.mk
@@ -21,9 +21,11 @@ LOCAL_PACKAGE_NAME := StatsdDogfood
LOCAL_SRC_FILES := $(call all-java-files-under, src)
LOCAL_SRC_FILES += ../../src/stats_log.proto \
../../src/atoms.proto \
+ ../../src/perfetto/perfetto_config.proto \
../../src/statsd_config.proto
LOCAL_PROTOC_FLAGS := --proto_path=$(LOCAL_PATH)/../../src/
+
LOCAL_RESOURCE_DIR := $(LOCAL_PATH)/res
LOCAL_STATIC_JAVA_LIBRARIES := platformprotoslite
diff --git a/cmds/statsd/tools/loadtest/Android.mk b/cmds/statsd/tools/loadtest/Android.mk
index 0a0fd6647fbb..f5722c2c3d19 100644
--- a/cmds/statsd/tools/loadtest/Android.mk
+++ b/cmds/statsd/tools/loadtest/Android.mk
@@ -21,6 +21,7 @@ LOCAL_PACKAGE_NAME := StatsdLoadtest
LOCAL_SRC_FILES := $(call all-java-files-under, src)
LOCAL_SRC_FILES += ../../src/stats_log.proto \
../../src/atoms.proto \
+ ../../src/perfetto/perfetto_config.proto \
../../src/statsd_config.proto
LOCAL_PROTOC_FLAGS := --proto_path=$(LOCAL_PATH)/../../src/
LOCAL_RESOURCE_DIR := $(LOCAL_PATH)/res
diff --git a/core/java/android/accessibilityservice/AccessibilityService.java b/core/java/android/accessibilityservice/AccessibilityService.java
index 97dcb90bbb99..0a4541ba4777 100644
--- a/core/java/android/accessibilityservice/AccessibilityService.java
+++ b/core/java/android/accessibilityservice/AccessibilityService.java
@@ -363,6 +363,11 @@ public abstract class AccessibilityService extends Service {
*/
public static final int GLOBAL_ACTION_LOCK_SCREEN = 8;
+ /**
+ * Action to take a screenshot
+ */
+ public static final int GLOBAL_ACTION_TAKE_SCREENSHOT = 9;
+
private static final String LOG_TAG = "AccessibilityService";
/**
diff --git a/core/java/android/app/admin/DeviceAdminReceiver.java b/core/java/android/app/admin/DeviceAdminReceiver.java
index 302d52f1ae72..ffb3affb03b3 100644
--- a/core/java/android/app/admin/DeviceAdminReceiver.java
+++ b/core/java/android/app/admin/DeviceAdminReceiver.java
@@ -339,7 +339,7 @@ public class DeviceAdminReceiver extends BroadcastReceiver {
/**
* Broadcast action: notify the device owner that a user or profile has been removed.
* Carries an extra {@link Intent#EXTRA_USER} that has the {@link UserHandle} of
- * the new user.
+ * the user.
* @hide
*/
@SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
@@ -347,6 +347,36 @@ public class DeviceAdminReceiver extends BroadcastReceiver {
public static final String ACTION_USER_REMOVED = "android.app.action.USER_REMOVED";
/**
+ * Broadcast action: notify the device owner that a user or profile has been started.
+ * Carries an extra {@link Intent#EXTRA_USER} that has the {@link UserHandle} of
+ * the user.
+ * @hide
+ */
+ @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
+ @BroadcastBehavior(explicitOnly = true)
+ public static final String ACTION_USER_STARTED = "android.app.action.USER_STARTED";
+
+ /**
+ * Broadcast action: notify the device owner that a user or profile has been stopped.
+ * Carries an extra {@link Intent#EXTRA_USER} that has the {@link UserHandle} of
+ * the user.
+ * @hide
+ */
+ @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
+ @BroadcastBehavior(explicitOnly = true)
+ public static final String ACTION_USER_STOPPED = "android.app.action.USER_STOPPED";
+
+ /**
+ * Broadcast action: notify the device owner that a user or profile has been switched to.
+ * Carries an extra {@link Intent#EXTRA_USER} that has the {@link UserHandle} of
+ * the user.
+ * @hide
+ */
+ @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
+ @BroadcastBehavior(explicitOnly = true)
+ public static final String ACTION_USER_SWITCHED = "android.app.action.USER_SWITCHED";
+
+ /**
* A string containing the SHA-256 hash of the bugreport file.
*
* @see #ACTION_BUGREPORT_SHARE
@@ -914,6 +944,42 @@ public class DeviceAdminReceiver extends BroadcastReceiver {
}
/**
+ * Called when a user or profile is started.
+ *
+ * <p>This callback is only applicable to device owners.
+ *
+ * @param context The running context as per {@link #onReceive}.
+ * @param intent The received intent as per {@link #onReceive}.
+ * @param startedUser The {@link UserHandle} of the user that has just been started.
+ */
+ public void onUserStarted(Context context, Intent intent, UserHandle startedUser) {
+ }
+
+ /**
+ * Called when a user or profile is stopped.
+ *
+ * <p>This callback is only applicable to device owners.
+ *
+ * @param context The running context as per {@link #onReceive}.
+ * @param intent The received intent as per {@link #onReceive}.
+ * @param stoppedUser The {@link UserHandle} of the user that has just been stopped.
+ */
+ public void onUserStopped(Context context, Intent intent, UserHandle stoppedUser) {
+ }
+
+ /**
+ * Called when a user or profile is switched to.
+ *
+ * <p>This callback is only applicable to device owners.
+ *
+ * @param context The running context as per {@link #onReceive}.
+ * @param intent The received intent as per {@link #onReceive}.
+ * @param switchedUser The {@link UserHandle} of the user that has just been switched to.
+ */
+ public void onUserSwitched(Context context, Intent intent, UserHandle switchedUser) {
+ }
+
+ /**
* Called on the newly assigned owner (either device owner or profile owner) when the ownership
* transfer has completed successfully.
*
@@ -989,6 +1055,12 @@ public class DeviceAdminReceiver extends BroadcastReceiver {
onUserAdded(context, intent, intent.getParcelableExtra(Intent.EXTRA_USER));
} else if (ACTION_USER_REMOVED.equals(action)) {
onUserRemoved(context, intent, intent.getParcelableExtra(Intent.EXTRA_USER));
+ } else if (ACTION_USER_STARTED.equals(action)) {
+ onUserStarted(context, intent, intent.getParcelableExtra(Intent.EXTRA_USER));
+ } else if (ACTION_USER_STOPPED.equals(action)) {
+ onUserStopped(context, intent, intent.getParcelableExtra(Intent.EXTRA_USER));
+ } else if (ACTION_USER_SWITCHED.equals(action)) {
+ onUserSwitched(context, intent, intent.getParcelableExtra(Intent.EXTRA_USER));
} else if (ACTION_TRANSFER_OWNERSHIP_COMPLETE.equals(action)) {
PersistableBundle bundle =
intent.getParcelableExtra(EXTRA_TRANSFER_OWNER_ADMIN_EXTRAS_BUNDLE);
diff --git a/core/java/android/app/admin/DevicePolicyManager.java b/core/java/android/app/admin/DevicePolicyManager.java
index 9329d56a8de9..0be55642d4cf 100644
--- a/core/java/android/app/admin/DevicePolicyManager.java
+++ b/core/java/android/app/admin/DevicePolicyManager.java
@@ -9197,4 +9197,50 @@ public class DevicePolicyManager {
throw re.rethrowFromSystemServer();
}
}
+
+ /**
+ * Allows/disallows printing.
+ *
+ * @param admin which {@link DeviceAdminReceiver} this request is associated with.
+ * @param enabled whether printing should be allowed or not.
+ * @throws SecurityException if {@code admin} is neither device, nor profile owner.
+ * @hide
+ */
+ public void setPrintingEnabled(@NonNull ComponentName admin, boolean enabled) {
+ try {
+ mService.setPrintingEnabled(admin, enabled);
+ } catch (RemoteException re) {
+ throw re.rethrowFromSystemServer();
+ }
+ }
+
+ /**
+ * Returns whether printing is enabled for current user.
+ *
+ * @return {@code true} iff printing is enabled.
+ * @hide
+ */
+ public boolean isPrintingEnabled() {
+ try {
+ return mService.isPrintingEnabled();
+ } catch (RemoteException re) {
+ throw re.rethrowFromSystemServer();
+ }
+ }
+
+ /**
+ * Returns error message to be displayed when printing is disabled.
+ *
+ * Used only by PrintService.
+ * @return Localized error message.
+ * @throws SecurityException if caller is not system.
+ * @hide
+ */
+ public CharSequence getPrintingDisabledReason() {
+ try {
+ return mService.getPrintingDisabledReason();
+ } catch (RemoteException re) {
+ throw re.rethrowFromSystemServer();
+ }
+ }
}
diff --git a/core/java/android/app/admin/IDevicePolicyManager.aidl b/core/java/android/app/admin/IDevicePolicyManager.aidl
index eac7f7ed4b3e..d2a2be7bbcb5 100644
--- a/core/java/android/app/admin/IDevicePolicyManager.aidl
+++ b/core/java/android/app/admin/IDevicePolicyManager.aidl
@@ -396,4 +396,8 @@ interface IDevicePolicyManager {
void setEndUserSessionMessage(in ComponentName admin, in CharSequence endUserSessionMessage);
CharSequence getStartUserSessionMessage(in ComponentName admin);
CharSequence getEndUserSessionMessage(in ComponentName admin);
+
+ void setPrintingEnabled(in ComponentName admin, boolean enabled);
+ boolean isPrintingEnabled();
+ CharSequence getPrintingDisabledReason();
}
diff --git a/core/java/android/app/job/JobInfo.java b/core/java/android/app/job/JobInfo.java
index 7c40b4eaf375..cba9dcc3c4cc 100644
--- a/core/java/android/app/job/JobInfo.java
+++ b/core/java/android/app/job/JobInfo.java
@@ -253,6 +253,11 @@ public class JobInfo implements Parcelable {
/**
* @hide
*/
+ public static final int FLAG_IS_PREFETCH = 1 << 2;
+
+ /**
+ * @hide
+ */
public static final int CONSTRAINT_FLAG_CHARGING = 1 << 0;
/**
@@ -1364,6 +1369,28 @@ public class JobInfo implements Parcelable {
}
/**
+ * Setting this to true indicates that this job is designed to prefetch
+ * content that will make a material improvement to the experience of
+ * the specific user of this device. For example, fetching top headlines
+ * of interest to the current user.
+ * <p>
+ * The system may use this signal to relax the network constraints you
+ * originally requested, such as allowing a
+ * {@link JobInfo#NETWORK_TYPE_UNMETERED} job to run over a metered
+ * network when there is a surplus of metered data available. The system
+ * may also use this signal in combination with end user usage patterns
+ * to ensure data is prefetched before the user launches your app.
+ */
+ public Builder setIsPrefetch(boolean isPrefetch) {
+ if (isPrefetch) {
+ mFlags |= FLAG_IS_PREFETCH;
+ } else {
+ mFlags &= (~FLAG_IS_PREFETCH);
+ }
+ return this;
+ }
+
+ /**
* Set whether or not to persist this job across device reboots.
*
* @param isPersisted True to indicate that the job will be written to
diff --git a/core/java/android/app/usage/UsageStatsManagerInternal.java b/core/java/android/app/usage/UsageStatsManagerInternal.java
index 5cd0981f72e3..bd978e3df863 100644
--- a/core/java/android/app/usage/UsageStatsManagerInternal.java
+++ b/core/java/android/app/usage/UsageStatsManagerInternal.java
@@ -176,6 +176,12 @@ public abstract class UsageStatsManagerInternal {
public abstract void setActiveAdminApps(Set<String> adminApps, int userId);
/**
+ * Called by DevicePolicyManagerService during boot to inform that admin data is loaded and
+ * pushed to UsageStatsService.
+ */
+ public abstract void onAdminDataAvailable();
+
+ /**
* Return usage stats.
*
* @param obfuscateInstantApps whether instant app package names need to be obfuscated in the
diff --git a/core/java/android/content/Intent.java b/core/java/android/content/Intent.java
index 6e9970980e96..f05a4d1aa9c7 100644
--- a/core/java/android/content/Intent.java
+++ b/core/java/android/content/Intent.java
@@ -3516,12 +3516,83 @@ public class Intent implements Parcelable, Cloneable {
* For more details see TelephonyIntents.ACTION_SIM_STATE_CHANGED. This is here
* because TelephonyIntents is an internal class.
* @hide
+ * @deprecated Use {@link #ACTION_SIM_CARD_STATE_CHANGED} or
+ * {@link #ACTION_SIM_APPLICATION_STATE_CHANGED}
*/
+ @Deprecated
@SystemApi
@SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
public static final String ACTION_SIM_STATE_CHANGED = "android.intent.action.SIM_STATE_CHANGED";
/**
+ * Broadcast Action: The sim card state has changed.
+ * The intent will have the following extra values:</p>
+ * <dl>
+ * <dt>{@link android.telephony.TelephonyManager.EXTRA_SIM_STATE}</dt>
+ * <dd>The sim card state. One of:
+ * <dl>
+ * <dt>{@link android.telephony.TelephonyManager.SIM_STATE_ABSENT}</dt>
+ * <dd>SIM card not found</dd>
+ * <dt>{@link android.telephony.TelephonyManager.SIM_STATE_CARD_IO_ERROR}</dt>
+ * <dd>SIM card IO error</dd>
+ * <dt>{@link android.telephony.TelephonyManager.SIM_STATE_CARD_RESTRICTED}</dt>
+ * <dd>SIM card is restricted</dd>
+ * <dt>{@link android.telephony.TelephonyManager.SIM_STATE_PRESENT}</dt>
+ * <dd>SIM card is present</dd>
+ * </dl>
+ * </dd>
+ * </dl>
+ *
+ * <p class="note">Requires the READ_PRIVILEGED_PHONE_STATE permission.
+ *
+ * <p class="note">The current state can also be queried using
+ * {@link android.telephony.TelephonyManager.getSimCardState()}
+ *
+ * <p class="note">This is a protected intent that can only be sent by the system.
+ * @hide
+ */
+ @SystemApi
+ @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
+ public static final String ACTION_SIM_CARD_STATE_CHANGED =
+ "android.intent.action.SIM_CARD_STATE_CHANGED";
+
+ /**
+ * Broadcast Action: The sim application state has changed.
+ * The intent will have the following extra values:</p>
+ * <dl>
+ * <dt>{@link android.telephony.TelephonyManager.EXTRA_SIM_STATE}</dt>
+ * <dd>The sim application state. One of:
+ * <dl>
+ * <dt>{@link android.telephony.TelephonyManager.SIM_STATE_NOT_READY}</dt>
+ * <dd>SIM card applications not ready</dd>
+ * <dt>{@link android.telephony.TelephonyManager.SIM_STATE_PIN_REQUIRED}</dt>
+ * <dd>SIM card PIN locked</dd>
+ * <dt>{@link android.telephony.TelephonyManager.SIM_STATE_PUK_REQUIRED}</dt>
+ * <dd>SIM card PUK locked</dd>
+ * <dt>{@link android.telephony.TelephonyManager.SIM_STATE_NETWORK_LOCKED}</dt>
+ * <dd>SIM card network locked</dd>
+ * <dt>{@link android.telephony.TelephonyManager.SIM_STATE_PERM_DISABLED}</dt>
+ * <dd>SIM card permanently disabled due to PUK failures</dd>
+ * <dt>{@link android.telephony.TelephonyManager.SIM_STATE_LOADED}</dt>
+ * <dd>SIM card data loaded</dd>
+ * </dl>
+ * </dd>
+ * </dl>
+ *
+ * <p class="note">Requires the READ_PRIVILEGED_PHONE_STATE permission.
+ *
+ * <p class="note">The current state can also be queried using
+ * {@link android.telephony.TelephonyManager.getSimApplicationState()}
+ *
+ * <p class="note">This is a protected intent that can only be sent by the system.
+ * @hide
+ */
+ @SystemApi
+ @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
+ public static final String ACTION_SIM_APPLICATION_STATE_CHANGED =
+ "android.intent.action.SIM_APPLICATION_STATE_CHANGED";
+
+ /**
* Broadcast Action: indicate that the phone service state has changed.
* The intent will have the following extra values:</p>
* <p>
diff --git a/core/java/android/content/pm/PackageManagerInternal.java b/core/java/android/content/pm/PackageManagerInternal.java
index 2c45b8d8b30e..6f093ba8d005 100644
--- a/core/java/android/content/pm/PackageManagerInternal.java
+++ b/core/java/android/content/pm/PackageManagerInternal.java
@@ -436,6 +436,11 @@ public abstract class PackageManagerInternal {
*/
public abstract int getUidTargetSdkVersion(int uid);
+ /**
+ * Return the taget SDK version for the app with the given package name.
+ */
+ public abstract int getPackageTargetSdkVersion(String packageName);
+
/** Whether the binder caller can access instant apps. */
public abstract boolean canAccessInstantApps(int callingUid, int userId);
diff --git a/core/java/android/hardware/HardwareBuffer.java b/core/java/android/hardware/HardwareBuffer.java
index 7866b52cc68c..9aa3f40a8f0a 100644
--- a/core/java/android/hardware/HardwareBuffer.java
+++ b/core/java/android/hardware/HardwareBuffer.java
@@ -25,11 +25,11 @@ import android.os.Parcelable;
import dalvik.annotation.optimization.FastNative;
import dalvik.system.CloseGuard;
+import libcore.util.NativeAllocationRegistry;
+
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
-import libcore.util.NativeAllocationRegistry;
-
/**
* HardwareBuffer wraps a native <code>AHardwareBuffer</code> object, which is a low-level object
* representing a memory buffer accessible by various hardware units. HardwareBuffer allows sharing
@@ -42,18 +42,25 @@ import libcore.util.NativeAllocationRegistry;
public final class HardwareBuffer implements Parcelable, AutoCloseable {
/** @hide */
@Retention(RetentionPolicy.SOURCE)
- @IntDef(prefix = { "RGB", "BLOB" }, value = {
+ @IntDef(prefix = { "RGB", "BLOB", "D_", "DS_", "S_" }, value = {
RGBA_8888,
RGBA_FP16,
RGBA_1010102,
RGBX_8888,
RGB_888,
RGB_565,
- BLOB
+ BLOB,
+ D_16,
+ D_24,
+ DS_24UI8,
+ D_FP32,
+ DS_FP32UI8,
+ S_UI8,
})
public @interface Format {
}
+ @Format
/** Format: 8 bits each red, green, blue, alpha */
public static final int RGBA_8888 = 1;
/** Format: 8 bits each red, green, blue, alpha, alpha is always 0xFF */
@@ -68,6 +75,18 @@ public final class HardwareBuffer implements Parcelable, AutoCloseable {
public static final int RGBA_1010102 = 0x2b;
/** Format: opaque format used for raw data transfer; must have a height of 1 */
public static final int BLOB = 0x21;
+ /** Format: 16 bits depth */
+ public static final int D_16 = 0x30;
+ /** Format: 24 bits depth */
+ public static final int D_24 = 0x31;
+ /** Format: 24 bits depth, 8 bits stencil */
+ public static final int DS_24UI8 = 0x32;
+ /** Format: 32 bits depth */
+ public static final int D_FP32 = 0x33;
+ /** Format: 32 bits depth, 8 bits stencil */
+ public static final int DS_FP32UI8 = 0x34;
+ /** Format: 8 bits stencil */
+ public static final int S_UI8 = 0x35;
// Note: do not rename, this field is used by native code
private long mNativeObject;
@@ -82,9 +101,11 @@ public final class HardwareBuffer implements Parcelable, AutoCloseable {
@LongDef(flag = true, value = {USAGE_CPU_READ_RARELY, USAGE_CPU_READ_OFTEN,
USAGE_CPU_WRITE_RARELY, USAGE_CPU_WRITE_OFTEN, USAGE_GPU_SAMPLED_IMAGE,
USAGE_GPU_COLOR_OUTPUT, USAGE_PROTECTED_CONTENT, USAGE_VIDEO_ENCODE,
- USAGE_GPU_DATA_BUFFER, USAGE_SENSOR_DIRECT_DATA})
+ USAGE_GPU_DATA_BUFFER, USAGE_SENSOR_DIRECT_DATA, USAGE_GPU_CUBE_MAP,
+ USAGE_GPU_MIPMAP_COMPLETE})
public @interface Usage {};
+ @Usage
/** Usage: The buffer will sometimes be read by the CPU */
public static final long USAGE_CPU_READ_RARELY = 2;
/** Usage: The buffer will often be read by the CPU */
@@ -107,6 +128,10 @@ public final class HardwareBuffer implements Parcelable, AutoCloseable {
public static final long USAGE_SENSOR_DIRECT_DATA = 1 << 23;
/** Usage: The buffer will be used as a shader storage or uniform buffer object */
public static final long USAGE_GPU_DATA_BUFFER = 1 << 24;
+ /** Usage: The buffer will be used as a cube map texture */
+ public static final long USAGE_GPU_CUBE_MAP = 1 << 25;
+ /** Usage: The buffer contains a complete mipmap hierarchy */
+ public static final long USAGE_GPU_MIPMAP_COMPLETE = 1 << 26;
// The approximate size of a native AHardwareBuffer object.
private static final long NATIVE_HARDWARE_BUFFER_SIZE = 232;
@@ -118,15 +143,9 @@ public final class HardwareBuffer implements Parcelable, AutoCloseable {
*
* @param width The width in pixels of the buffer
* @param height The height in pixels of the buffer
- * @param format The format of each pixel, one of {@link #RGBA_8888}, {@link #RGBA_FP16},
- * {@link #RGBX_8888}, {@link #RGB_565}, {@link #RGB_888}, {@link #RGBA_1010102}, {@link #BLOB}
+ * @param format The @Format of each pixel
* @param layers The number of layers in the buffer
- * @param usage Flags describing how the buffer will be used, one of
- * {@link #USAGE_CPU_READ_RARELY}, {@link #USAGE_CPU_READ_OFTEN},
- * {@link #USAGE_CPU_WRITE_RARELY}, {@link #USAGE_CPU_WRITE_OFTEN},
- * {@link #USAGE_GPU_SAMPLED_IMAGE}, {@link #USAGE_GPU_COLOR_OUTPUT},
- * {@link #USAGE_GPU_DATA_BUFFER}, {@link #USAGE_PROTECTED_CONTENT},
- * {@link #USAGE_SENSOR_DIRECT_DATA}, {@link #USAGE_VIDEO_ENCODE}
+ * @param usage The @Usage flags describing how the buffer will be used
* @return A <code>HardwareBuffer</code> instance if successful, or throws an
* IllegalArgumentException if the dimensions passed are invalid (either zero, negative, or
* too large to allocate), if the format is not supported, if the requested number of layers
@@ -154,7 +173,7 @@ public final class HardwareBuffer implements Parcelable, AutoCloseable {
if (nativeObject == 0) {
throw new IllegalArgumentException("Unable to create a HardwareBuffer, either the " +
"dimensions passed were too large, too many image layers were requested, " +
- "or an invalid set of usage flags was passed");
+ "or an invalid set of usage flags or invalid format was passed");
}
return new HardwareBuffer(nativeObject);
}
@@ -206,8 +225,7 @@ public final class HardwareBuffer implements Parcelable, AutoCloseable {
}
/**
- * Returns the format of this buffer, one of {@link #RGBA_8888}, {@link #RGBA_FP16},
- * {@link #RGBX_8888}, {@link #RGB_565}, {@link #RGB_888}, {@link #RGBA_1010102}, {@link #BLOB}.
+ * Returns the @Format of this buffer.
*/
@Format
public int getFormat() {
@@ -338,6 +356,12 @@ public final class HardwareBuffer implements Parcelable, AutoCloseable {
case RGB_565:
case RGB_888:
case BLOB:
+ case D_16:
+ case D_24:
+ case DS_24UI8:
+ case D_FP32:
+ case DS_FP32UI8:
+ case S_UI8:
return true;
}
return false;
diff --git a/core/java/android/hardware/camera2/CameraDevice.java b/core/java/android/hardware/camera2/CameraDevice.java
index ce1fba798c0e..639795ab8080 100644
--- a/core/java/android/hardware/camera2/CameraDevice.java
+++ b/core/java/android/hardware/camera2/CameraDevice.java
@@ -183,7 +183,9 @@ public abstract class CameraDevice implements AutoCloseable {
TEMPLATE_RECORD,
TEMPLATE_VIDEO_SNAPSHOT,
TEMPLATE_ZERO_SHUTTER_LAG,
- TEMPLATE_MANUAL })
+ TEMPLATE_MANUAL,
+ TEMPLATE_MOTION_TRACKING_PREVIEW,
+ TEMPLATE_MOTION_TRACKING_BEST})
public @interface RequestTemplate {};
/**
@@ -424,14 +426,17 @@ public abstract class CameraDevice implements AutoCloseable {
* {@link CameraMetadata#INFO_SUPPORTED_HARDWARE_LEVEL_LIMITED LIMITED} devices. The
* {@code FULL FOV 640} entry means that the device will support a resolution that's 640 pixels
* wide, with the height set so that the resolution aspect ratio matches the MAXIMUM output
- * aspect ratio. So for a device with a 4:3 image sensor, this will be 640x480, and for a
- * device with a 16:9 sensor, this will be 640x360, and so on.
+ * aspect ratio, rounded down. So for a device with a 4:3 image sensor, this will be 640x480,
+ * and for a device with a 16:9 sensor, this will be 640x360, and so on. And the
+ * {@code MAX 30FPS} entry means the largest JPEG resolution on the device for which
+ * {@link android.hardware.camera2.params.StreamConfigurationMap#getOutputMinFrameDuration}
+ * returns a value less than or equal to 1/30s.
*
* <table>
* <tr><th colspan="7">MOTION_TRACKING-capability additional guaranteed configurations</th></tr>
* <tr><th colspan="2" id="rb">Target 1</th><th colspan="2" id="rb">Target 2</th><th colspan="2" id="rb">Target 3</th><th rowspan="2">Sample use case(s)</th> </tr>
* <tr><th>Type</th><th id="rb">Max size</th><th>Type</th><th id="rb">Max size</th><th>Type</th><th id="rb">Max size</th></tr>
- * <tr> <td>{@code PRIV}</td><td id="rb">{@code PREVIEW}</td> <td>{@code YUV }</td><td id="rb">{@code FULL FOV 640}</td> <td>{@code YUV }</td><td id="rb">{@code MAXIMUM}</td> <td>Live preview with a tracking YUV output and a maximum-resolution YUV for still captures.</td> </tr>
+ * <tr> <td>{@code YUV}</td><td id="rb">{@code PREVIEW}</td> <td>{@code YUV }</td><td id="rb">{@code FULL FOV 640}</td> <td>{@code JPEG}</td><td id="rb">{@code MAX 30FPS}</td> <td>Preview with a tracking YUV output and a as-large-as-possible JPEG for still captures.</td> </tr>
* </table><br>
* </p>
*
@@ -899,12 +904,6 @@ public abstract class CameraDevice implements AutoCloseable {
* @throws CameraAccessException if the camera device is no longer connected or has
* encountered a fatal error
* @throws IllegalStateException if the camera device has been closed
- *
- * @see #TEMPLATE_PREVIEW
- * @see #TEMPLATE_RECORD
- * @see #TEMPLATE_STILL_CAPTURE
- * @see #TEMPLATE_VIDEO_SNAPSHOT
- * @see #TEMPLATE_MANUAL
*/
@NonNull
public abstract CaptureRequest.Builder createCaptureRequest(@RequestTemplate int templateType)
diff --git a/core/java/android/hardware/camera2/CameraMetadata.java b/core/java/android/hardware/camera2/CameraMetadata.java
index 1c7f2896b167..2294ec56525f 100644
--- a/core/java/android/hardware/camera2/CameraMetadata.java
+++ b/core/java/android/hardware/camera2/CameraMetadata.java
@@ -1359,6 +1359,20 @@ public abstract class CameraMetadata<TKey> {
*/
public static final int CONTROL_AE_MODE_ON_AUTO_FLASH_REDEYE = 4;
+ /**
+ * <p>An external flash has been turned on.</p>
+ * <p>It informs the camera device that an external flash has been turned on, and that
+ * metering (and continuous focus if active) should be quickly recaculated to account
+ * for the external flash. Otherwise, this mode acts like ON.</p>
+ * <p>When the external flash is turned off, AE mode should be changed to one of the
+ * other available AE modes.</p>
+ * <p>If the camera device supports AE external flash mode, aeState must be
+ * FLASH_REQUIRED after the camera device finishes AE scan and it's too dark without
+ * flash.</p>
+ * @see CaptureRequest#CONTROL_AE_MODE
+ */
+ public static final int CONTROL_AE_MODE_ON_EXTERNAL_FLASH = 5;
+
//
// Enumeration values for CaptureRequest#CONTROL_AE_PRECAPTURE_TRIGGER
//
diff --git a/core/java/android/hardware/camera2/CaptureRequest.java b/core/java/android/hardware/camera2/CaptureRequest.java
index cf27c704f7e5..ce75fa52eff7 100644
--- a/core/java/android/hardware/camera2/CaptureRequest.java
+++ b/core/java/android/hardware/camera2/CaptureRequest.java
@@ -1076,6 +1076,7 @@ public final class CaptureRequest extends CameraMetadata<CaptureRequest.Key<?>>
* <li>{@link #CONTROL_AE_MODE_ON_AUTO_FLASH ON_AUTO_FLASH}</li>
* <li>{@link #CONTROL_AE_MODE_ON_ALWAYS_FLASH ON_ALWAYS_FLASH}</li>
* <li>{@link #CONTROL_AE_MODE_ON_AUTO_FLASH_REDEYE ON_AUTO_FLASH_REDEYE}</li>
+ * <li>{@link #CONTROL_AE_MODE_ON_EXTERNAL_FLASH ON_EXTERNAL_FLASH}</li>
* </ul></p>
* <p><b>Available values for this device:</b><br>
* {@link CameraCharacteristics#CONTROL_AE_AVAILABLE_MODES android.control.aeAvailableModes}</p>
@@ -1093,6 +1094,7 @@ public final class CaptureRequest extends CameraMetadata<CaptureRequest.Key<?>>
* @see #CONTROL_AE_MODE_ON_AUTO_FLASH
* @see #CONTROL_AE_MODE_ON_ALWAYS_FLASH
* @see #CONTROL_AE_MODE_ON_AUTO_FLASH_REDEYE
+ * @see #CONTROL_AE_MODE_ON_EXTERNAL_FLASH
*/
@PublicKey
public static final Key<Integer> CONTROL_AE_MODE =
diff --git a/core/java/android/hardware/camera2/CaptureResult.java b/core/java/android/hardware/camera2/CaptureResult.java
index b6b0c907a8f9..237a92d3ca9f 100644
--- a/core/java/android/hardware/camera2/CaptureResult.java
+++ b/core/java/android/hardware/camera2/CaptureResult.java
@@ -691,6 +691,7 @@ public class CaptureResult extends CameraMetadata<CaptureResult.Key<?>> {
* <li>{@link #CONTROL_AE_MODE_ON_AUTO_FLASH ON_AUTO_FLASH}</li>
* <li>{@link #CONTROL_AE_MODE_ON_ALWAYS_FLASH ON_ALWAYS_FLASH}</li>
* <li>{@link #CONTROL_AE_MODE_ON_AUTO_FLASH_REDEYE ON_AUTO_FLASH_REDEYE}</li>
+ * <li>{@link #CONTROL_AE_MODE_ON_EXTERNAL_FLASH ON_EXTERNAL_FLASH}</li>
* </ul></p>
* <p><b>Available values for this device:</b><br>
* {@link CameraCharacteristics#CONTROL_AE_AVAILABLE_MODES android.control.aeAvailableModes}</p>
@@ -708,6 +709,7 @@ public class CaptureResult extends CameraMetadata<CaptureResult.Key<?>> {
* @see #CONTROL_AE_MODE_ON_AUTO_FLASH
* @see #CONTROL_AE_MODE_ON_ALWAYS_FLASH
* @see #CONTROL_AE_MODE_ON_AUTO_FLASH_REDEYE
+ * @see #CONTROL_AE_MODE_ON_EXTERNAL_FLASH
*/
@PublicKey
public static final Key<Integer> CONTROL_AE_MODE =
@@ -877,7 +879,7 @@ public class CaptureResult extends CameraMetadata<CaptureResult.Key<?>> {
* </tr>
* </tbody>
* </table>
- * <p>When {@link CaptureRequest#CONTROL_AE_MODE android.control.aeMode} is AE_MODE_ON_*:</p>
+ * <p>When {@link CaptureRequest#CONTROL_AE_MODE android.control.aeMode} is AE_MODE_ON*:</p>
* <table>
* <thead>
* <tr>
@@ -998,10 +1000,13 @@ public class CaptureResult extends CameraMetadata<CaptureResult.Key<?>> {
* </tr>
* </tbody>
* </table>
+ * <p>If the camera device supports AE external flash mode (ON_EXTERNAL_FLASH is included in
+ * {@link CameraCharacteristics#CONTROL_AE_AVAILABLE_MODES android.control.aeAvailableModes}), aeState must be FLASH_REQUIRED after the camera device
+ * finishes AE scan and it's too dark without flash.</p>
* <p>For the above table, the camera device may skip reporting any state changes that happen
* without application intervention (i.e. mode switch, trigger, locking). Any state that
* can be skipped in that manner is called a transient state.</p>
- * <p>For example, for above AE modes (AE_MODE_ON_*), in addition to the state transitions
+ * <p>For example, for above AE modes (AE_MODE_ON*), in addition to the state transitions
* listed in above table, it is also legal for the camera device to skip one or more
* transient states between two results. See below table for examples:</p>
* <table>
@@ -1072,6 +1077,7 @@ public class CaptureResult extends CameraMetadata<CaptureResult.Key<?>> {
* Present on all camera devices that report being at least {@link CameraCharacteristics#INFO_SUPPORTED_HARDWARE_LEVEL_LIMITED HARDWARE_LEVEL_LIMITED} devices in the
* {@link CameraCharacteristics#INFO_SUPPORTED_HARDWARE_LEVEL android.info.supportedHardwareLevel} key</p>
*
+ * @see CameraCharacteristics#CONTROL_AE_AVAILABLE_MODES
* @see CaptureRequest#CONTROL_AE_LOCK
* @see CaptureRequest#CONTROL_AE_MODE
* @see CaptureRequest#CONTROL_AE_PRECAPTURE_TRIGGER
diff --git a/core/java/android/hardware/radio/ProgramSelector.java b/core/java/android/hardware/radio/ProgramSelector.java
index 3556751f4af4..0cf7605c98a2 100644
--- a/core/java/android/hardware/radio/ProgramSelector.java
+++ b/core/java/android/hardware/radio/ProgramSelector.java
@@ -59,24 +59,56 @@ import java.util.stream.Stream;
*/
@SystemApi
public final class ProgramSelector implements Parcelable {
+ /** Invalid program type.
+ * @deprecated use {@link ProgramIdentifier} instead
+ */
+ @Deprecated
public static final int PROGRAM_TYPE_INVALID = 0;
- /** Analogue AM radio (with or without RDS). */
+ /** Analogue AM radio (with or without RDS).
+ * @deprecated use {@link ProgramIdentifier} instead
+ */
+ @Deprecated
public static final int PROGRAM_TYPE_AM = 1;
- /** analogue FM radio (with or without RDS). */
+ /** analogue FM radio (with or without RDS).
+ * @deprecated use {@link ProgramIdentifier} instead
+ */
+ @Deprecated
public static final int PROGRAM_TYPE_FM = 2;
- /** AM HD Radio. */
+ /** AM HD Radio.
+ * @deprecated use {@link ProgramIdentifier} instead
+ */
+ @Deprecated
public static final int PROGRAM_TYPE_AM_HD = 3;
- /** FM HD Radio. */
+ /** FM HD Radio.
+ * @deprecated use {@link ProgramIdentifier} instead
+ */
+ @Deprecated
public static final int PROGRAM_TYPE_FM_HD = 4;
- /** Digital audio broadcasting. */
+ /** Digital audio broadcasting.
+ * @deprecated use {@link ProgramIdentifier} instead
+ */
+ @Deprecated
public static final int PROGRAM_TYPE_DAB = 5;
- /** Digital Radio Mondiale. */
+ /** Digital Radio Mondiale.
+ * @deprecated use {@link ProgramIdentifier} instead
+ */
+ @Deprecated
public static final int PROGRAM_TYPE_DRMO = 6;
- /** SiriusXM Satellite Radio. */
+ /** SiriusXM Satellite Radio.
+ * @deprecated use {@link ProgramIdentifier} instead
+ */
+ @Deprecated
public static final int PROGRAM_TYPE_SXM = 7;
- /** Vendor-specific, not synced across devices. */
+ /** Vendor-specific, not synced across devices.
+ * @deprecated use {@link ProgramIdentifier} instead
+ */
+ @Deprecated
public static final int PROGRAM_TYPE_VENDOR_START = 1000;
+ /** @deprecated use {@link ProgramIdentifier} instead */
+ @Deprecated
public static final int PROGRAM_TYPE_VENDOR_END = 1999;
+ /** @deprecated use {@link ProgramIdentifier} instead */
+ @Deprecated
@IntDef(prefix = { "PROGRAM_TYPE_" }, value = {
PROGRAM_TYPE_INVALID,
PROGRAM_TYPE_AM,
@@ -112,18 +144,46 @@ public final class ProgramSelector implements Parcelable {
*
* The subchannel index is 0-based (where 0 is MPS and 1..7 are SPS),
* as opposed to HD Radio standard (where it's 1-based).
+ *
+ * @deprecated use IDENTIFIER_TYPE_HD_STATION_ID_EXT instead
*/
+ @Deprecated
public static final int IDENTIFIER_TYPE_HD_SUBCHANNEL = 4;
/**
- * 24bit compound primary identifier for DAB.
+ * 64bit additional identifier for HD Radio.
+ *
+ * Due to Station ID abuse, some HD_STATION_ID_EXT identifiers may be not
+ * globally unique. To provide a best-effort solution, a short version of
+ * station name may be carried as additional identifier and may be used
+ * by the tuner hardware to double-check tuning.
+ *
+ * The name is limited to the first 8 A-Z0-9 characters (lowercase letters
+ * must be converted to uppercase). Encoded in little-endian ASCII:
+ * the first character of the name is the LSB.
+ *
+ * For example: "Abc" is encoded as 0x434241.
+ */
+ public static final int IDENTIFIER_TYPE_HD_STATION_NAME = 10004;
+ /**
+ * @see {@link IDENTIFIER_TYPE_DAB_SID_EXT}
+ */
+ public static final int IDENTIFIER_TYPE_DAB_SIDECC = 5;
+ /**
+ * 28bit compound primary identifier for Digital Audio Broadcasting.
*
* Consists of (from the LSB):
* - 16bit: SId;
- * - 8bit: ECC code.
+ * - 8bit: ECC code;
+ * - 4bit: SCIdS.
+ *
+ * SCIdS (Service Component Identifier within the Service) value
+ * of 0 represents the main service, while 1 and above represents
+ * secondary services.
+ *
* The remaining bits should be set to zeros when writing on the chip side
* and ignored when read.
*/
- public static final int IDENTIFIER_TYPE_DAB_SIDECC = 5;
+ public static final int IDENTIFIER_TYPE_DAB_SID_EXT = IDENTIFIER_TYPE_DAB_SIDECC;
/** 16bit */
public static final int IDENTIFIER_TYPE_DAB_ENSEMBLE = 6;
/** 12bit */
@@ -134,7 +194,11 @@ public final class ProgramSelector implements Parcelable {
public static final int IDENTIFIER_TYPE_DRMO_SERVICE_ID = 9;
/** kHz */
public static final int IDENTIFIER_TYPE_DRMO_FREQUENCY = 10;
- /** 1: AM, 2:FM */
+ /**
+ * 1: AM, 2:FM
+ * @deprecated use {@link IDENTIFIER_TYPE_DRMO_FREQUENCY} instead
+ */
+ @Deprecated
public static final int IDENTIFIER_TYPE_DRMO_MODULATION = 11;
/** 32bit */
public static final int IDENTIFIER_TYPE_SXM_SERVICE_ID = 12;
@@ -148,14 +212,29 @@ public final class ProgramSelector implements Parcelable {
* type between VENDOR_START and VENDOR_END (eg. identifier type 1015 must
* not be used in any program type other than 1015).
*/
- public static final int IDENTIFIER_TYPE_VENDOR_PRIMARY_START = PROGRAM_TYPE_VENDOR_START;
- public static final int IDENTIFIER_TYPE_VENDOR_PRIMARY_END = PROGRAM_TYPE_VENDOR_END;
+ public static final int IDENTIFIER_TYPE_VENDOR_START = PROGRAM_TYPE_VENDOR_START;
+ /**
+ * @see {@link IDENTIFIER_TYPE_VENDOR_START}
+ */
+ public static final int IDENTIFIER_TYPE_VENDOR_END = PROGRAM_TYPE_VENDOR_END;
+ /**
+ * @deprecated use {@link IDENTIFIER_TYPE_VENDOR_START} instead
+ */
+ @Deprecated
+ public static final int IDENTIFIER_TYPE_VENDOR_PRIMARY_START = IDENTIFIER_TYPE_VENDOR_START;
+ /**
+ * @deprecated use {@link IDENTIFIER_TYPE_VENDOR_END} instead
+ */
+ @Deprecated
+ public static final int IDENTIFIER_TYPE_VENDOR_PRIMARY_END = IDENTIFIER_TYPE_VENDOR_END;
@IntDef(prefix = { "IDENTIFIER_TYPE_" }, value = {
IDENTIFIER_TYPE_INVALID,
IDENTIFIER_TYPE_AMFM_FREQUENCY,
IDENTIFIER_TYPE_RDS_PI,
IDENTIFIER_TYPE_HD_STATION_ID_EXT,
IDENTIFIER_TYPE_HD_SUBCHANNEL,
+ IDENTIFIER_TYPE_HD_STATION_NAME,
+ IDENTIFIER_TYPE_DAB_SID_EXT,
IDENTIFIER_TYPE_DAB_SIDECC,
IDENTIFIER_TYPE_DAB_ENSEMBLE,
IDENTIFIER_TYPE_DAB_SCID,
@@ -166,7 +245,7 @@ public final class ProgramSelector implements Parcelable {
IDENTIFIER_TYPE_SXM_SERVICE_ID,
IDENTIFIER_TYPE_SXM_CHANNEL,
})
- @IntRange(from = IDENTIFIER_TYPE_VENDOR_PRIMARY_START, to = IDENTIFIER_TYPE_VENDOR_PRIMARY_END)
+ @IntRange(from = IDENTIFIER_TYPE_VENDOR_START, to = IDENTIFIER_TYPE_VENDOR_END)
@Retention(RetentionPolicy.SOURCE)
public @interface IdentifierType {}
@@ -205,7 +284,9 @@ public final class ProgramSelector implements Parcelable {
* Type of a radio technology.
*
* @return program type.
+ * @deprecated use {@link getPrimaryId} instead
*/
+ @Deprecated
public @ProgramType int getProgramType() {
return mProgramType;
}
@@ -273,7 +354,10 @@ public final class ProgramSelector implements Parcelable {
* preserving elements order.
*
* @return an array of vendor identifiers, must not be modified.
+ * @deprecated for HAL 1.x compatibility;
+ * HAL 2.x uses standard primary/secondary lists for vendor IDs
*/
+ @Deprecated
public @NonNull long[] getVendorIds() {
return mVendorIds;
}
@@ -427,6 +511,10 @@ public final class ProgramSelector implements Parcelable {
private final long mValue;
public Identifier(@IdentifierType int type, long value) {
+ if (type == IDENTIFIER_TYPE_HD_STATION_NAME) {
+ // see getType
+ type = IDENTIFIER_TYPE_HD_SUBCHANNEL;
+ }
mType = type;
mValue = value;
}
@@ -437,6 +525,13 @@ public final class ProgramSelector implements Parcelable {
* @return type of an identifier.
*/
public @IdentifierType int getType() {
+ if (mType == IDENTIFIER_TYPE_HD_SUBCHANNEL && mValue > 10) {
+ /* HD_SUBCHANNEL and HD_STATION_NAME use the same identifier type, but they differ
+ * in possible values: sub channel is 0-7, station name is greater than ASCII space
+ * code (32).
+ */
+ return IDENTIFIER_TYPE_HD_STATION_NAME;
+ }
return mType;
}
diff --git a/core/java/android/net/INetworkPolicyListener.aidl b/core/java/android/net/INetworkPolicyListener.aidl
index 005dd6e16880..10667aecd128 100644
--- a/core/java/android/net/INetworkPolicyListener.aidl
+++ b/core/java/android/net/INetworkPolicyListener.aidl
@@ -18,10 +18,9 @@ package android.net;
/** {@hide} */
oneway interface INetworkPolicyListener {
-
void onUidRulesChanged(int uid, int uidRules);
void onMeteredIfacesChanged(in String[] meteredIfaces);
void onRestrictBackgroundChanged(boolean restrictBackground);
void onUidPoliciesChanged(int uid, int uidPolicies);
-
+ void onSubscriptionOverride(int subId, int overrideMask, int overrideValue);
}
diff --git a/core/java/android/net/INetworkPolicyManager.aidl b/core/java/android/net/INetworkPolicyManager.aidl
index 7e37432fb06a..476e2f43649f 100644
--- a/core/java/android/net/INetworkPolicyManager.aidl
+++ b/core/java/android/net/INetworkPolicyManager.aidl
@@ -71,6 +71,7 @@ interface INetworkPolicyManager {
SubscriptionPlan[] getSubscriptionPlans(int subId, String callingPackage);
void setSubscriptionPlans(int subId, in SubscriptionPlan[] plans, String callingPackage);
String getSubscriptionPlansOwner(int subId);
+ void setSubscriptionOverride(int subId, int overrideMask, int overrideValue, long timeoutMillis, String callingPackage);
void factoryReset(String subscriber);
diff --git a/core/java/android/net/INetworkStatsService.aidl b/core/java/android/net/INetworkStatsService.aidl
index 95e7f6031c72..90e3ffd550b4 100644
--- a/core/java/android/net/INetworkStatsService.aidl
+++ b/core/java/android/net/INetworkStatsService.aidl
@@ -18,6 +18,7 @@ package android.net;
import android.net.DataUsageRequest;
import android.net.INetworkStatsSession;
+import android.net.Network;
import android.net.NetworkStats;
import android.net.NetworkStatsHistory;
import android.net.NetworkTemplate;
@@ -53,7 +54,7 @@ interface INetworkStatsService {
void setUidForeground(int uid, boolean uidForeground);
/** Force update of ifaces. */
- void forceUpdateIfaces();
+ void forceUpdateIfaces(in Network[] defaultNetworks);
/** Force update of statistics. */
void forceUpdate();
diff --git a/core/java/android/net/IpSecManager.java b/core/java/android/net/IpSecManager.java
index 2cda58c99a61..f04f03f6b617 100644
--- a/core/java/android/net/IpSecManager.java
+++ b/core/java/android/net/IpSecManager.java
@@ -19,6 +19,7 @@ import static com.android.internal.util.Preconditions.checkNotNull;
import android.annotation.IntDef;
import android.annotation.NonNull;
+import android.annotation.SystemApi;
import android.annotation.SystemService;
import android.annotation.TestApi;
import android.content.Context;
@@ -625,6 +626,133 @@ public final class IpSecManager {
}
/**
+ * This class represents an IpSecTunnelInterface
+ *
+ * <p>IpSecTunnelInterface objects track tunnel interfaces that serve as
+ * local endpoints for IPsec tunnels.
+ *
+ * <p>Creating an IpSecTunnelInterface creates a device to which IpSecTransforms may be
+ * applied to provide IPsec security to packets sent through the tunnel. While a tunnel
+ * cannot be used in standalone mode within Android, the higher layers may use the tunnel
+ * to create Network objects which are accessible to the Android system.
+ * @hide
+ */
+ @SystemApi
+ public static final class IpSecTunnelInterface implements AutoCloseable {
+ private final IIpSecService mService;
+ private final InetAddress mRemoteAddress;
+ private final InetAddress mLocalAddress;
+ private final Network mUnderlyingNetwork;
+ private final CloseGuard mCloseGuard = CloseGuard.get();
+ private String mInterfaceName;
+ private int mResourceId = INVALID_RESOURCE_ID;
+
+ /** Get the underlying SPI held by this object. */
+ public String getInterfaceName() {
+ return mInterfaceName;
+ }
+
+ /**
+ * Add an address to the IpSecTunnelInterface
+ *
+ * <p>Add an address which may be used as the local inner address for
+ * tunneled traffic.
+ *
+ * @param address the local address for traffic inside the tunnel
+ * @throws IOException if the address could not be added
+ * @hide
+ */
+ public void addAddress(LinkAddress address) throws IOException {
+ }
+
+ /**
+ * Remove an address from the IpSecTunnelInterface
+ *
+ * <p>Remove an address which was previously added to the IpSecTunnelInterface
+ *
+ * @param address to be removed
+ * @throws IOException if the address could not be removed
+ * @hide
+ */
+ public void removeAddress(LinkAddress address) throws IOException {
+ }
+
+ private IpSecTunnelInterface(@NonNull IIpSecService service,
+ @NonNull InetAddress localAddress, @NonNull InetAddress remoteAddress,
+ @NonNull Network underlyingNetwork)
+ throws ResourceUnavailableException, IOException {
+ mService = service;
+ mLocalAddress = localAddress;
+ mRemoteAddress = remoteAddress;
+ mUnderlyingNetwork = underlyingNetwork;
+ // TODO: Call IpSecService
+ }
+
+ /**
+ * Delete an IpSecTunnelInterface
+ *
+ * <p>Calling close will deallocate the IpSecTunnelInterface and all of its system
+ * resources. Any packets bound for this interface either inbound or outbound will
+ * all be lost.
+ */
+ @Override
+ public void close() {
+ // try {
+ // TODO: Call IpSecService
+ mResourceId = INVALID_RESOURCE_ID;
+ // } catch (RemoteException e) {
+ // throw e.rethrowFromSystemServer();
+ // }
+ mCloseGuard.close();
+ }
+
+ /** Check that the Interface was closed properly. */
+ @Override
+ protected void finalize() throws Throwable {
+ if (mCloseGuard != null) {
+ mCloseGuard.warnIfOpen();
+ }
+ close();
+ }
+ }
+
+ /**
+ * Create a new IpSecTunnelInterface as a local endpoint for tunneled IPsec traffic.
+ *
+ * @param localAddress The local addres of the tunnel
+ * @param remoteAddress The local addres of the tunnel
+ * @param underlyingNetwork the {@link Network} that will carry traffic for this tunnel.
+ * This network should almost certainly be a network such as WiFi with an L2 address.
+ * @return a new {@link IpSecManager#IpSecTunnelInterface} with the specified properties
+ * @throws IOException indicating that the socket could not be opened or bound
+ * @throws ResourceUnavailableException indicating that too many encapsulation sockets are open
+ * @hide
+ */
+ @SystemApi
+ public IpSecTunnelInterface createIpSecTunnelInterface(@NonNull InetAddress localAddress,
+ @NonNull InetAddress remoteAddress, @NonNull Network underlyingNetwork)
+ throws ResourceUnavailableException, IOException {
+ return new IpSecTunnelInterface(mService, localAddress, remoteAddress, underlyingNetwork);
+ }
+
+ /**
+ * Apply a transform to the IpSecTunnelInterface
+ *
+ * @param tunnel The {@link IpSecManager#IpSecTunnelInterface} that will use the supplied
+ * transform.
+ * @param direction the direction, {@link DIRECTION_OUT} or {@link #DIRECTION_IN} in which
+ * the transform will be used.
+ * @param transform an {@link IpSecTransform} created in tunnel mode
+ * @throws IOException indicating that the transform could not be applied due to a lower
+ * layer failure.
+ * @hide
+ */
+ @SystemApi
+ void applyTunnelModeTransform(IpSecTunnelInterface tunnel, int direction,
+ IpSecTransform transform) throws IOException {
+ // TODO: call IpSecService
+ }
+ /**
* Construct an instance of IpSecManager within an application context.
*
* @param context the application context for this manager
diff --git a/core/java/android/net/IpSecTransform.java b/core/java/android/net/IpSecTransform.java
index 7b9b4830929d..be6026ff376e 100644
--- a/core/java/android/net/IpSecTransform.java
+++ b/core/java/android/net/IpSecTransform.java
@@ -300,21 +300,6 @@ public final class IpSecTransform implements AutoCloseable {
}
/**
- * Set the {@link Network} which will carry tunneled traffic.
- *
- * <p>Restricts the transformed traffic to a particular {@link Network}. This is required
- * for tunnel mode, otherwise tunneled traffic would be sent on the default network.
- *
- * @hide
- */
- @SystemApi
- public IpSecTransform.Builder setUnderlyingNetwork(@NonNull Network net) {
- Preconditions.checkNotNull(net);
- mConfig.setNetwork(net);
- return this;
- }
-
- /**
* Add UDP encapsulation to an IPv4 transform.
*
* <p>This allows IPsec traffic to pass through a NAT.
@@ -415,6 +400,7 @@ public final class IpSecTransform implements AutoCloseable {
* @throws IOException indicating other errors
* @hide
*/
+ @SystemApi
public IpSecTransform buildTunnelModeTransform(
@NonNull InetAddress sourceAddress,
@NonNull IpSecManager.SecurityParameterIndex spi)
diff --git a/core/java/android/net/NetworkIdentity.java b/core/java/android/net/NetworkIdentity.java
index d3b35998be13..fd118f340119 100644
--- a/core/java/android/net/NetworkIdentity.java
+++ b/core/java/android/net/NetworkIdentity.java
@@ -58,21 +58,24 @@ public class NetworkIdentity implements Comparable<NetworkIdentity> {
final String mNetworkId;
final boolean mRoaming;
final boolean mMetered;
+ final boolean mDefaultNetwork;
public NetworkIdentity(
int type, int subType, String subscriberId, String networkId, boolean roaming,
- boolean metered) {
+ boolean metered, boolean defaultNetwork) {
mType = type;
mSubType = COMBINE_SUBTYPE_ENABLED ? SUBTYPE_COMBINED : subType;
mSubscriberId = subscriberId;
mNetworkId = networkId;
mRoaming = roaming;
mMetered = metered;
+ mDefaultNetwork = defaultNetwork;
}
@Override
public int hashCode() {
- return Objects.hash(mType, mSubType, mSubscriberId, mNetworkId, mRoaming, mMetered);
+ return Objects.hash(mType, mSubType, mSubscriberId, mNetworkId, mRoaming, mMetered,
+ mDefaultNetwork);
}
@Override
@@ -82,7 +85,8 @@ public class NetworkIdentity implements Comparable<NetworkIdentity> {
return mType == ident.mType && mSubType == ident.mSubType && mRoaming == ident.mRoaming
&& Objects.equals(mSubscriberId, ident.mSubscriberId)
&& Objects.equals(mNetworkId, ident.mNetworkId)
- && mMetered == ident.mMetered;
+ && mMetered == ident.mMetered
+ && mDefaultNetwork == ident.mDefaultNetwork;
}
return false;
}
@@ -109,6 +113,7 @@ public class NetworkIdentity implements Comparable<NetworkIdentity> {
builder.append(", ROAMING");
}
builder.append(", metered=").append(mMetered);
+ builder.append(", defaultNetwork=").append(mDefaultNetwork);
return builder.append("}").toString();
}
@@ -153,6 +158,10 @@ public class NetworkIdentity implements Comparable<NetworkIdentity> {
return mMetered;
}
+ public boolean getDefaultNetwork() {
+ return mDefaultNetwork;
+ }
+
/**
* Scrub given IMSI on production builds.
*/
@@ -183,7 +192,8 @@ public class NetworkIdentity implements Comparable<NetworkIdentity> {
* Build a {@link NetworkIdentity} from the given {@link NetworkState},
* assuming that any mobile networks are using the current IMSI.
*/
- public static NetworkIdentity buildNetworkIdentity(Context context, NetworkState state) {
+ public static NetworkIdentity buildNetworkIdentity(Context context, NetworkState state,
+ boolean defaultNetwork) {
final int type = state.networkInfo.getType();
final int subType = state.networkInfo.getSubtype();
@@ -216,7 +226,8 @@ public class NetworkIdentity implements Comparable<NetworkIdentity> {
}
}
- return new NetworkIdentity(type, subType, subscriberId, networkId, roaming, metered);
+ return new NetworkIdentity(type, subType, subscriberId, networkId, roaming, metered,
+ defaultNetwork);
}
@Override
@@ -237,6 +248,9 @@ public class NetworkIdentity implements Comparable<NetworkIdentity> {
if (res == 0) {
res = Boolean.compare(mMetered, another.mMetered);
}
+ if (res == 0) {
+ res = Boolean.compare(mDefaultNetwork, another.mDefaultNetwork);
+ }
return res;
}
}
diff --git a/core/java/android/net/NetworkPolicyManager.java b/core/java/android/net/NetworkPolicyManager.java
index 9ef26a9f5a5b..2c5a021ec42a 100644
--- a/core/java/android/net/NetworkPolicyManager.java
+++ b/core/java/android/net/NetworkPolicyManager.java
@@ -113,6 +113,9 @@ public class NetworkPolicyManager {
*/
public static final String EXTRA_NETWORK_TEMPLATE = "android.net.NETWORK_TEMPLATE";
+ public static final int OVERRIDE_UNMETERED = 1 << 0;
+ public static final int OVERRIDE_CONGESTED = 1 << 1;
+
private final Context mContext;
private INetworkPolicyManager mService;
@@ -347,4 +350,13 @@ public class NetworkPolicyManager {
public static String resolveNetworkId(String ssid) {
return WifiInfo.removeDoubleQuotes(ssid);
}
+
+ /** {@hide} */
+ public static class Listener extends INetworkPolicyListener.Stub {
+ @Override public void onUidRulesChanged(int uid, int uidRules) { }
+ @Override public void onMeteredIfacesChanged(String[] meteredIfaces) { }
+ @Override public void onRestrictBackgroundChanged(boolean restrictBackground) { }
+ @Override public void onUidPoliciesChanged(int uid, int uidPolicies) { }
+ @Override public void onSubscriptionOverride(int subId, int overrideMask, int overrideValue) { }
+ }
}
diff --git a/core/java/android/net/NetworkStats.java b/core/java/android/net/NetworkStats.java
index 171adc054bbe..a85f80e38dfd 100644
--- a/core/java/android/net/NetworkStats.java
+++ b/core/java/android/net/NetworkStats.java
@@ -82,6 +82,13 @@ public class NetworkStats implements Parcelable {
/** {@link #roaming} value where roaming data is accounted. */
public static final int ROAMING_YES = 1;
+ /** {@link #onDefaultNetwork} value to account for all default network states. */
+ public static final int DEFAULT_NETWORK_ALL = -1;
+ /** {@link #onDefaultNetwork} value to account for usage while not the default network. */
+ public static final int DEFAULT_NETWORK_NO = 0;
+ /** {@link #onDefaultNetwork} value to account for usage while the default network. */
+ public static final int DEFAULT_NETWORK_YES = 1;
+
/** Denotes a request for stats at the interface level. */
public static final int STATS_PER_IFACE = 0;
/** Denotes a request for stats at the interface and UID level. */
@@ -102,6 +109,7 @@ public class NetworkStats implements Parcelable {
private int[] tag;
private int[] metered;
private int[] roaming;
+ private int[] defaultNetwork;
private long[] rxBytes;
private long[] rxPackets;
private long[] txBytes;
@@ -125,6 +133,12 @@ public class NetworkStats implements Parcelable {
* getSummary().
*/
public int roaming;
+ /**
+ * Note that this is only populated w/ the default value when read from /proc or written
+ * to disk. We merge in the correct value when reporting this value to clients of
+ * getSummary().
+ */
+ public int defaultNetwork;
public long rxBytes;
public long rxPackets;
public long txBytes;
@@ -142,18 +156,27 @@ public class NetworkStats implements Parcelable {
public Entry(String iface, int uid, int set, int tag, long rxBytes, long rxPackets,
long txBytes, long txPackets, long operations) {
- this(iface, uid, set, tag, METERED_NO, ROAMING_NO, rxBytes, rxPackets, txBytes,
- txPackets, operations);
+ this(iface, uid, set, tag, METERED_NO, ROAMING_NO, DEFAULT_NETWORK_NO,
+ rxBytes, rxPackets, txBytes, txPackets, operations);
}
+ // TODO: fix the the telephony code to pass DEFAULT_NETWORK_YES and remove this constructor.
public Entry(String iface, int uid, int set, int tag, int metered, int roaming,
long rxBytes, long rxPackets, long txBytes, long txPackets, long operations) {
+ this(iface, uid, set, tag, metered, roaming, DEFAULT_NETWORK_YES, rxBytes, rxPackets,
+ txBytes, txPackets, operations);
+ }
+
+ public Entry(String iface, int uid, int set, int tag, int metered, int roaming,
+ int defaultNetwork, long rxBytes, long rxPackets, long txBytes, long txPackets,
+ long operations) {
this.iface = iface;
this.uid = uid;
this.set = set;
this.tag = tag;
this.metered = metered;
this.roaming = roaming;
+ this.defaultNetwork = defaultNetwork;
this.rxBytes = rxBytes;
this.rxPackets = rxPackets;
this.txBytes = txBytes;
@@ -187,6 +210,7 @@ public class NetworkStats implements Parcelable {
builder.append(" tag=").append(tagToString(tag));
builder.append(" metered=").append(meteredToString(metered));
builder.append(" roaming=").append(roamingToString(roaming));
+ builder.append(" defaultNetwork=").append(defaultNetworkToString(defaultNetwork));
builder.append(" rxBytes=").append(rxBytes);
builder.append(" rxPackets=").append(rxPackets);
builder.append(" txBytes=").append(txBytes);
@@ -200,7 +224,8 @@ public class NetworkStats implements Parcelable {
if (o instanceof Entry) {
final Entry e = (Entry) o;
return uid == e.uid && set == e.set && tag == e.tag && metered == e.metered
- && roaming == e.roaming && rxBytes == e.rxBytes && rxPackets == e.rxPackets
+ && roaming == e.roaming && defaultNetwork == e.defaultNetwork
+ && rxBytes == e.rxBytes && rxPackets == e.rxPackets
&& txBytes == e.txBytes && txPackets == e.txPackets
&& operations == e.operations && iface.equals(e.iface);
}
@@ -209,7 +234,7 @@ public class NetworkStats implements Parcelable {
@Override
public int hashCode() {
- return Objects.hash(uid, set, tag, metered, roaming, iface);
+ return Objects.hash(uid, set, tag, metered, roaming, defaultNetwork, iface);
}
}
@@ -224,6 +249,7 @@ public class NetworkStats implements Parcelable {
this.tag = new int[initialSize];
this.metered = new int[initialSize];
this.roaming = new int[initialSize];
+ this.defaultNetwork = new int[initialSize];
this.rxBytes = new long[initialSize];
this.rxPackets = new long[initialSize];
this.txBytes = new long[initialSize];
@@ -238,6 +264,7 @@ public class NetworkStats implements Parcelable {
this.tag = EmptyArray.INT;
this.metered = EmptyArray.INT;
this.roaming = EmptyArray.INT;
+ this.defaultNetwork = EmptyArray.INT;
this.rxBytes = EmptyArray.LONG;
this.rxPackets = EmptyArray.LONG;
this.txBytes = EmptyArray.LONG;
@@ -256,6 +283,7 @@ public class NetworkStats implements Parcelable {
tag = parcel.createIntArray();
metered = parcel.createIntArray();
roaming = parcel.createIntArray();
+ defaultNetwork = parcel.createIntArray();
rxBytes = parcel.createLongArray();
rxPackets = parcel.createLongArray();
txBytes = parcel.createLongArray();
@@ -274,6 +302,7 @@ public class NetworkStats implements Parcelable {
dest.writeIntArray(tag);
dest.writeIntArray(metered);
dest.writeIntArray(roaming);
+ dest.writeIntArray(defaultNetwork);
dest.writeLongArray(rxBytes);
dest.writeLongArray(rxPackets);
dest.writeLongArray(txBytes);
@@ -308,10 +337,11 @@ public class NetworkStats implements Parcelable {
@VisibleForTesting
public NetworkStats addValues(String iface, int uid, int set, int tag, int metered, int roaming,
- long rxBytes, long rxPackets, long txBytes, long txPackets, long operations) {
+ int defaultNetwork, long rxBytes, long rxPackets, long txBytes, long txPackets,
+ long operations) {
return addValues(new Entry(
- iface, uid, set, tag, metered, roaming, rxBytes, rxPackets, txBytes, txPackets,
- operations));
+ iface, uid, set, tag, metered, roaming, defaultNetwork, rxBytes, rxPackets,
+ txBytes, txPackets, operations));
}
/**
@@ -327,6 +357,7 @@ public class NetworkStats implements Parcelable {
tag = Arrays.copyOf(tag, newLength);
metered = Arrays.copyOf(metered, newLength);
roaming = Arrays.copyOf(roaming, newLength);
+ defaultNetwork = Arrays.copyOf(defaultNetwork, newLength);
rxBytes = Arrays.copyOf(rxBytes, newLength);
rxPackets = Arrays.copyOf(rxPackets, newLength);
txBytes = Arrays.copyOf(txBytes, newLength);
@@ -341,6 +372,7 @@ public class NetworkStats implements Parcelable {
tag[size] = entry.tag;
metered[size] = entry.metered;
roaming[size] = entry.roaming;
+ defaultNetwork[size] = entry.defaultNetwork;
rxBytes[size] = entry.rxBytes;
rxPackets[size] = entry.rxPackets;
txBytes[size] = entry.txBytes;
@@ -362,6 +394,7 @@ public class NetworkStats implements Parcelable {
entry.tag = tag[i];
entry.metered = metered[i];
entry.roaming = roaming[i];
+ entry.defaultNetwork = defaultNetwork[i];
entry.rxBytes = rxBytes[i];
entry.rxPackets = rxPackets[i];
entry.txBytes = txBytes[i];
@@ -416,7 +449,7 @@ public class NetworkStats implements Parcelable {
*/
public NetworkStats combineValues(Entry entry) {
final int i = findIndex(entry.iface, entry.uid, entry.set, entry.tag, entry.metered,
- entry.roaming);
+ entry.roaming, entry.defaultNetwork);
if (i == -1) {
// only create new entry when positive contribution
addValues(entry);
@@ -444,10 +477,12 @@ public class NetworkStats implements Parcelable {
/**
* Find first stats index that matches the requested parameters.
*/
- public int findIndex(String iface, int uid, int set, int tag, int metered, int roaming) {
+ public int findIndex(String iface, int uid, int set, int tag, int metered, int roaming,
+ int defaultNetwork) {
for (int i = 0; i < size; i++) {
if (uid == this.uid[i] && set == this.set[i] && tag == this.tag[i]
&& metered == this.metered[i] && roaming == this.roaming[i]
+ && defaultNetwork == this.defaultNetwork[i]
&& Objects.equals(iface, this.iface[i])) {
return i;
}
@@ -461,7 +496,7 @@ public class NetworkStats implements Parcelable {
*/
@VisibleForTesting
public int findIndexHinted(String iface, int uid, int set, int tag, int metered, int roaming,
- int hintIndex) {
+ int defaultNetwork, int hintIndex) {
for (int offset = 0; offset < size; offset++) {
final int halfOffset = offset / 2;
@@ -475,6 +510,7 @@ public class NetworkStats implements Parcelable {
if (uid == this.uid[i] && set == this.set[i] && tag == this.tag[i]
&& metered == this.metered[i] && roaming == this.roaming[i]
+ && defaultNetwork == this.defaultNetwork[i]
&& Objects.equals(iface, this.iface[i])) {
return i;
}
@@ -489,7 +525,8 @@ public class NetworkStats implements Parcelable {
*/
public void spliceOperationsFrom(NetworkStats stats) {
for (int i = 0; i < size; i++) {
- final int j = stats.findIndex(iface[i], uid[i], set[i], tag[i], metered[i], roaming[i]);
+ final int j = stats.findIndex(iface[i], uid[i], set[i], tag[i], metered[i], roaming[i],
+ defaultNetwork[i]);
if (j == -1) {
operations[i] = 0;
} else {
@@ -581,6 +618,7 @@ public class NetworkStats implements Parcelable {
entry.tag = TAG_NONE;
entry.metered = METERED_ALL;
entry.roaming = ROAMING_ALL;
+ entry.defaultNetwork = DEFAULT_NETWORK_ALL;
entry.rxBytes = 0;
entry.rxPackets = 0;
entry.txBytes = 0;
@@ -677,6 +715,7 @@ public class NetworkStats implements Parcelable {
entry.tag = left.tag[i];
entry.metered = left.metered[i];
entry.roaming = left.roaming[i];
+ entry.defaultNetwork = left.defaultNetwork[i];
entry.rxBytes = left.rxBytes[i];
entry.rxPackets = left.rxPackets[i];
entry.txBytes = left.txBytes[i];
@@ -685,7 +724,7 @@ public class NetworkStats implements Parcelable {
// find remote row that matches, and subtract
final int j = right.findIndexHinted(entry.iface, entry.uid, entry.set, entry.tag,
- entry.metered, entry.roaming, i);
+ entry.metered, entry.roaming, entry.defaultNetwork, i);
if (j != -1) {
// Found matching row, subtract remote value.
entry.rxBytes -= right.rxBytes[j];
@@ -725,6 +764,7 @@ public class NetworkStats implements Parcelable {
entry.tag = TAG_NONE;
entry.metered = METERED_ALL;
entry.roaming = ROAMING_ALL;
+ entry.defaultNetwork = DEFAULT_NETWORK_ALL;
entry.operations = 0L;
for (int i = 0; i < size; i++) {
@@ -755,6 +795,7 @@ public class NetworkStats implements Parcelable {
entry.tag = TAG_NONE;
entry.metered = METERED_ALL;
entry.roaming = ROAMING_ALL;
+ entry.defaultNetwork = DEFAULT_NETWORK_ALL;
for (int i = 0; i < size; i++) {
// skip specific tags, since already counted in TAG_NONE
@@ -802,6 +843,7 @@ public class NetworkStats implements Parcelable {
pw.print(" tag="); pw.print(tagToString(tag[i]));
pw.print(" metered="); pw.print(meteredToString(metered[i]));
pw.print(" roaming="); pw.print(roamingToString(roaming[i]));
+ pw.print(" defaultNetwork="); pw.print(defaultNetworkToString(defaultNetwork[i]));
pw.print(" rxBytes="); pw.print(rxBytes[i]);
pw.print(" rxPackets="); pw.print(rxPackets[i]);
pw.print(" txBytes="); pw.print(txBytes[i]);
@@ -900,6 +942,22 @@ public class NetworkStats implements Parcelable {
}
}
+ /**
+ * Return text description of {@link #defaultNetwork} value.
+ */
+ public static String defaultNetworkToString(int defaultNetwork) {
+ switch (defaultNetwork) {
+ case DEFAULT_NETWORK_ALL:
+ return "ALL";
+ case DEFAULT_NETWORK_NO:
+ return "NO";
+ case DEFAULT_NETWORK_YES:
+ return "YES";
+ default:
+ return "UNKNOWN";
+ }
+ }
+
@Override
public String toString() {
final CharArrayWriter writer = new CharArrayWriter();
@@ -1055,6 +1113,7 @@ public class NetworkStats implements Parcelable {
tmpEntry.set = set[i];
tmpEntry.metered = metered[i];
tmpEntry.roaming = roaming[i];
+ tmpEntry.defaultNetwork = defaultNetwork[i];
combineValues(tmpEntry);
if (tag[i] == TAG_NONE) {
moved.add(tmpEntry);
@@ -1075,6 +1134,7 @@ public class NetworkStats implements Parcelable {
moved.iface = underlyingIface;
moved.metered = METERED_ALL;
moved.roaming = ROAMING_ALL;
+ moved.defaultNetwork = DEFAULT_NETWORK_ALL;
combineValues(moved);
// Caveat: if the vpn software uses tag, the total tagged traffic may be greater than
@@ -1085,13 +1145,13 @@ public class NetworkStats implements Parcelable {
// roaming data after applying these adjustments, by checking the NetworkIdentity of the
// underlying iface.
int idxVpnBackground = findIndex(underlyingIface, tunUid, SET_DEFAULT, TAG_NONE,
- METERED_NO, ROAMING_NO);
+ METERED_NO, ROAMING_NO, DEFAULT_NETWORK_NO);
if (idxVpnBackground != -1) {
tunSubtract(idxVpnBackground, this, moved);
}
int idxVpnForeground = findIndex(underlyingIface, tunUid, SET_FOREGROUND, TAG_NONE,
- METERED_NO, ROAMING_NO);
+ METERED_NO, ROAMING_NO, DEFAULT_NETWORK_NO);
if (idxVpnForeground != -1) {
tunSubtract(idxVpnForeground, this, moved);
}
diff --git a/core/java/android/os/BatteryStats.java b/core/java/android/os/BatteryStats.java
index dc271d8639d5..49879a8a84a7 100644
--- a/core/java/android/os/BatteryStats.java
+++ b/core/java/android/os/BatteryStats.java
@@ -35,6 +35,7 @@ import android.util.proto.ProtoOutputStream;
import android.view.Display;
import com.android.internal.annotations.VisibleForTesting;
+import com.android.internal.location.gnssmetrics.GnssMetrics;
import com.android.internal.os.BatterySipper;
import com.android.internal.os.BatteryStatsHelper;
@@ -683,6 +684,14 @@ public abstract class BatteryStats implements Parcelable {
public abstract long[] getCpuFreqTimes(int which);
public abstract long[] getScreenOffCpuFreqTimes(int which);
+ /**
+ * Returns cpu active time of an uid.
+ */
+ public abstract long getCpuActiveTime();
+ /**
+ * Returns cpu times of an uid on each cluster
+ */
+ public abstract long[] getCpuClusterTimes();
/**
* Returns cpu times of an uid at a particular process state.
@@ -1500,6 +1509,10 @@ public abstract class BatteryStats implements Parcelable {
public static final int STATE2_WIFI_SIGNAL_STRENGTH_SHIFT = 4;
public static final int STATE2_WIFI_SIGNAL_STRENGTH_MASK =
0x7 << STATE2_WIFI_SIGNAL_STRENGTH_SHIFT;
+ // Values for NUM_GPS_SIGNAL_QUALITY_LEVELS
+ public static final int STATE2_GPS_SIGNAL_QUALITY_SHIFT = 7;
+ public static final int STATE2_GPS_SIGNAL_QUALITY_MASK =
+ 0x1 << STATE2_GPS_SIGNAL_QUALITY_SHIFT;
public static final int STATE2_POWER_SAVE_FLAG = 1<<31;
public static final int STATE2_VIDEO_ON_FLAG = 1<<30;
@@ -2088,6 +2101,23 @@ public abstract class BatteryStats implements Parcelable {
*/
public abstract int getNumConnectivityChange(int which);
+
+ /**
+ * Returns the time in microseconds that the phone has been running with
+ * the given GPS signal quality level
+ *
+ * {@hide}
+ */
+ public abstract long getGpsSignalQualityTime(int strengthBin,
+ long elapsedRealtimeUs, int which);
+
+ /**
+ * Returns the GPS battery drain in mA-ms
+ *
+ * {@hide}
+ */
+ public abstract long getGpsBatteryDrainMaMs();
+
/**
* Returns the time in microseconds that the phone has been on while the device was
* running on battery.
@@ -2312,6 +2342,9 @@ public abstract class BatteryStats implements Parcelable {
WIFI_SUPPL_STATE_NAMES, WIFI_SUPPL_STATE_SHORT_NAMES),
new BitDescription(HistoryItem.STATE2_CAMERA_FLAG, "camera", "ca"),
new BitDescription(HistoryItem.STATE2_BLUETOOTH_SCAN_FLAG, "ble_scan", "bles"),
+ new BitDescription(HistoryItem.STATE2_GPS_SIGNAL_QUALITY_MASK,
+ HistoryItem.STATE2_GPS_SIGNAL_QUALITY_SHIFT, "gps_signal_quality", "Gss",
+ new String[] { "poor", "good"}, new String[] { "poor", "good"}),
};
public static final String[] HISTORY_EVENT_NAMES = new String[] {
@@ -4732,6 +4765,43 @@ public abstract class BatteryStats implements Parcelable {
pw.print(prefix);
sb.setLength(0);
sb.append(prefix);
+ sb.append(" GPS Statistics:");
+ pw.println(sb.toString());
+
+ sb.setLength(0);
+ sb.append(prefix);
+ sb.append(" GPS signal quality (Top 4 Average CN0):");
+ final String[] gpsSignalQualityDescription = new String[]{
+ "poor (less than 20 dBHz): ",
+ "good (greater than 20 dBHz): "};
+ final int numGpsSignalQualityBins = Math.min(GnssMetrics.NUM_GPS_SIGNAL_QUALITY_LEVELS,
+ gpsSignalQualityDescription.length);
+ for (int i=0; i<numGpsSignalQualityBins; i++) {
+ final long time = getGpsSignalQualityTime(i, rawRealtime, which);
+ sb.append("\n ");
+ sb.append(prefix);
+ sb.append(" ");
+ sb.append(gpsSignalQualityDescription[i]);
+ formatTimeMs(sb, time/1000);
+ sb.append("(");
+ sb.append(formatRatioLocked(time, whichBatteryRealtime));
+ sb.append(") ");
+ }
+ pw.println(sb.toString());
+
+ final long gpsBatteryDrainMaMs = getGpsBatteryDrainMaMs();
+ if (gpsBatteryDrainMaMs > 0) {
+ pw.print(prefix);
+ sb.setLength(0);
+ sb.append(prefix);
+ sb.append(" Battery Drain (mAh): ");
+ sb.append(Double.toString(((double) gpsBatteryDrainMaMs)/(3600 * 1000)));
+ pw.println(sb.toString());
+ }
+
+ pw.print(prefix);
+ sb.setLength(0);
+ sb.append(prefix);
sb.append(" CONNECTIVITY POWER SUMMARY END");
pw.println(sb.toString());
pw.println("");
diff --git a/core/java/android/os/IPermissionController.aidl b/core/java/android/os/IPermissionController.aidl
index 5e8590af11f1..3de953a2dfbe 100644
--- a/core/java/android/os/IPermissionController.aidl
+++ b/core/java/android/os/IPermissionController.aidl
@@ -22,4 +22,5 @@ interface IPermissionController {
boolean checkPermission(String permission, int pid, int uid);
String[] getPackagesForUid(int uid);
boolean isRuntimePermission(String permission);
+ int getPackageUid(String packageName, int flags);
}
diff --git a/core/java/android/os/Process.java b/core/java/android/os/Process.java
index e6cf5e6a6cbf..7654e9b6ee22 100644
--- a/core/java/android/os/Process.java
+++ b/core/java/android/os/Process.java
@@ -151,6 +151,12 @@ public class Process {
*/
public static final int OTA_UPDATE_UID = 1061;
+ /**
+ * Defines the UID used for incidentd.
+ * @hide
+ */
+ public static final int INCIDENTD_UID = 1067;
+
/** {@hide} */
public static final int NOBODY_UID = 9999;
diff --git a/core/java/android/os/RecoverySystem.java b/core/java/android/os/RecoverySystem.java
index 673a8ba661b6..57db9d19f42d 100644
--- a/core/java/android/os/RecoverySystem.java
+++ b/core/java/android/os/RecoverySystem.java
@@ -61,6 +61,7 @@ import java.util.HashSet;
import java.util.Locale;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit;
+import java.util.concurrent.atomic.AtomicBoolean;
import java.util.zip.ZipEntry;
import java.util.zip.ZipFile;
import java.util.zip.ZipInputStream;
@@ -101,6 +102,9 @@ public class RecoverySystem {
private static final String ACTION_EUICC_FACTORY_RESET =
"com.android.internal.action.EUICC_FACTORY_RESET";
+ /** used in {@link #wipeEuiccData} as package name of callback intent */
+ private static final String PACKAGE_NAME_WIPING_EUICC_DATA_CALLBACK = "android";
+
/**
* The recovery image uses this file to identify the location (i.e. blocks)
* of an OTA package on the /data partition. The block map file is
@@ -751,7 +755,7 @@ public class RecoverySystem {
// Block until the ordered broadcast has completed.
condition.block();
- wipeEuiccData(context, wipeEuicc);
+ wipeEuiccData(context, wipeEuicc, PACKAGE_NAME_WIPING_EUICC_DATA_CALLBACK);
String shutdownArg = null;
if (shutdown) {
@@ -767,19 +771,29 @@ public class RecoverySystem {
bootCommand(context, shutdownArg, "--wipe_data", reasonArg, localeArg);
}
- private static void wipeEuiccData(Context context, final boolean isWipeEuicc) {
+ /**
+ * Returns whether wipe Euicc data successfully or not.
+ *
+ * @param isWipeEuicc whether we want to wipe Euicc data or not
+ * @param packageName the package name of the caller app.
+ *
+ * @hide
+ */
+ public static boolean wipeEuiccData(
+ Context context, final boolean isWipeEuicc, final String packageName) {
ContentResolver cr = context.getContentResolver();
if (Settings.Global.getInt(cr, Settings.Global.EUICC_PROVISIONED, 0) == 0) {
// If the eUICC isn't provisioned, there's no reason to either wipe or retain profiles,
// as there's nothing to wipe nor retain.
Log.d(TAG, "Skipping eUICC wipe/retain as it is not provisioned");
- return;
+ return true;
}
EuiccManager euiccManager = (EuiccManager) context.getSystemService(
Context.EUICC_SERVICE);
if (euiccManager != null && euiccManager.isEnabled()) {
CountDownLatch euiccFactoryResetLatch = new CountDownLatch(1);
+ final AtomicBoolean wipingSucceeded = new AtomicBoolean(false);
BroadcastReceiver euiccWipeFinishReceiver = new BroadcastReceiver() {
@Override
@@ -801,6 +815,7 @@ public class RecoverySystem {
} else {
Log.d(TAG, "Successfully retained euicc data.");
}
+ wipingSucceeded.set(true /* newValue */);
}
euiccFactoryResetLatch.countDown();
}
@@ -808,7 +823,7 @@ public class RecoverySystem {
};
Intent intent = new Intent(ACTION_EUICC_FACTORY_RESET);
- intent.setPackage("android");
+ intent.setPackage(packageName);
PendingIntent callbackIntent = PendingIntent.getBroadcastAsUser(
context, 0, intent, PendingIntent.FLAG_UPDATE_CURRENT, UserHandle.SYSTEM);
IntentFilter filterConsent = new IntentFilter();
@@ -839,8 +854,8 @@ public class RecoverySystem {
} else {
Log.e(TAG, "Timeout retaining eUICC data.");
}
+ return false;
}
- context.getApplicationContext().unregisterReceiver(euiccWipeFinishReceiver);
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
if (isWipeEuicc) {
@@ -848,8 +863,13 @@ public class RecoverySystem {
} else {
Log.e(TAG, "Retaining eUICC data interrupted", e);
}
+ return false;
+ } finally {
+ context.getApplicationContext().unregisterReceiver(euiccWipeFinishReceiver);
}
+ return wipingSucceeded.get();
}
+ return false;
}
/** {@hide} */
diff --git a/core/java/android/os/connectivity/GpsBatteryStats.aidl b/core/java/android/os/connectivity/GpsBatteryStats.aidl
new file mode 100644
index 000000000000..7b96d1a8e062
--- /dev/null
+++ b/core/java/android/os/connectivity/GpsBatteryStats.aidl
@@ -0,0 +1,20 @@
+/*
+ * 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.connectivity;
+
+/** {@hide} */
+parcelable GpsBatteryStats; \ No newline at end of file
diff --git a/core/java/android/os/connectivity/GpsBatteryStats.java b/core/java/android/os/connectivity/GpsBatteryStats.java
new file mode 100644
index 000000000000..f2ac5ef6d40b
--- /dev/null
+++ b/core/java/android/os/connectivity/GpsBatteryStats.java
@@ -0,0 +1,108 @@
+/*
+ * 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.connectivity;
+
+import android.os.Parcel;
+import android.os.Parcelable;
+
+import com.android.internal.location.gnssmetrics.GnssMetrics;
+
+import java.util.Arrays;
+
+/**
+ * API for GPS power stats
+ *
+ * @hide
+ */
+public final class GpsBatteryStats implements Parcelable {
+
+ private long mLoggingDurationMs;
+ private long mEnergyConsumedMaMs;
+ private long[] mTimeInGpsSignalQualityLevel;
+
+ public static final Parcelable.Creator<GpsBatteryStats> CREATOR = new
+ Parcelable.Creator<GpsBatteryStats>() {
+ public GpsBatteryStats createFromParcel(Parcel in) {
+ return new GpsBatteryStats(in);
+ }
+
+ public GpsBatteryStats[] newArray(int size) {
+ return new GpsBatteryStats[size];
+ }
+ };
+
+ public GpsBatteryStats() {
+ initialize();
+ }
+
+ @Override
+ public void writeToParcel(Parcel out, int flags) {
+ out.writeLong(mLoggingDurationMs);
+ out.writeLong(mEnergyConsumedMaMs);
+ out.writeLongArray(mTimeInGpsSignalQualityLevel);
+ }
+
+ public void readFromParcel(Parcel in) {
+ mLoggingDurationMs = in.readLong();
+ mEnergyConsumedMaMs = in.readLong();
+ in.readLongArray(mTimeInGpsSignalQualityLevel);
+ }
+
+ public long getLoggingDurationMs() {
+ return mLoggingDurationMs;
+ }
+
+ public long getEnergyConsumedMaMs() {
+ return mEnergyConsumedMaMs;
+ }
+
+ public long[] getTimeInGpsSignalQualityLevel() {
+ return mTimeInGpsSignalQualityLevel;
+ }
+
+ public void setLoggingDurationMs(long t) {
+ mLoggingDurationMs = t;
+ return;
+ }
+
+ public void setEnergyConsumedMaMs(long e) {
+ mEnergyConsumedMaMs = e;
+ return;
+ }
+
+ public void setTimeInGpsSignalQualityLevel(long[] t) {
+ mTimeInGpsSignalQualityLevel = Arrays.copyOfRange(t, 0,
+ Math.min(t.length, GnssMetrics.NUM_GPS_SIGNAL_QUALITY_LEVELS));
+ return;
+ }
+
+ @Override
+ public int describeContents() {
+ return 0;
+ }
+
+ private GpsBatteryStats(Parcel in) {
+ initialize();
+ readFromParcel(in);
+ }
+
+ private void initialize() {
+ mLoggingDurationMs = 0;
+ mEnergyConsumedMaMs = 0;
+ mTimeInGpsSignalQualityLevel = new long[GnssMetrics.NUM_GPS_SIGNAL_QUALITY_LEVELS];
+ return;
+ }
+} \ No newline at end of file
diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java
index 956e8f624b17..b2cc18b94641 100644
--- a/core/java/android/provider/Settings.java
+++ b/core/java/android/provider/Settings.java
@@ -16,6 +16,16 @@
package android.provider;
+import static android.provider.SettingsValidators.ANY_INTEGER_VALIDATOR;
+import static android.provider.SettingsValidators.ANY_STRING_VALIDATOR;
+import static android.provider.SettingsValidators.BOOLEAN_VALIDATOR;
+import static android.provider.SettingsValidators.COMPONENT_NAME_VALIDATOR;
+import static android.provider.SettingsValidators.LENIENT_IP_ADDRESS_VALIDATOR;
+import static android.provider.SettingsValidators.LOCALE_VALIDATOR;
+import static android.provider.SettingsValidators.NON_NEGATIVE_INTEGER_VALIDATOR;
+import static android.provider.SettingsValidators.PACKAGE_NAME_VALIDATOR;
+import static android.provider.SettingsValidators.URI_VALIDATOR;
+
import android.Manifest;
import android.annotation.IntDef;
import android.annotation.IntRange;
@@ -65,6 +75,8 @@ import android.os.RemoteException;
import android.os.ResultReceiver;
import android.os.ServiceManager;
import android.os.UserHandle;
+import android.provider.SettingsValidators;
+import android.provider.SettingsValidators.Validator;
import android.speech.tts.TextToSpeech;
import android.telephony.SubscriptionManager;
import android.text.TextUtils;
@@ -76,7 +88,6 @@ import android.util.MemoryIntArray;
import android.util.StatsLog;
import com.android.internal.annotations.GuardedBy;
-import com.android.internal.util.ArrayUtils;
import com.android.internal.widget.ILockSettings;
import java.io.IOException;
@@ -2119,11 +2130,6 @@ public final class Settings {
private static final float DEFAULT_FONT_SCALE = 1.0f;
- /** @hide */
- public static interface Validator {
- public boolean validate(String value);
- }
-
/**
* The content:// style URL for this table
*/
@@ -2228,41 +2234,6 @@ public final class Settings {
MOVED_TO_GLOBAL.add(Settings.Global.CERT_PIN_UPDATE_METADATA_URL);
}
- private static final Validator sBooleanValidator =
- new DiscreteValueValidator(new String[] {"0", "1"});
-
- private static final Validator sNonNegativeIntegerValidator = new Validator() {
- @Override
- public boolean validate(String value) {
- try {
- return Integer.parseInt(value) >= 0;
- } catch (NumberFormatException e) {
- return false;
- }
- }
- };
-
- private static final Validator sUriValidator = new Validator() {
- @Override
- public boolean validate(String value) {
- try {
- Uri.decode(value);
- return true;
- } catch (IllegalArgumentException e) {
- return false;
- }
- }
- };
-
- private static final Validator sLenientIpAddressValidator = new Validator() {
- private static final int MAX_IPV6_LENGTH = 45;
-
- @Override
- public boolean validate(String value) {
- return value.length() <= MAX_IPV6_LENGTH;
- }
- };
-
/** @hide */
public static void getMovedToGlobalSettings(Set<String> outKeySet) {
outKeySet.addAll(MOVED_TO_GLOBAL);
@@ -2730,64 +2701,35 @@ public final class Settings {
putIntForUser(cr, SHOW_GTALK_SERVICE_STATUS, flag ? 1 : 0, userHandle);
}
- private static final class DiscreteValueValidator implements Validator {
- private final String[] mValues;
-
- public DiscreteValueValidator(String[] values) {
- mValues = values;
- }
-
- @Override
- public boolean validate(String value) {
- return ArrayUtils.contains(mValues, value);
- }
- }
-
- private static final class InclusiveIntegerRangeValidator implements Validator {
- private final int mMin;
- private final int mMax;
-
- public InclusiveIntegerRangeValidator(int min, int max) {
- mMin = min;
- mMax = max;
- }
-
- @Override
- public boolean validate(String value) {
- try {
- final int intValue = Integer.parseInt(value);
- return intValue >= mMin && intValue <= mMax;
- } catch (NumberFormatException e) {
- return false;
- }
- }
- }
-
- private static final class InclusiveFloatRangeValidator implements Validator {
- private final float mMin;
- private final float mMax;
-
- public InclusiveFloatRangeValidator(float min, float max) {
- mMin = min;
- mMax = max;
- }
+ /**
+ * @deprecated Use {@link android.provider.Settings.Global#STAY_ON_WHILE_PLUGGED_IN} instead
+ */
+ @Deprecated
+ public static final String STAY_ON_WHILE_PLUGGED_IN = Global.STAY_ON_WHILE_PLUGGED_IN;
+ private static final Validator STAY_ON_WHILE_PLUGGED_IN_VALIDATOR = new Validator() {
@Override
public boolean validate(String value) {
try {
- final float floatValue = Float.parseFloat(value);
- return floatValue >= mMin && floatValue <= mMax;
+ int val = Integer.parseInt(value);
+ return (val == 0)
+ || (val == BatteryManager.BATTERY_PLUGGED_AC)
+ || (val == BatteryManager.BATTERY_PLUGGED_USB)
+ || (val == BatteryManager.BATTERY_PLUGGED_WIRELESS)
+ || (val == (BatteryManager.BATTERY_PLUGGED_AC
+ | BatteryManager.BATTERY_PLUGGED_USB))
+ || (val == (BatteryManager.BATTERY_PLUGGED_AC
+ | BatteryManager.BATTERY_PLUGGED_WIRELESS))
+ || (val == (BatteryManager.BATTERY_PLUGGED_USB
+ | BatteryManager.BATTERY_PLUGGED_WIRELESS))
+ || (val == (BatteryManager.BATTERY_PLUGGED_AC
+ | BatteryManager.BATTERY_PLUGGED_USB
+ | BatteryManager.BATTERY_PLUGGED_WIRELESS));
} catch (NumberFormatException e) {
return false;
}
}
- }
-
- /**
- * @deprecated Use {@link android.provider.Settings.Global#STAY_ON_WHILE_PLUGGED_IN} instead
- */
- @Deprecated
- public static final String STAY_ON_WHILE_PLUGGED_IN = Global.STAY_ON_WHILE_PLUGGED_IN;
+ };
/**
* What happens when the user presses the end call button if they're not
@@ -2802,7 +2744,7 @@ public final class Settings {
public static final String END_BUTTON_BEHAVIOR = "end_button_behavior";
private static final Validator END_BUTTON_BEHAVIOR_VALIDATOR =
- new InclusiveIntegerRangeValidator(0, 3);
+ new SettingsValidators.InclusiveIntegerRangeValidator(0, 3);
/**
* END_BUTTON_BEHAVIOR value for "go home".
@@ -2828,7 +2770,7 @@ public final class Settings {
*/
public static final String ADVANCED_SETTINGS = "advanced_settings";
- private static final Validator ADVANCED_SETTINGS_VALIDATOR = sBooleanValidator;
+ private static final Validator ADVANCED_SETTINGS_VALIDATOR = BOOLEAN_VALIDATOR;
/**
* ADVANCED_SETTINGS default value.
@@ -2929,7 +2871,7 @@ public final class Settings {
@Deprecated
public static final String WIFI_USE_STATIC_IP = "wifi_use_static_ip";
- private static final Validator WIFI_USE_STATIC_IP_VALIDATOR = sBooleanValidator;
+ private static final Validator WIFI_USE_STATIC_IP_VALIDATOR = BOOLEAN_VALIDATOR;
/**
* The static IP address.
@@ -2941,7 +2883,7 @@ public final class Settings {
@Deprecated
public static final String WIFI_STATIC_IP = "wifi_static_ip";
- private static final Validator WIFI_STATIC_IP_VALIDATOR = sLenientIpAddressValidator;
+ private static final Validator WIFI_STATIC_IP_VALIDATOR = LENIENT_IP_ADDRESS_VALIDATOR;
/**
* If using static IP, the gateway's IP address.
@@ -2953,7 +2895,7 @@ public final class Settings {
@Deprecated
public static final String WIFI_STATIC_GATEWAY = "wifi_static_gateway";
- private static final Validator WIFI_STATIC_GATEWAY_VALIDATOR = sLenientIpAddressValidator;
+ private static final Validator WIFI_STATIC_GATEWAY_VALIDATOR = LENIENT_IP_ADDRESS_VALIDATOR;
/**
* If using static IP, the net mask.
@@ -2965,7 +2907,7 @@ public final class Settings {
@Deprecated
public static final String WIFI_STATIC_NETMASK = "wifi_static_netmask";
- private static final Validator WIFI_STATIC_NETMASK_VALIDATOR = sLenientIpAddressValidator;
+ private static final Validator WIFI_STATIC_NETMASK_VALIDATOR = LENIENT_IP_ADDRESS_VALIDATOR;
/**
* If using static IP, the primary DNS's IP address.
@@ -2977,7 +2919,7 @@ public final class Settings {
@Deprecated
public static final String WIFI_STATIC_DNS1 = "wifi_static_dns1";
- private static final Validator WIFI_STATIC_DNS1_VALIDATOR = sLenientIpAddressValidator;
+ private static final Validator WIFI_STATIC_DNS1_VALIDATOR = LENIENT_IP_ADDRESS_VALIDATOR;
/**
* If using static IP, the secondary DNS's IP address.
@@ -2989,7 +2931,7 @@ public final class Settings {
@Deprecated
public static final String WIFI_STATIC_DNS2 = "wifi_static_dns2";
- private static final Validator WIFI_STATIC_DNS2_VALIDATOR = sLenientIpAddressValidator;
+ private static final Validator WIFI_STATIC_DNS2_VALIDATOR = LENIENT_IP_ADDRESS_VALIDATOR;
/**
* Determines whether remote devices may discover and/or connect to
@@ -3003,7 +2945,7 @@ public final class Settings {
"bluetooth_discoverability";
private static final Validator BLUETOOTH_DISCOVERABILITY_VALIDATOR =
- new InclusiveIntegerRangeValidator(0, 2);
+ new SettingsValidators.InclusiveIntegerRangeValidator(0, 2);
/**
* Bluetooth discoverability timeout. If this value is nonzero, then
@@ -3014,7 +2956,7 @@ public final class Settings {
"bluetooth_discoverability_timeout";
private static final Validator BLUETOOTH_DISCOVERABILITY_TIMEOUT_VALIDATOR =
- sNonNegativeIntegerValidator;
+ NON_NEGATIVE_INTEGER_VALIDATOR;
/**
* @deprecated Use {@link android.provider.Settings.Secure#LOCK_PATTERN_ENABLED}
@@ -3110,7 +3052,7 @@ public final class Settings {
@Deprecated
public static final String DIM_SCREEN = "dim_screen";
- private static final Validator DIM_SCREEN_VALIDATOR = sBooleanValidator;
+ private static final Validator DIM_SCREEN_VALIDATOR = BOOLEAN_VALIDATOR;
/**
* The display color mode.
@@ -3130,7 +3072,8 @@ public final class Settings {
*/
public static final String SCREEN_OFF_TIMEOUT = "screen_off_timeout";
- private static final Validator SCREEN_OFF_TIMEOUT_VALIDATOR = sNonNegativeIntegerValidator;
+ private static final Validator SCREEN_OFF_TIMEOUT_VALIDATOR =
+ NON_NEGATIVE_INTEGER_VALIDATOR;
/**
* The screen backlight brightness between 0 and 255.
@@ -3138,7 +3081,7 @@ public final class Settings {
public static final String SCREEN_BRIGHTNESS = "screen_brightness";
private static final Validator SCREEN_BRIGHTNESS_VALIDATOR =
- new InclusiveIntegerRangeValidator(0, 255);
+ new SettingsValidators.InclusiveIntegerRangeValidator(0, 255);
/**
* The screen backlight brightness between 0 and 255.
@@ -3147,14 +3090,14 @@ public final class Settings {
public static final String SCREEN_BRIGHTNESS_FOR_VR = "screen_brightness_for_vr";
private static final Validator SCREEN_BRIGHTNESS_FOR_VR_VALIDATOR =
- new InclusiveIntegerRangeValidator(0, 255);
+ new SettingsValidators.InclusiveIntegerRangeValidator(0, 255);
/**
* Control whether to enable automatic brightness mode.
*/
public static final String SCREEN_BRIGHTNESS_MODE = "screen_brightness_mode";
- private static final Validator SCREEN_BRIGHTNESS_MODE_VALIDATOR = sBooleanValidator;
+ private static final Validator SCREEN_BRIGHTNESS_MODE_VALIDATOR = BOOLEAN_VALIDATOR;
/**
* Adjustment to auto-brightness to make it generally more (>0.0 <1.0)
@@ -3164,7 +3107,7 @@ public final class Settings {
public static final String SCREEN_AUTO_BRIGHTNESS_ADJ = "screen_auto_brightness_adj";
private static final Validator SCREEN_AUTO_BRIGHTNESS_ADJ_VALIDATOR =
- new InclusiveFloatRangeValidator(-1, 1);
+ new SettingsValidators.InclusiveFloatRangeValidator(-1, 1);
/**
* SCREEN_BRIGHTNESS_MODE value for manual mode.
@@ -3203,7 +3146,7 @@ public final class Settings {
public static final String MODE_RINGER_STREAMS_AFFECTED = "mode_ringer_streams_affected";
private static final Validator MODE_RINGER_STREAMS_AFFECTED_VALIDATOR =
- sNonNegativeIntegerValidator;
+ NON_NEGATIVE_INTEGER_VALIDATOR;
/**
* Determines which streams are affected by mute. The
@@ -3213,7 +3156,7 @@ public final class Settings {
public static final String MUTE_STREAMS_AFFECTED = "mute_streams_affected";
private static final Validator MUTE_STREAMS_AFFECTED_VALIDATOR =
- sNonNegativeIntegerValidator;
+ NON_NEGATIVE_INTEGER_VALIDATOR;
/**
* Whether vibrate is on for different events. This is used internally,
@@ -3221,7 +3164,7 @@ public final class Settings {
*/
public static final String VIBRATE_ON = "vibrate_on";
- private static final Validator VIBRATE_ON_VALIDATOR = sBooleanValidator;
+ private static final Validator VIBRATE_ON_VALIDATOR = BOOLEAN_VALIDATOR;
/**
* If 1, redirects the system vibrator to all currently attached input devices
@@ -3237,7 +3180,7 @@ public final class Settings {
*/
public static final String VIBRATE_INPUT_DEVICES = "vibrate_input_devices";
- private static final Validator VIBRATE_INPUT_DEVICES_VALIDATOR = sBooleanValidator;
+ private static final Validator VIBRATE_INPUT_DEVICES_VALIDATOR = BOOLEAN_VALIDATOR;
/**
* Ringer volume. This is used internally, changing this value will not
@@ -3316,7 +3259,7 @@ public final class Settings {
*/
public static final String MASTER_MONO = "master_mono";
- private static final Validator MASTER_MONO_VALIDATOR = sBooleanValidator;
+ private static final Validator MASTER_MONO_VALIDATOR = BOOLEAN_VALIDATOR;
/**
* Whether the notifications should use the ring volume (value of 1) or
@@ -3336,7 +3279,7 @@ public final class Settings {
public static final String NOTIFICATIONS_USE_RING_VOLUME =
"notifications_use_ring_volume";
- private static final Validator NOTIFICATIONS_USE_RING_VOLUME_VALIDATOR = sBooleanValidator;
+ private static final Validator NOTIFICATIONS_USE_RING_VOLUME_VALIDATOR = BOOLEAN_VALIDATOR;
/**
* Whether silent mode should allow vibration feedback. This is used
@@ -3352,7 +3295,7 @@ public final class Settings {
*/
public static final String VIBRATE_IN_SILENT = "vibrate_in_silent";
- private static final Validator VIBRATE_IN_SILENT_VALIDATOR = sBooleanValidator;
+ private static final Validator VIBRATE_IN_SILENT_VALIDATOR = BOOLEAN_VALIDATOR;
/**
* The mapping of stream type (integer) to its setting.
@@ -3400,7 +3343,7 @@ public final class Settings {
*/
public static final String RINGTONE = "ringtone";
- private static final Validator RINGTONE_VALIDATOR = sUriValidator;
+ private static final Validator RINGTONE_VALIDATOR = URI_VALIDATOR;
/**
* A {@link Uri} that will point to the current default ringtone at any
@@ -3425,7 +3368,7 @@ public final class Settings {
*/
public static final String NOTIFICATION_SOUND = "notification_sound";
- private static final Validator NOTIFICATION_SOUND_VALIDATOR = sUriValidator;
+ private static final Validator NOTIFICATION_SOUND_VALIDATOR = URI_VALIDATOR;
/**
* A {@link Uri} that will point to the current default notification
@@ -3448,7 +3391,7 @@ public final class Settings {
*/
public static final String ALARM_ALERT = "alarm_alert";
- private static final Validator ALARM_ALERT_VALIDATOR = sUriValidator;
+ private static final Validator ALARM_ALERT_VALIDATOR = URI_VALIDATOR;
/**
* A {@link Uri} that will point to the current default alarm alert at
@@ -3470,31 +3413,21 @@ public final class Settings {
*/
public static final String MEDIA_BUTTON_RECEIVER = "media_button_receiver";
- private static final Validator MEDIA_BUTTON_RECEIVER_VALIDATOR = new Validator() {
- @Override
- public boolean validate(String value) {
- try {
- ComponentName.unflattenFromString(value);
- return true;
- } catch (NullPointerException e) {
- return false;
- }
- }
- };
+ private static final Validator MEDIA_BUTTON_RECEIVER_VALIDATOR = COMPONENT_NAME_VALIDATOR;
/**
* Setting to enable Auto Replace (AutoText) in text editors. 1 = On, 0 = Off
*/
public static final String TEXT_AUTO_REPLACE = "auto_replace";
- private static final Validator TEXT_AUTO_REPLACE_VALIDATOR = sBooleanValidator;
+ private static final Validator TEXT_AUTO_REPLACE_VALIDATOR = BOOLEAN_VALIDATOR;
/**
* Setting to enable Auto Caps in text editors. 1 = On, 0 = Off
*/
public static final String TEXT_AUTO_CAPS = "auto_caps";
- private static final Validator TEXT_AUTO_CAPS_VALIDATOR = sBooleanValidator;
+ private static final Validator TEXT_AUTO_CAPS_VALIDATOR = BOOLEAN_VALIDATOR;
/**
* Setting to enable Auto Punctuate in text editors. 1 = On, 0 = Off. This
@@ -3502,19 +3435,19 @@ public final class Settings {
*/
public static final String TEXT_AUTO_PUNCTUATE = "auto_punctuate";
- private static final Validator TEXT_AUTO_PUNCTUATE_VALIDATOR = sBooleanValidator;
+ private static final Validator TEXT_AUTO_PUNCTUATE_VALIDATOR = BOOLEAN_VALIDATOR;
/**
* Setting to showing password characters in text editors. 1 = On, 0 = Off
*/
public static final String TEXT_SHOW_PASSWORD = "show_password";
- private static final Validator TEXT_SHOW_PASSWORD_VALIDATOR = sBooleanValidator;
+ private static final Validator TEXT_SHOW_PASSWORD_VALIDATOR = BOOLEAN_VALIDATOR;
public static final String SHOW_GTALK_SERVICE_STATUS =
"SHOW_GTALK_SERVICE_STATUS";
- private static final Validator SHOW_GTALK_SERVICE_STATUS_VALIDATOR = sBooleanValidator;
+ private static final Validator SHOW_GTALK_SERVICE_STATUS_VALIDATOR = BOOLEAN_VALIDATOR;
/**
* Name of activity to use for wallpaper on the home screen.
@@ -3543,6 +3476,8 @@ public final class Settings {
@Deprecated
public static final String AUTO_TIME = Global.AUTO_TIME;
+ private static final Validator AUTO_TIME_VALIDATOR = BOOLEAN_VALIDATOR;
+
/**
* @deprecated Use {@link android.provider.Settings.Global#AUTO_TIME_ZONE}
* instead
@@ -3550,6 +3485,8 @@ public final class Settings {
@Deprecated
public static final String AUTO_TIME_ZONE = Global.AUTO_TIME_ZONE;
+ private static final Validator AUTO_TIME_ZONE_VALIDATOR = BOOLEAN_VALIDATOR;
+
/**
* Display times as 12 or 24 hours
* 12
@@ -3559,7 +3496,7 @@ public final class Settings {
/** @hide */
public static final Validator TIME_12_24_VALIDATOR =
- new DiscreteValueValidator(new String[] {"12", "24", null});
+ new SettingsValidators.DiscreteValueValidator(new String[] {"12", "24", null});
/**
* Date format string
@@ -3592,7 +3529,7 @@ public final class Settings {
public static final String SETUP_WIZARD_HAS_RUN = "setup_wizard_has_run";
/** @hide */
- public static final Validator SETUP_WIZARD_HAS_RUN_VALIDATOR = sBooleanValidator;
+ public static final Validator SETUP_WIZARD_HAS_RUN_VALIDATOR = BOOLEAN_VALIDATOR;
/**
* Scaling factor for normal window animations. Setting to 0 will disable window
@@ -3631,7 +3568,7 @@ public final class Settings {
public static final String ACCELEROMETER_ROTATION = "accelerometer_rotation";
/** @hide */
- public static final Validator ACCELEROMETER_ROTATION_VALIDATOR = sBooleanValidator;
+ public static final Validator ACCELEROMETER_ROTATION_VALIDATOR = BOOLEAN_VALIDATOR;
/**
* Default screen rotation when no other policy applies.
@@ -3645,7 +3582,7 @@ public final class Settings {
/** @hide */
public static final Validator USER_ROTATION_VALIDATOR =
- new InclusiveIntegerRangeValidator(0, 3);
+ new SettingsValidators.InclusiveIntegerRangeValidator(0, 3);
/**
* Control whether the rotation lock toggle in the System UI should be hidden.
@@ -3663,7 +3600,7 @@ public final class Settings {
/** @hide */
public static final Validator HIDE_ROTATION_LOCK_TOGGLE_FOR_ACCESSIBILITY_VALIDATOR =
- sBooleanValidator;
+ BOOLEAN_VALIDATOR;
/**
* Whether the phone vibrates when it is ringing due to an incoming call. This will
@@ -3678,7 +3615,7 @@ public final class Settings {
public static final String VIBRATE_WHEN_RINGING = "vibrate_when_ringing";
/** @hide */
- public static final Validator VIBRATE_WHEN_RINGING_VALIDATOR = sBooleanValidator;
+ public static final Validator VIBRATE_WHEN_RINGING_VALIDATOR = BOOLEAN_VALIDATOR;
/**
* Whether the audible DTMF tones are played by the dialer when dialing. The value is
@@ -3687,7 +3624,7 @@ public final class Settings {
public static final String DTMF_TONE_WHEN_DIALING = "dtmf_tone";
/** @hide */
- public static final Validator DTMF_TONE_WHEN_DIALING_VALIDATOR = sBooleanValidator;
+ public static final Validator DTMF_TONE_WHEN_DIALING_VALIDATOR = BOOLEAN_VALIDATOR;
/**
* CDMA only settings
@@ -3698,7 +3635,7 @@ public final class Settings {
public static final String DTMF_TONE_TYPE_WHEN_DIALING = "dtmf_tone_type";
/** @hide */
- public static final Validator DTMF_TONE_TYPE_WHEN_DIALING_VALIDATOR = sBooleanValidator;
+ public static final Validator DTMF_TONE_TYPE_WHEN_DIALING_VALIDATOR = BOOLEAN_VALIDATOR;
/**
* Whether the hearing aid is enabled. The value is
@@ -3708,7 +3645,7 @@ public final class Settings {
public static final String HEARING_AID = "hearing_aid";
/** @hide */
- public static final Validator HEARING_AID_VALIDATOR = sBooleanValidator;
+ public static final Validator HEARING_AID_VALIDATOR = BOOLEAN_VALIDATOR;
/**
* CDMA only settings
@@ -3722,7 +3659,8 @@ public final class Settings {
public static final String TTY_MODE = "tty_mode";
/** @hide */
- public static final Validator TTY_MODE_VALIDATOR = new InclusiveIntegerRangeValidator(0, 3);
+ public static final Validator TTY_MODE_VALIDATOR =
+ new SettingsValidators.InclusiveIntegerRangeValidator(0, 3);
/**
* Whether the sounds effects (key clicks, lid open ...) are enabled. The value is
@@ -3731,7 +3669,7 @@ public final class Settings {
public static final String SOUND_EFFECTS_ENABLED = "sound_effects_enabled";
/** @hide */
- public static final Validator SOUND_EFFECTS_ENABLED_VALIDATOR = sBooleanValidator;
+ public static final Validator SOUND_EFFECTS_ENABLED_VALIDATOR = BOOLEAN_VALIDATOR;
/**
* Whether the haptic feedback (long presses, ...) are enabled. The value is
@@ -3740,7 +3678,7 @@ public final class Settings {
public static final String HAPTIC_FEEDBACK_ENABLED = "haptic_feedback_enabled";
/** @hide */
- public static final Validator HAPTIC_FEEDBACK_ENABLED_VALIDATOR = sBooleanValidator;
+ public static final Validator HAPTIC_FEEDBACK_ENABLED_VALIDATOR = BOOLEAN_VALIDATOR;
/**
* @deprecated Each application that shows web suggestions should have its own
@@ -3750,7 +3688,7 @@ public final class Settings {
public static final String SHOW_WEB_SUGGESTIONS = "show_web_suggestions";
/** @hide */
- public static final Validator SHOW_WEB_SUGGESTIONS_VALIDATOR = sBooleanValidator;
+ public static final Validator SHOW_WEB_SUGGESTIONS_VALIDATOR = BOOLEAN_VALIDATOR;
/**
* Whether the notification LED should repeatedly flash when a notification is
@@ -3760,7 +3698,7 @@ public final class Settings {
public static final String NOTIFICATION_LIGHT_PULSE = "notification_light_pulse";
/** @hide */
- public static final Validator NOTIFICATION_LIGHT_PULSE_VALIDATOR = sBooleanValidator;
+ public static final Validator NOTIFICATION_LIGHT_PULSE_VALIDATOR = BOOLEAN_VALIDATOR;
/**
* Show pointer location on screen?
@@ -3771,7 +3709,7 @@ public final class Settings {
public static final String POINTER_LOCATION = "pointer_location";
/** @hide */
- public static final Validator POINTER_LOCATION_VALIDATOR = sBooleanValidator;
+ public static final Validator POINTER_LOCATION_VALIDATOR = BOOLEAN_VALIDATOR;
/**
* Show touch positions on screen?
@@ -3782,7 +3720,7 @@ public final class Settings {
public static final String SHOW_TOUCHES = "show_touches";
/** @hide */
- public static final Validator SHOW_TOUCHES_VALIDATOR = sBooleanValidator;
+ public static final Validator SHOW_TOUCHES_VALIDATOR = BOOLEAN_VALIDATOR;
/**
* Log raw orientation data from
@@ -3796,7 +3734,7 @@ public final class Settings {
"window_orientation_listener_log";
/** @hide */
- public static final Validator WINDOW_ORIENTATION_LISTENER_LOG_VALIDATOR = sBooleanValidator;
+ public static final Validator WINDOW_ORIENTATION_LISTENER_LOG_VALIDATOR = BOOLEAN_VALIDATOR;
/**
* @deprecated Use {@link android.provider.Settings.Global#POWER_SOUNDS_ENABLED}
@@ -3806,6 +3744,8 @@ public final class Settings {
@Deprecated
public static final String POWER_SOUNDS_ENABLED = Global.POWER_SOUNDS_ENABLED;
+ private static final Validator POWER_SOUNDS_ENABLED_VALIDATOR = BOOLEAN_VALIDATOR;
+
/**
* @deprecated Use {@link android.provider.Settings.Global#DOCK_SOUNDS_ENABLED}
* instead
@@ -3814,6 +3754,8 @@ public final class Settings {
@Deprecated
public static final String DOCK_SOUNDS_ENABLED = Global.DOCK_SOUNDS_ENABLED;
+ private static final Validator DOCK_SOUNDS_ENABLED_VALIDATOR = BOOLEAN_VALIDATOR;
+
/**
* Whether to play sounds when the keyguard is shown and dismissed.
* @hide
@@ -3821,7 +3763,7 @@ public final class Settings {
public static final String LOCKSCREEN_SOUNDS_ENABLED = "lockscreen_sounds_enabled";
/** @hide */
- public static final Validator LOCKSCREEN_SOUNDS_ENABLED_VALIDATOR = sBooleanValidator;
+ public static final Validator LOCKSCREEN_SOUNDS_ENABLED_VALIDATOR = BOOLEAN_VALIDATOR;
/**
* Whether the lockscreen should be completely disabled.
@@ -3830,7 +3772,7 @@ public final class Settings {
public static final String LOCKSCREEN_DISABLED = "lockscreen.disabled";
/** @hide */
- public static final Validator LOCKSCREEN_DISABLED_VALIDATOR = sBooleanValidator;
+ public static final Validator LOCKSCREEN_DISABLED_VALIDATOR = BOOLEAN_VALIDATOR;
/**
* @deprecated Use {@link android.provider.Settings.Global#LOW_BATTERY_SOUND}
@@ -3897,7 +3839,7 @@ public final class Settings {
public static final String SIP_RECEIVE_CALLS = "sip_receive_calls";
/** @hide */
- public static final Validator SIP_RECEIVE_CALLS_VALIDATOR = sBooleanValidator;
+ public static final Validator SIP_RECEIVE_CALLS_VALIDATOR = BOOLEAN_VALIDATOR;
/**
* Call Preference String.
@@ -3908,8 +3850,9 @@ public final class Settings {
public static final String SIP_CALL_OPTIONS = "sip_call_options";
/** @hide */
- public static final Validator SIP_CALL_OPTIONS_VALIDATOR = new DiscreteValueValidator(
- new String[] {"SIP_ALWAYS", "SIP_ADDRESS_ONLY"});
+ public static final Validator SIP_CALL_OPTIONS_VALIDATOR =
+ new SettingsValidators.DiscreteValueValidator(
+ new String[] {"SIP_ALWAYS", "SIP_ADDRESS_ONLY"});
/**
* One of the sip call options: Always use SIP with network access.
@@ -3918,7 +3861,7 @@ public final class Settings {
public static final String SIP_ALWAYS = "SIP_ALWAYS";
/** @hide */
- public static final Validator SIP_ALWAYS_VALIDATOR = sBooleanValidator;
+ public static final Validator SIP_ALWAYS_VALIDATOR = BOOLEAN_VALIDATOR;
/**
* One of the sip call options: Only if destination is a SIP address.
@@ -3927,7 +3870,7 @@ public final class Settings {
public static final String SIP_ADDRESS_ONLY = "SIP_ADDRESS_ONLY";
/** @hide */
- public static final Validator SIP_ADDRESS_ONLY_VALIDATOR = sBooleanValidator;
+ public static final Validator SIP_ADDRESS_ONLY_VALIDATOR = BOOLEAN_VALIDATOR;
/**
* @deprecated Use SIP_ALWAYS or SIP_ADDRESS_ONLY instead. Formerly used to indicate that
@@ -3940,7 +3883,7 @@ public final class Settings {
public static final String SIP_ASK_ME_EACH_TIME = "SIP_ASK_ME_EACH_TIME";
/** @hide */
- public static final Validator SIP_ASK_ME_EACH_TIME_VALIDATOR = sBooleanValidator;
+ public static final Validator SIP_ASK_ME_EACH_TIME_VALIDATOR = BOOLEAN_VALIDATOR;
/**
* Pointer speed setting.
@@ -3954,7 +3897,7 @@ public final class Settings {
/** @hide */
public static final Validator POINTER_SPEED_VALIDATOR =
- new InclusiveFloatRangeValidator(-7, 7);
+ new SettingsValidators.InclusiveFloatRangeValidator(-7, 7);
/**
* Whether lock-to-app will be triggered by long-press on recents.
@@ -3963,7 +3906,7 @@ public final class Settings {
public static final String LOCK_TO_APP_ENABLED = "lock_to_app_enabled";
/** @hide */
- public static final Validator LOCK_TO_APP_ENABLED_VALIDATOR = sBooleanValidator;
+ public static final Validator LOCK_TO_APP_ENABLED_VALIDATOR = BOOLEAN_VALIDATOR;
/**
* I am the lolrus.
@@ -3995,7 +3938,7 @@ public final class Settings {
public static final String SHOW_BATTERY_PERCENT = "status_bar_show_battery_percent";
/** @hide */
- private static final Validator SHOW_BATTERY_PERCENT_VALIDATOR = sBooleanValidator;
+ private static final Validator SHOW_BATTERY_PERCENT_VALIDATOR = BOOLEAN_VALIDATOR;
/**
* IMPORTANT: If you add a new public settings you also have to add it to
@@ -4067,6 +4010,9 @@ public final class Settings {
* Keys we no longer back up under the current schema, but want to continue to
* process when restoring historical backup datasets.
*
+ * All settings in {@link LEGACY_RESTORE_SETTINGS} array *must* have a non-null validator,
+ * otherwise they won't be restored.
+ *
* @hide
*/
public static final String[] LEGACY_RESTORE_SETTINGS = {
@@ -4175,11 +4121,15 @@ public final class Settings {
/**
* These are all public system settings
*
+ * All settings in {@link SETTINGS_TO_BACKUP} array *must* have a non-null validator,
+ * otherwise they won't be restored.
+ *
* @hide
*/
public static final Map<String, Validator> VALIDATORS = new ArrayMap<>();
static {
- VALIDATORS.put(END_BUTTON_BEHAVIOR,END_BUTTON_BEHAVIOR_VALIDATOR);
+ VALIDATORS.put(STAY_ON_WHILE_PLUGGED_IN, STAY_ON_WHILE_PLUGGED_IN_VALIDATOR);
+ VALIDATORS.put(END_BUTTON_BEHAVIOR, END_BUTTON_BEHAVIOR_VALIDATOR);
VALIDATORS.put(WIFI_USE_STATIC_IP, WIFI_USE_STATIC_IP_VALIDATOR);
VALIDATORS.put(BLUETOOTH_DISCOVERABILITY, BLUETOOTH_DISCOVERABILITY_VALIDATOR);
VALIDATORS.put(BLUETOOTH_DISCOVERABILITY_TIMEOUT,
@@ -4201,6 +4151,8 @@ public final class Settings {
VALIDATORS.put(TEXT_AUTO_CAPS, TEXT_AUTO_CAPS_VALIDATOR);
VALIDATORS.put(TEXT_AUTO_PUNCTUATE, TEXT_AUTO_PUNCTUATE_VALIDATOR);
VALIDATORS.put(TEXT_SHOW_PASSWORD, TEXT_SHOW_PASSWORD_VALIDATOR);
+ VALIDATORS.put(AUTO_TIME, AUTO_TIME_VALIDATOR);
+ VALIDATORS.put(AUTO_TIME_ZONE, AUTO_TIME_ZONE_VALIDATOR);
VALIDATORS.put(SHOW_GTALK_SERVICE_STATUS, SHOW_GTALK_SERVICE_STATUS_VALIDATOR);
VALIDATORS.put(WALLPAPER_ACTIVITY, WALLPAPER_ACTIVITY_VALIDATOR);
VALIDATORS.put(TIME_12_24, TIME_12_24_VALIDATOR);
@@ -4211,6 +4163,8 @@ public final class Settings {
VALIDATORS.put(DTMF_TONE_WHEN_DIALING, DTMF_TONE_WHEN_DIALING_VALIDATOR);
VALIDATORS.put(SOUND_EFFECTS_ENABLED, SOUND_EFFECTS_ENABLED_VALIDATOR);
VALIDATORS.put(HAPTIC_FEEDBACK_ENABLED, HAPTIC_FEEDBACK_ENABLED_VALIDATOR);
+ VALIDATORS.put(POWER_SOUNDS_ENABLED, POWER_SOUNDS_ENABLED_VALIDATOR);
+ VALIDATORS.put(DOCK_SOUNDS_ENABLED, DOCK_SOUNDS_ENABLED_VALIDATOR);
VALIDATORS.put(SHOW_WEB_SUGGESTIONS, SHOW_WEB_SUGGESTIONS_VALIDATOR);
VALIDATORS.put(WIFI_USE_STATIC_IP, WIFI_USE_STATIC_IP_VALIDATOR);
VALIDATORS.put(END_BUTTON_BEHAVIOR, END_BUTTON_BEHAVIOR_VALIDATOR);
@@ -4335,6 +4289,8 @@ public final class Settings {
@Deprecated
public static final String BLUETOOTH_ON = Global.BLUETOOTH_ON;
+ private static final Validator BLUETOOTH_ON_VALIDATOR = BOOLEAN_VALIDATOR;
+
/**
* @deprecated Use {@link android.provider.Settings.Global#DATA_ROAMING} instead
*/
@@ -4412,6 +4368,8 @@ public final class Settings {
@Deprecated
public static final String USB_MASS_STORAGE_ENABLED = Global.USB_MASS_STORAGE_ENABLED;
+ private static final Validator USB_MASS_STORAGE_ENABLED_VALIDATOR = BOOLEAN_VALIDATOR;
+
/**
* @deprecated Use {@link android.provider.Settings.Global#USE_GOOGLE_MAIL} instead
*/
@@ -4441,6 +4399,9 @@ public final class Settings {
public static final String WIFI_NETWORKS_AVAILABLE_NOTIFICATION_ON =
Global.WIFI_NETWORKS_AVAILABLE_NOTIFICATION_ON;
+ private static final Validator WIFI_NETWORKS_AVAILABLE_NOTIFICATION_ON_VALIDATOR =
+ BOOLEAN_VALIDATOR;
+
/**
* @deprecated Use
* {@link android.provider.Settings.Global#WIFI_NETWORKS_AVAILABLE_REPEAT_DELAY} instead
@@ -4449,6 +4410,9 @@ public final class Settings {
public static final String WIFI_NETWORKS_AVAILABLE_REPEAT_DELAY =
Global.WIFI_NETWORKS_AVAILABLE_REPEAT_DELAY;
+ private static final Validator WIFI_NETWORKS_AVAILABLE_REPEAT_DELAY_VALIDATOR =
+ NON_NEGATIVE_INTEGER_VALIDATOR;
+
/**
* @deprecated Use {@link android.provider.Settings.Global#WIFI_NUM_OPEN_NETWORKS_KEPT}
* instead
@@ -4456,6 +4420,9 @@ public final class Settings {
@Deprecated
public static final String WIFI_NUM_OPEN_NETWORKS_KEPT = Global.WIFI_NUM_OPEN_NETWORKS_KEPT;
+ private static final Validator WIFI_NUM_OPEN_NETWORKS_KEPT_VALIDATOR =
+ NON_NEGATIVE_INTEGER_VALIDATOR;
+
/**
* @deprecated Use {@link android.provider.Settings.Global#WIFI_ON} instead
*/
@@ -5218,6 +5185,8 @@ public final class Settings {
@Deprecated
public static final String BUGREPORT_IN_POWER_MENU = "bugreport_in_power_menu";
+ private static final Validator BUGREPORT_IN_POWER_MENU_VALIDATOR = BOOLEAN_VALIDATOR;
+
/**
* @deprecated Use {@link android.provider.Settings.Global#ADB_ENABLED} instead
*/
@@ -5235,6 +5204,8 @@ public final class Settings {
@Deprecated
public static final String ALLOW_MOCK_LOCATION = "mock_location";
+ private static final Validator ALLOW_MOCK_LOCATION_VALIDATOR = BOOLEAN_VALIDATOR;
+
/**
* On Android 8.0 (API level 26) and higher versions of the platform,
* a 64-bit number (expressed as a hexadecimal string), unique to
@@ -5280,6 +5251,8 @@ public final class Settings {
@Deprecated
public static final String BLUETOOTH_ON = Global.BLUETOOTH_ON;
+ private static final Validator BLUETOOTH_ON_VALIDATOR = BOOLEAN_VALIDATOR;
+
/**
* @deprecated Use {@link android.provider.Settings.Global#DATA_ROAMING} instead
*/
@@ -5327,6 +5300,8 @@ public final class Settings {
@TestApi
public static final String AUTOFILL_SERVICE = "autofill_service";
+ private static final Validator AUTOFILL_SERVICE_VALIDATOR = COMPONENT_NAME_VALIDATOR;
+
/**
* Boolean indicating if Autofill supports field classification.
*
@@ -5413,9 +5388,38 @@ public final class Settings {
* List of input methods that are currently enabled. This is a string
* containing the IDs of all enabled input methods, each ID separated
* by ':'.
+ *
+ * Format like "ime0;subtype0;subtype1;subtype2:ime1:ime2;subtype0"
+ * where imeId is ComponentName and subtype is int32.
*/
public static final String ENABLED_INPUT_METHODS = "enabled_input_methods";
+ private static final Validator ENABLED_INPUT_METHODS_VALIDATOR = new Validator() {
+ @Override
+ public boolean validate(String value) {
+ if (value == null) {
+ return false;
+ }
+ String[] inputMethods = value.split(":");
+ boolean valid = true;
+ for (String inputMethod : inputMethods) {
+ if (inputMethod.length() == 0) {
+ return false;
+ }
+ String[] subparts = inputMethod.split(";");
+ for (String subpart : subparts) {
+ // allow either a non negative integer or a ComponentName
+ valid |= (NON_NEGATIVE_INTEGER_VALIDATOR.validate(subpart)
+ || COMPONENT_NAME_VALIDATOR.validate(subpart));
+ }
+ if (!valid) {
+ return false;
+ }
+ }
+ return valid;
+ }
+ };
+
/**
* List of system input methods that are currently disabled. This is a string
* containing the IDs of all disabled input methods, each ID separated
@@ -5431,6 +5435,8 @@ public final class Settings {
*/
public static final String SHOW_IME_WITH_HARD_KEYBOARD = "show_ime_with_hard_keyboard";
+ private static final Validator SHOW_IME_WITH_HARD_KEYBOARD_VALIDATOR = BOOLEAN_VALIDATOR;
+
/**
* Host name and port for global http proxy. Uses ':' seperator for
* between host and port.
@@ -5707,6 +5713,8 @@ public final class Settings {
@Deprecated
public static final String USB_MASS_STORAGE_ENABLED = Global.USB_MASS_STORAGE_ENABLED;
+ private static final Validator USB_MASS_STORAGE_ENABLED_VALIDATOR = BOOLEAN_VALIDATOR;
+
/**
* @deprecated Use {@link android.provider.Settings.Global#USE_GOOGLE_MAIL} instead
*/
@@ -5718,6 +5726,8 @@ public final class Settings {
*/
public static final String ACCESSIBILITY_ENABLED = "accessibility_enabled";
+ private static final Validator ACCESSIBILITY_ENABLED_VALIDATOR = BOOLEAN_VALIDATOR;
+
/**
* Setting specifying if the accessibility shortcut is enabled.
* @hide
@@ -5725,6 +5735,8 @@ public final class Settings {
public static final String ACCESSIBILITY_SHORTCUT_ENABLED =
"accessibility_shortcut_enabled";
+ private static final Validator ACCESSIBILITY_SHORTCUT_ENABLED_VALIDATOR = BOOLEAN_VALIDATOR;
+
/**
* Setting specifying if the accessibility shortcut is enabled.
* @hide
@@ -5732,6 +5744,9 @@ public final class Settings {
public static final String ACCESSIBILITY_SHORTCUT_ON_LOCK_SCREEN =
"accessibility_shortcut_on_lock_screen";
+ private static final Validator ACCESSIBILITY_SHORTCUT_ON_LOCK_SCREEN_VALIDATOR =
+ BOOLEAN_VALIDATOR;
+
/**
* Setting specifying if the accessibility shortcut dialog has been shown to this user.
* @hide
@@ -5739,6 +5754,9 @@ public final class Settings {
public static final String ACCESSIBILITY_SHORTCUT_DIALOG_SHOWN =
"accessibility_shortcut_dialog_shown";
+ private static final Validator ACCESSIBILITY_SHORTCUT_DIALOG_SHOWN_VALIDATOR =
+ BOOLEAN_VALIDATOR;
+
/**
* Setting specifying the accessibility service to be toggled via the accessibility
* shortcut. Must be its flattened {@link ComponentName}.
@@ -5747,6 +5765,9 @@ public final class Settings {
public static final String ACCESSIBILITY_SHORTCUT_TARGET_SERVICE =
"accessibility_shortcut_target_service";
+ private static final Validator ACCESSIBILITY_SHORTCUT_TARGET_SERVICE_VALIDATOR =
+ COMPONENT_NAME_VALIDATOR;
+
/**
* Setting specifying the accessibility service or feature to be toggled via the
* accessibility button in the navigation bar. This is either a flattened
@@ -5757,17 +5778,32 @@ public final class Settings {
public static final String ACCESSIBILITY_BUTTON_TARGET_COMPONENT =
"accessibility_button_target_component";
+ private static final Validator ACCESSIBILITY_BUTTON_TARGET_COMPONENT_VALIDATOR =
+ new Validator() {
+ @Override
+ public boolean validate(String value) {
+ // technically either ComponentName or class name, but there's proper value
+ // validation at callsites, so allow any non-null string
+ return value != null;
+ }
+ };
+
/**
* If touch exploration is enabled.
*/
public static final String TOUCH_EXPLORATION_ENABLED = "touch_exploration_enabled";
+ private static final Validator TOUCH_EXPLORATION_ENABLED_VALIDATOR = BOOLEAN_VALIDATOR;
+
/**
* List of the enabled accessibility providers.
*/
public static final String ENABLED_ACCESSIBILITY_SERVICES =
"enabled_accessibility_services";
+ private static final Validator ENABLED_ACCESSIBILITY_SERVICES_VALIDATOR =
+ new SettingsValidators.ComponentNameListValidator(":");
+
/**
* List of the accessibility services to which the user has granted
* permission to put the device into touch exploration mode.
@@ -5777,6 +5813,9 @@ public final class Settings {
public static final String TOUCH_EXPLORATION_GRANTED_ACCESSIBILITY_SERVICES =
"touch_exploration_granted_accessibility_services";
+ private static final Validator TOUCH_EXPLORATION_GRANTED_ACCESSIBILITY_SERVICES_VALIDATOR =
+ new SettingsValidators.ComponentNameListValidator(":");
+
/**
* Uri of the slice that's presented on the keyguard.
* Defaults to a slice with the date and next alarm.
@@ -5795,6 +5834,8 @@ public final class Settings {
@Deprecated
public static final String ACCESSIBILITY_SPEAK_PASSWORD = "speak_password";
+ private static final Validator ACCESSIBILITY_SPEAK_PASSWORD_VALIDATOR = BOOLEAN_VALIDATOR;
+
/**
* Whether to draw text with high contrast while in accessibility mode.
*
@@ -5803,6 +5844,9 @@ public final class Settings {
public static final String ACCESSIBILITY_HIGH_TEXT_CONTRAST_ENABLED =
"high_text_contrast_enabled";
+ private static final Validator ACCESSIBILITY_HIGH_TEXT_CONTRAST_ENABLED_VALIDATOR =
+ BOOLEAN_VALIDATOR;
+
/**
* Setting that specifies whether the display magnification is enabled via a system-wide
* triple tap gesture. Display magnifications allows the user to zoom in the display content
@@ -5815,6 +5859,9 @@ public final class Settings {
public static final String ACCESSIBILITY_DISPLAY_MAGNIFICATION_ENABLED =
"accessibility_display_magnification_enabled";
+ private static final Validator ACCESSIBILITY_DISPLAY_MAGNIFICATION_ENABLED_VALIDATOR =
+ BOOLEAN_VALIDATOR;
+
/**
* Setting that specifies whether the display magnification is enabled via a shortcut
* affordance within the system's navigation area. Display magnifications allows the user to
@@ -5826,6 +5873,9 @@ public final class Settings {
public static final String ACCESSIBILITY_DISPLAY_MAGNIFICATION_NAVBAR_ENABLED =
"accessibility_display_magnification_navbar_enabled";
+ private static final Validator ACCESSIBILITY_DISPLAY_MAGNIFICATION_NAVBAR_ENABLED_VALIDATOR
+ = BOOLEAN_VALIDATOR;
+
/**
* Setting that specifies what the display magnification scale is.
* Display magnifications allows the user to zoom in the display
@@ -5839,6 +5889,9 @@ public final class Settings {
public static final String ACCESSIBILITY_DISPLAY_MAGNIFICATION_SCALE =
"accessibility_display_magnification_scale";
+ private static final Validator ACCESSIBILITY_DISPLAY_MAGNIFICATION_SCALE_VALIDATOR =
+ new SettingsValidators.InclusiveFloatRangeValidator(1.0f, Float.MAX_VALUE);
+
/**
* Unused mangnification setting
*
@@ -5891,6 +5944,9 @@ public final class Settings {
public static final String ACCESSIBILITY_CAPTIONING_ENABLED =
"accessibility_captioning_enabled";
+ private static final Validator ACCESSIBILITY_CAPTIONING_ENABLED_VALIDATOR =
+ BOOLEAN_VALIDATOR;
+
/**
* Setting that specifies the language for captions as a locale string,
* e.g. en_US.
@@ -5901,6 +5957,8 @@ public final class Settings {
public static final String ACCESSIBILITY_CAPTIONING_LOCALE =
"accessibility_captioning_locale";
+ private static final Validator ACCESSIBILITY_CAPTIONING_LOCALE_VALIDATOR = LOCALE_VALIDATOR;
+
/**
* Integer property that specifies the preset style for captions, one
* of:
@@ -5915,6 +5973,10 @@ public final class Settings {
public static final String ACCESSIBILITY_CAPTIONING_PRESET =
"accessibility_captioning_preset";
+ private static final Validator ACCESSIBILITY_CAPTIONING_PRESET_VALIDATOR =
+ new SettingsValidators.DiscreteValueValidator(new String[]{"-1", "0", "1", "2",
+ "3", "4"});
+
/**
* Integer property that specifes the background color for captions as a
* packed 32-bit color.
@@ -5925,6 +5987,9 @@ public final class Settings {
public static final String ACCESSIBILITY_CAPTIONING_BACKGROUND_COLOR =
"accessibility_captioning_background_color";
+ private static final Validator ACCESSIBILITY_CAPTIONING_BACKGROUND_COLOR_VALIDATOR =
+ ANY_INTEGER_VALIDATOR;
+
/**
* Integer property that specifes the foreground color for captions as a
* packed 32-bit color.
@@ -5935,6 +6000,9 @@ public final class Settings {
public static final String ACCESSIBILITY_CAPTIONING_FOREGROUND_COLOR =
"accessibility_captioning_foreground_color";
+ private static final Validator ACCESSIBILITY_CAPTIONING_FOREGROUND_COLOR_VALIDATOR =
+ ANY_INTEGER_VALIDATOR;
+
/**
* Integer property that specifes the edge type for captions, one of:
* <ul>
@@ -5949,6 +6017,9 @@ public final class Settings {
public static final String ACCESSIBILITY_CAPTIONING_EDGE_TYPE =
"accessibility_captioning_edge_type";
+ private static final Validator ACCESSIBILITY_CAPTIONING_EDGE_TYPE_VALIDATOR =
+ new SettingsValidators.DiscreteValueValidator(new String[]{"0", "1", "2"});
+
/**
* Integer property that specifes the edge color for captions as a
* packed 32-bit color.
@@ -5960,6 +6031,9 @@ public final class Settings {
public static final String ACCESSIBILITY_CAPTIONING_EDGE_COLOR =
"accessibility_captioning_edge_color";
+ private static final Validator ACCESSIBILITY_CAPTIONING_EDGE_COLOR_VALIDATOR =
+ ANY_INTEGER_VALIDATOR;
+
/**
* Integer property that specifes the window color for captions as a
* packed 32-bit color.
@@ -5970,6 +6044,9 @@ public final class Settings {
public static final String ACCESSIBILITY_CAPTIONING_WINDOW_COLOR =
"accessibility_captioning_window_color";
+ private static final Validator ACCESSIBILITY_CAPTIONING_WINDOW_COLOR_VALIDATOR =
+ ANY_INTEGER_VALIDATOR;
+
/**
* String property that specifies the typeface for captions, one of:
* <ul>
@@ -5985,6 +6062,10 @@ public final class Settings {
public static final String ACCESSIBILITY_CAPTIONING_TYPEFACE =
"accessibility_captioning_typeface";
+ private static final Validator ACCESSIBILITY_CAPTIONING_TYPEFACE_VALIDATOR =
+ new SettingsValidators.DiscreteValueValidator(new String[]{"DEFAULT",
+ "MONOSPACE", "SANS_SERIF", "SERIF"});
+
/**
* Floating point property that specifies font scaling for captions.
*
@@ -5993,12 +6074,18 @@ public final class Settings {
public static final String ACCESSIBILITY_CAPTIONING_FONT_SCALE =
"accessibility_captioning_font_scale";
+ private static final Validator ACCESSIBILITY_CAPTIONING_FONT_SCALE_VALIDATOR =
+ new SettingsValidators.InclusiveFloatRangeValidator(0.5f, 2.0f);
+
/**
* Setting that specifies whether display color inversion is enabled.
*/
public static final String ACCESSIBILITY_DISPLAY_INVERSION_ENABLED =
"accessibility_display_inversion_enabled";
+ private static final Validator ACCESSIBILITY_DISPLAY_INVERSION_ENABLED_VALIDATOR =
+ BOOLEAN_VALIDATOR;
+
/**
* Setting that specifies whether display color space adjustment is
* enabled.
@@ -6008,15 +6095,24 @@ public final class Settings {
public static final String ACCESSIBILITY_DISPLAY_DALTONIZER_ENABLED =
"accessibility_display_daltonizer_enabled";
+ private static final Validator ACCESSIBILITY_DISPLAY_DALTONIZER_ENABLED_VALIDATOR =
+ BOOLEAN_VALIDATOR;
+
/**
* Integer property that specifies the type of color space adjustment to
- * perform. Valid values are defined in AccessibilityManager.
+ * perform. Valid values are defined in AccessibilityManager:
+ * - AccessibilityManager.DALTONIZER_DISABLED = -1
+ * - AccessibilityManager.DALTONIZER_SIMULATE_MONOCHROMACY = 0
+ * - AccessibilityManager.DALTONIZER_CORRECT_DEUTERANOMALY = 12
*
* @hide
*/
public static final String ACCESSIBILITY_DISPLAY_DALTONIZER =
"accessibility_display_daltonizer";
+ private static final Validator ACCESSIBILITY_DISPLAY_DALTONIZER_VALIDATOR =
+ new SettingsValidators.DiscreteValueValidator(new String[] {"-1", "0", "12"});
+
/**
* Setting that specifies whether automatic click when the mouse pointer stops moving is
* enabled.
@@ -6026,6 +6122,9 @@ public final class Settings {
public static final String ACCESSIBILITY_AUTOCLICK_ENABLED =
"accessibility_autoclick_enabled";
+ private static final Validator ACCESSIBILITY_AUTOCLICK_ENABLED_VALIDATOR =
+ BOOLEAN_VALIDATOR;
+
/**
* Integer setting specifying amount of time in ms the mouse pointer has to stay still
* before performing click when {@link #ACCESSIBILITY_AUTOCLICK_ENABLED} is set.
@@ -6036,6 +6135,9 @@ public final class Settings {
public static final String ACCESSIBILITY_AUTOCLICK_DELAY =
"accessibility_autoclick_delay";
+ private static final Validator ACCESSIBILITY_AUTOCLICK_DELAY_VALIDATOR =
+ NON_NEGATIVE_INTEGER_VALIDATOR;
+
/**
* Whether or not larger size icons are used for the pointer of mouse/trackpad for
* accessibility.
@@ -6045,12 +6147,18 @@ public final class Settings {
public static final String ACCESSIBILITY_LARGE_POINTER_ICON =
"accessibility_large_pointer_icon";
+ private static final Validator ACCESSIBILITY_LARGE_POINTER_ICON_VALIDATOR =
+ BOOLEAN_VALIDATOR;
+
/**
* The timeout for considering a press to be a long press in milliseconds.
* @hide
*/
public static final String LONG_PRESS_TIMEOUT = "long_press_timeout";
+ private static final Validator LONG_PRESS_TIMEOUT_VALIDATOR =
+ NON_NEGATIVE_INTEGER_VALIDATOR;
+
/**
* The duration in milliseconds between the first tap's up event and the second tap's
* down event for an interaction to be considered part of the same multi-press.
@@ -6104,16 +6212,22 @@ public final class Settings {
*/
public static final String TTS_DEFAULT_RATE = "tts_default_rate";
+ private static final Validator TTS_DEFAULT_RATE_VALIDATOR = NON_NEGATIVE_INTEGER_VALIDATOR;
+
/**
* Default text-to-speech engine pitch. 100 = 1x
*/
public static final String TTS_DEFAULT_PITCH = "tts_default_pitch";
+ private static final Validator TTS_DEFAULT_PITCH_VALIDATOR = NON_NEGATIVE_INTEGER_VALIDATOR;
+
/**
* Default text-to-speech engine.
*/
public static final String TTS_DEFAULT_SYNTH = "tts_default_synth";
+ private static final Validator TTS_DEFAULT_SYNTH_VALIDATOR = PACKAGE_NAME_VALIDATOR;
+
/**
* Default text-to-speech language.
*
@@ -6161,11 +6275,33 @@ public final class Settings {
*/
public static final String TTS_DEFAULT_LOCALE = "tts_default_locale";
+ private static final Validator TTS_DEFAULT_LOCALE_VALIDATOR = new Validator() {
+ @Override
+ public boolean validate(String value) {
+ if (value == null || value.length() == 0) {
+ return false;
+ }
+ String[] ttsLocales = value.split(",");
+ boolean valid = true;
+ for (String ttsLocale : ttsLocales) {
+ String[] parts = ttsLocale.split(":");
+ valid |= ((parts.length == 2)
+ && (parts[0].length() > 0)
+ && ANY_STRING_VALIDATOR.validate(parts[0])
+ && LOCALE_VALIDATOR.validate(parts[1]));
+ }
+ return valid;
+ }
+ };
+
/**
* Space delimited list of plugin packages that are enabled.
*/
public static final String TTS_ENABLED_PLUGINS = "tts_enabled_plugins";
+ private static final Validator TTS_ENABLED_PLUGINS_VALIDATOR =
+ new SettingsValidators.PackageNameListValidator(" ");
+
/**
* @deprecated Use {@link android.provider.Settings.Global#WIFI_NETWORKS_AVAILABLE_NOTIFICATION_ON}
* instead.
@@ -6174,6 +6310,9 @@ public final class Settings {
public static final String WIFI_NETWORKS_AVAILABLE_NOTIFICATION_ON =
Global.WIFI_NETWORKS_AVAILABLE_NOTIFICATION_ON;
+ private static final Validator WIFI_NETWORKS_AVAILABLE_NOTIFICATION_ON_VALIDATOR =
+ BOOLEAN_VALIDATOR;
+
/**
* @deprecated Use {@link android.provider.Settings.Global#WIFI_NETWORKS_AVAILABLE_REPEAT_DELAY}
* instead.
@@ -6182,6 +6321,9 @@ public final class Settings {
public static final String WIFI_NETWORKS_AVAILABLE_REPEAT_DELAY =
Global.WIFI_NETWORKS_AVAILABLE_REPEAT_DELAY;
+ private static final Validator WIFI_NETWORKS_AVAILABLE_REPEAT_DELAY_VALIDATOR =
+ NON_NEGATIVE_INTEGER_VALIDATOR;
+
/**
* @deprecated Use {@link android.provider.Settings.Global#WIFI_NUM_OPEN_NETWORKS_KEPT}
* instead.
@@ -6190,6 +6332,9 @@ public final class Settings {
public static final String WIFI_NUM_OPEN_NETWORKS_KEPT =
Global.WIFI_NUM_OPEN_NETWORKS_KEPT;
+ private static final Validator WIFI_NUM_OPEN_NETWORKS_KEPT_VALIDATOR =
+ NON_NEGATIVE_INTEGER_VALIDATOR;
+
/**
* @deprecated Use {@link android.provider.Settings.Global#WIFI_ON}
* instead.
@@ -6348,6 +6493,9 @@ public final class Settings {
public static final String PREFERRED_TTY_MODE =
"preferred_tty_mode";
+ private static final Validator PREFERRED_TTY_MODE_VALIDATOR =
+ new SettingsValidators.DiscreteValueValidator(new String[]{"0", "1", "2", "3"});
+
/**
* Whether the enhanced voice privacy mode is enabled.
* 0 = normal voice privacy
@@ -6356,6 +6504,8 @@ public final class Settings {
*/
public static final String ENHANCED_VOICE_PRIVACY_ENABLED = "enhanced_voice_privacy_enabled";
+ private static final Validator ENHANCED_VOICE_PRIVACY_ENABLED_VALIDATOR = BOOLEAN_VALIDATOR;
+
/**
* Whether the TTY mode mode is enabled.
* 0 = disabled
@@ -6364,6 +6514,8 @@ public final class Settings {
*/
public static final String TTY_MODE_ENABLED = "tty_mode_enabled";
+ private static final Validator TTY_MODE_ENABLED_VALIDATOR = BOOLEAN_VALIDATOR;
+
/**
* Controls whether settings backup is enabled.
* Type: int ( 0 = disabled, 1 = enabled )
@@ -6534,24 +6686,32 @@ public final class Settings {
*/
public static final String MOUNT_PLAY_NOTIFICATION_SND = "mount_play_not_snd";
+ private static final Validator MOUNT_PLAY_NOTIFICATION_SND_VALIDATOR = BOOLEAN_VALIDATOR;
+
/**
* Whether or not UMS auto-starts on UMS host detection. (0 = false, 1 = true)
* @hide
*/
public static final String MOUNT_UMS_AUTOSTART = "mount_ums_autostart";
+ private static final Validator MOUNT_UMS_AUTOSTART_VALIDATOR = BOOLEAN_VALIDATOR;
+
/**
* Whether or not a notification is displayed on UMS host detection. (0 = false, 1 = true)
* @hide
*/
public static final String MOUNT_UMS_PROMPT = "mount_ums_prompt";
+ private static final Validator MOUNT_UMS_PROMPT_VALIDATOR = BOOLEAN_VALIDATOR;
+
/**
* Whether or not a notification is displayed while UMS is enabled. (0 = false, 1 = true)
* @hide
*/
public static final String MOUNT_UMS_NOTIFY_ENABLED = "mount_ums_notify_enabled";
+ private static final Validator MOUNT_UMS_NOTIFY_ENABLED_VALIDATOR = BOOLEAN_VALIDATOR;
+
/**
* If nonzero, ANRs in invisible background processes bring up a dialog.
* Otherwise, the process will be silently killed.
@@ -6569,6 +6729,9 @@ public final class Settings {
public static final String SHOW_FIRST_CRASH_DIALOG_DEV_OPTION =
"show_first_crash_dialog_dev_option";
+ private static final Validator SHOW_FIRST_CRASH_DIALOG_DEV_OPTION_VALIDATOR =
+ BOOLEAN_VALIDATOR;
+
/**
* The {@link ComponentName} string of the service to be used as the voice recognition
* service.
@@ -6594,6 +6757,8 @@ public final class Settings {
*/
public static final String SELECTED_SPELL_CHECKER = "selected_spell_checker";
+ private static final Validator SELECTED_SPELL_CHECKER_VALIDATOR = COMPONENT_NAME_VALIDATOR;
+
/**
* The {@link ComponentName} string of the selected subtype of the selected spell checker
* service which is one of the services managed by the text service manager.
@@ -6603,13 +6768,18 @@ public final class Settings {
public static final String SELECTED_SPELL_CHECKER_SUBTYPE =
"selected_spell_checker_subtype";
+ private static final Validator SELECTED_SPELL_CHECKER_SUBTYPE_VALIDATOR =
+ COMPONENT_NAME_VALIDATOR;
+
/**
- * The {@link ComponentName} string whether spell checker is enabled or not.
+ * Whether spell checker is enabled or not.
*
* @hide
*/
public static final String SPELL_CHECKER_ENABLED = "spell_checker_enabled";
+ private static final Validator SPELL_CHECKER_ENABLED_VALIDATOR = BOOLEAN_VALIDATOR;
+
/**
* What happens when the user presses the Power button while in-call
* and the screen is on.<br/>
@@ -6621,6 +6791,9 @@ public final class Settings {
*/
public static final String INCALL_POWER_BUTTON_BEHAVIOR = "incall_power_button_behavior";
+ private static final Validator INCALL_POWER_BUTTON_BEHAVIOR_VALIDATOR =
+ new SettingsValidators.DiscreteValueValidator(new String[]{"1", "2"});
+
/**
* INCALL_POWER_BUTTON_BEHAVIOR value for "turn off screen".
* @hide
@@ -6676,12 +6849,16 @@ public final class Settings {
*/
public static final String WAKE_GESTURE_ENABLED = "wake_gesture_enabled";
+ private static final Validator WAKE_GESTURE_ENABLED_VALIDATOR = BOOLEAN_VALIDATOR;
+
/**
* Whether the device should doze if configured.
* @hide
*/
public static final String DOZE_ENABLED = "doze_enabled";
+ private static final Validator DOZE_ENABLED_VALIDATOR = BOOLEAN_VALIDATOR;
+
/**
* Whether doze should be always on.
* @hide
@@ -6694,6 +6871,8 @@ public final class Settings {
*/
public static final String DOZE_PULSE_ON_PICK_UP = "doze_pulse_on_pick_up";
+ private static final Validator DOZE_PULSE_ON_PICK_UP_VALIDATOR = BOOLEAN_VALIDATOR;
+
/**
* Whether the device should pulse on long press gesture.
* @hide
@@ -6706,6 +6885,8 @@ public final class Settings {
*/
public static final String DOZE_PULSE_ON_DOUBLE_TAP = "doze_pulse_on_double_tap";
+ private static final Validator DOZE_PULSE_ON_DOUBLE_TAP_VALIDATOR = BOOLEAN_VALIDATOR;
+
/**
* The current night mode that has been selected by the user. Owned
* and controlled by UiModeManagerService. Constants are as per
@@ -6720,6 +6901,8 @@ public final class Settings {
*/
public static final String SCREENSAVER_ENABLED = "screensaver_enabled";
+ private static final Validator SCREENSAVER_ENABLED_VALIDATOR = BOOLEAN_VALIDATOR;
+
/**
* The user's chosen screensaver components.
*
@@ -6729,6 +6912,9 @@ public final class Settings {
*/
public static final String SCREENSAVER_COMPONENTS = "screensaver_components";
+ private static final Validator SCREENSAVER_COMPONENTS_VALIDATOR =
+ new SettingsValidators.ComponentNameListValidator(",");
+
/**
* If screensavers are enabled, whether the screensaver should be automatically launched
* when the device is inserted into a (desk) dock.
@@ -6736,6 +6922,8 @@ public final class Settings {
*/
public static final String SCREENSAVER_ACTIVATE_ON_DOCK = "screensaver_activate_on_dock";
+ private static final Validator SCREENSAVER_ACTIVATE_ON_DOCK_VALIDATOR = BOOLEAN_VALIDATOR;
+
/**
* If screensavers are enabled, whether the screensaver should be automatically launched
* when the screen times out when not on battery.
@@ -6743,6 +6931,8 @@ public final class Settings {
*/
public static final String SCREENSAVER_ACTIVATE_ON_SLEEP = "screensaver_activate_on_sleep";
+ private static final Validator SCREENSAVER_ACTIVATE_ON_SLEEP_VALIDATOR = BOOLEAN_VALIDATOR;
+
/**
* If screensavers are enabled, the default screensaver component.
* @hide
@@ -6755,6 +6945,9 @@ public final class Settings {
*/
public static final String NFC_PAYMENT_DEFAULT_COMPONENT = "nfc_payment_default_component";
+ private static final Validator NFC_PAYMENT_DEFAULT_COMPONENT_VALIDATOR =
+ COMPONENT_NAME_VALIDATOR;
+
/**
* Whether NFC payment is handled by the foreground application or a default.
* @hide
@@ -6852,6 +7045,9 @@ public final class Settings {
public static final String ENABLED_NOTIFICATION_ASSISTANT =
"enabled_notification_assistant";
+ private static final Validator ENABLED_NOTIFICATION_ASSISTANT_VALIDATOR =
+ new SettingsValidators.ComponentNameListValidator(":");
+
/**
* Read only list of the service components that the current user has explicitly allowed to
* see all of the user's notifications, separated by ':'.
@@ -6863,6 +7059,9 @@ public final class Settings {
@Deprecated
public static final String ENABLED_NOTIFICATION_LISTENERS = "enabled_notification_listeners";
+ private static final Validator ENABLED_NOTIFICATION_LISTENERS_VALIDATOR =
+ new SettingsValidators.ComponentNameListValidator(":");
+
/**
* Read only list of the packages that the current user has explicitly allowed to
* manage do not disturb, separated by ':'.
@@ -6875,6 +7074,9 @@ public final class Settings {
public static final String ENABLED_NOTIFICATION_POLICY_ACCESS_PACKAGES =
"enabled_notification_policy_access_packages";
+ private static final Validator ENABLED_NOTIFICATION_POLICY_ACCESS_PACKAGES_VALIDATOR =
+ new SettingsValidators.PackageNameListValidator(":");
+
/**
* Defines whether managed profile ringtones should be synced from it's parent profile
* <p>
@@ -6888,6 +7090,8 @@ public final class Settings {
@RequiresPermission(Manifest.permission.WRITE_SECURE_SETTINGS)
public static final String SYNC_PARENT_SOUNDS = "sync_parent_sounds";
+ private static final Validator SYNC_PARENT_SOUNDS_VALIDATOR = BOOLEAN_VALIDATOR;
+
/** @hide */
public static final String IMMERSIVE_MODE_CONFIRMATIONS = "immersive_mode_confirmations";
@@ -6974,12 +7178,17 @@ public final class Settings {
*/
public static final String SLEEP_TIMEOUT = "sleep_timeout";
+ private static final Validator SLEEP_TIMEOUT_VALIDATOR =
+ new SettingsValidators.InclusiveIntegerRangeValidator(-1, Integer.MAX_VALUE);
+
/**
* Controls whether double tap to wake is enabled.
* @hide
*/
public static final String DOUBLE_TAP_TO_WAKE = "double_tap_to_wake";
+ private static final Validator DOUBLE_TAP_TO_WAKE_VALIDATOR = BOOLEAN_VALIDATOR;
+
/**
* The current assistant component. It could be a voice interaction service,
* or an activity that handles ACTION_ASSIST, or empty which means using the default
@@ -6996,6 +7205,8 @@ public final class Settings {
*/
public static final String CAMERA_GESTURE_DISABLED = "camera_gesture_disabled";
+ private static final Validator CAMERA_GESTURE_DISABLED_VALIDATOR = BOOLEAN_VALIDATOR;
+
/**
* Whether the camera launch gesture to double tap the power button when the screen is off
* should be disabled.
@@ -7005,6 +7216,9 @@ public final class Settings {
public static final String CAMERA_DOUBLE_TAP_POWER_GESTURE_DISABLED =
"camera_double_tap_power_gesture_disabled";
+ private static final Validator CAMERA_DOUBLE_TAP_POWER_GESTURE_DISABLED_VALIDATOR =
+ BOOLEAN_VALIDATOR;
+
/**
* Whether the camera double twist gesture to flip between front and back mode should be
* enabled.
@@ -7014,6 +7228,9 @@ public final class Settings {
public static final String CAMERA_DOUBLE_TWIST_TO_FLIP_ENABLED =
"camera_double_twist_to_flip_enabled";
+ private static final Validator CAMERA_DOUBLE_TWIST_TO_FLIP_ENABLED_VALIDATOR =
+ BOOLEAN_VALIDATOR;
+
/**
* Whether or not the smart camera lift trigger that launches the camera when the user moves
* the phone into a position for taking photos should be enabled.
@@ -7036,6 +7253,9 @@ public final class Settings {
*/
public static final String ASSIST_GESTURE_ENABLED = "assist_gesture_enabled";
+ private static final Validator ASSIST_GESTURE_ENABLED_VALIDATOR =
+ BOOLEAN_VALIDATOR;
+
/**
* Sensitivity control for the assist gesture.
*
@@ -7043,6 +7263,9 @@ public final class Settings {
*/
public static final String ASSIST_GESTURE_SENSITIVITY = "assist_gesture_sensitivity";
+ private static final Validator ASSIST_GESTURE_SENSITIVITY_VALIDATOR =
+ new SettingsValidators.InclusiveFloatRangeValidator(0.0f, 1.0f);
+
/**
* Whether the assist gesture should silence alerts.
*
@@ -7051,6 +7274,9 @@ public final class Settings {
public static final String ASSIST_GESTURE_SILENCE_ALERTS_ENABLED =
"assist_gesture_silence_alerts_enabled";
+ private static final Validator ASSIST_GESTURE_SILENCE_ALERTS_ENABLED_VALIDATOR =
+ BOOLEAN_VALIDATOR;
+
/**
* Whether the assist gesture should wake the phone.
*
@@ -7059,6 +7285,9 @@ public final class Settings {
public static final String ASSIST_GESTURE_WAKE_ENABLED =
"assist_gesture_wake_enabled";
+ private static final Validator ASSIST_GESTURE_WAKE_ENABLED_VALIDATOR =
+ BOOLEAN_VALIDATOR;
+
/**
* Whether Assist Gesture Deferred Setup has been completed
*
@@ -7066,6 +7295,8 @@ public final class Settings {
*/
public static final String ASSIST_GESTURE_SETUP_COMPLETE = "assist_gesture_setup_complete";
+ private static final Validator ASSIST_GESTURE_SETUP_COMPLETE_VALIDATOR = BOOLEAN_VALIDATOR;
+
/**
* Control whether Night display is currently activated.
* @hide
@@ -7078,6 +7309,8 @@ public final class Settings {
*/
public static final String NIGHT_DISPLAY_AUTO_MODE = "night_display_auto_mode";
+ private static final Validator NIGHT_DISPLAY_AUTO_MODE_VALIDATOR = BOOLEAN_VALIDATOR;
+
/**
* Control the color temperature of Night Display, represented in Kelvin.
* @hide
@@ -7085,6 +7318,9 @@ public final class Settings {
public static final String NIGHT_DISPLAY_COLOR_TEMPERATURE =
"night_display_color_temperature";
+ private static final Validator NIGHT_DISPLAY_COLOR_TEMPERATURE_VALIDATOR =
+ NON_NEGATIVE_INTEGER_VALIDATOR;
+
/**
* Custom time when Night display is scheduled to activate.
* Represented as milliseconds from midnight (e.g. 79200000 == 10pm).
@@ -7093,6 +7329,9 @@ public final class Settings {
public static final String NIGHT_DISPLAY_CUSTOM_START_TIME =
"night_display_custom_start_time";
+ private static final Validator NIGHT_DISPLAY_CUSTOM_START_TIME_VALIDATOR =
+ NON_NEGATIVE_INTEGER_VALIDATOR;
+
/**
* Custom time when Night display is scheduled to deactivate.
* Represented as milliseconds from midnight (e.g. 21600000 == 6am).
@@ -7100,6 +7339,9 @@ public final class Settings {
*/
public static final String NIGHT_DISPLAY_CUSTOM_END_TIME = "night_display_custom_end_time";
+ private static final Validator NIGHT_DISPLAY_CUSTOM_END_TIME_VALIDATOR =
+ NON_NEGATIVE_INTEGER_VALIDATOR;
+
/**
* A String representing the LocalDateTime when Night display was last activated. Use to
* decide whether to apply the current activated state after a reboot or user change. In
@@ -7117,6 +7359,9 @@ public final class Settings {
*/
public static final String ENABLED_VR_LISTENERS = "enabled_vr_listeners";
+ private static final Validator ENABLED_VR_LISTENERS_VALIDATOR =
+ new SettingsValidators.ComponentNameListValidator(":");
+
/**
* Behavior of the display while in VR mode.
*
@@ -7126,6 +7371,9 @@ public final class Settings {
*/
public static final String VR_DISPLAY_MODE = "vr_display_mode";
+ private static final Validator VR_DISPLAY_MODE_VALIDATOR =
+ new SettingsValidators.DiscreteValueValidator(new String[]{"0", "1"});
+
/**
* Lower the display persistence while the system is in VR mode.
*
@@ -7182,6 +7430,9 @@ public final class Settings {
public static final String AUTOMATIC_STORAGE_MANAGER_DAYS_TO_RETAIN =
"automatic_storage_manager_days_to_retain";
+ private static final Validator AUTOMATIC_STORAGE_MANAGER_DAYS_TO_RETAIN_VALIDATOR =
+ NON_NEGATIVE_INTEGER_VALIDATOR;
+
/**
* Default number of days of information for the automatic storage manager to retain.
*
@@ -7223,12 +7474,30 @@ public final class Settings {
public static final String SYSTEM_NAVIGATION_KEYS_ENABLED =
"system_navigation_keys_enabled";
+ private static final Validator SYSTEM_NAVIGATION_KEYS_ENABLED_VALIDATOR = BOOLEAN_VALIDATOR;
+
/**
* Holds comma separated list of ordering of QS tiles.
* @hide
*/
public static final String QS_TILES = "sysui_qs_tiles";
+ private static final Validator QS_TILES_VALIDATOR = new Validator() {
+ @Override
+ public boolean validate(String value) {
+ if (value == null) {
+ return false;
+ }
+ String[] tiles = value.split(",");
+ boolean valid = true;
+ for (String tile : tiles) {
+ // tile can be any non-empty string as specified by OEM
+ valid |= ((tile.length() > 0) && ANY_STRING_VALIDATOR.validate(tile));
+ }
+ return valid;
+ }
+ };
+
/**
* Specifies whether the web action API is enabled.
*
@@ -7264,18 +7533,38 @@ public final class Settings {
*/
public static final String NOTIFICATION_BADGING = "notification_badging";
+ private static final Validator NOTIFICATION_BADGING_VALIDATOR = BOOLEAN_VALIDATOR;
+
/**
* Comma separated list of QS tiles that have been auto-added already.
* @hide
*/
public static final String QS_AUTO_ADDED_TILES = "qs_auto_tiles";
+ private static final Validator QS_AUTO_ADDED_TILES_VALIDATOR = new Validator() {
+ @Override
+ public boolean validate(String value) {
+ if (value == null) {
+ return false;
+ }
+ String[] tiles = value.split(",");
+ boolean valid = true;
+ for (String tile : tiles) {
+ // tile can be any non-empty string as specified by OEM
+ valid |= ((tile.length() > 0) && ANY_STRING_VALIDATOR.validate(tile));
+ }
+ return valid;
+ }
+ };
+
/**
* Whether the Lockdown button should be shown in the power menu.
* @hide
*/
public static final String LOCKDOWN_IN_POWER_MENU = "lockdown_in_power_menu";
+ private static final Validator LOCKDOWN_IN_POWER_MENU_VALIDATOR = BOOLEAN_VALIDATOR;
+
/**
* Backup manager behavioral parameters.
* This is encoded as a key=value list, separated by commas. Ex:
@@ -7315,8 +7604,6 @@ public final class Settings {
public static final String[] SETTINGS_TO_BACKUP = {
BUGREPORT_IN_POWER_MENU, // moved to global
ALLOW_MOCK_LOCATION,
- PARENTAL_CONTROL_ENABLED,
- PARENTAL_CONTROL_REDIRECT_URL,
USB_MASS_STORAGE_ENABLED, // moved to global
ACCESSIBILITY_DISPLAY_INVERSION_ENABLED,
ACCESSIBILITY_DISPLAY_DALTONIZER,
@@ -7348,12 +7635,9 @@ public final class Settings {
ACCESSIBILITY_CAPTIONING_TYPEFACE,
ACCESSIBILITY_CAPTIONING_FONT_SCALE,
ACCESSIBILITY_CAPTIONING_WINDOW_COLOR,
- TTS_USE_DEFAULTS,
TTS_DEFAULT_RATE,
TTS_DEFAULT_PITCH,
TTS_DEFAULT_SYNTH,
- TTS_DEFAULT_LANG,
- TTS_DEFAULT_COUNTRY,
TTS_ENABLED_PLUGINS,
TTS_DEFAULT_LOCALE,
SHOW_IME_WITH_HARD_KEYBOARD,
@@ -7409,7 +7693,158 @@ public final class Settings {
SHOW_FIRST_CRASH_DIALOG_DEV_OPTION,
};
- /** @hide */
+ /**
+ * All settings in {@link SETTINGS_TO_BACKUP} array *must* have a non-null validator,
+ * otherwise they won't be restored.
+ *
+ * @hide
+ */
+ public static final Map<String, Validator> VALIDATORS = new ArrayMap<>();
+ static {
+ VALIDATORS.put(BUGREPORT_IN_POWER_MENU, BUGREPORT_IN_POWER_MENU_VALIDATOR);
+ VALIDATORS.put(ALLOW_MOCK_LOCATION, ALLOW_MOCK_LOCATION_VALIDATOR);
+ VALIDATORS.put(USB_MASS_STORAGE_ENABLED, USB_MASS_STORAGE_ENABLED_VALIDATOR);
+ VALIDATORS.put(ACCESSIBILITY_DISPLAY_INVERSION_ENABLED,
+ ACCESSIBILITY_DISPLAY_INVERSION_ENABLED_VALIDATOR);
+ VALIDATORS.put(ACCESSIBILITY_DISPLAY_DALTONIZER,
+ ACCESSIBILITY_DISPLAY_DALTONIZER_VALIDATOR);
+ VALIDATORS.put(ACCESSIBILITY_DISPLAY_DALTONIZER_ENABLED,
+ ACCESSIBILITY_DISPLAY_DALTONIZER_ENABLED_VALIDATOR);
+ VALIDATORS.put(ACCESSIBILITY_DISPLAY_MAGNIFICATION_ENABLED,
+ ACCESSIBILITY_DISPLAY_MAGNIFICATION_ENABLED_VALIDATOR);
+ VALIDATORS.put(ACCESSIBILITY_DISPLAY_MAGNIFICATION_NAVBAR_ENABLED,
+ ACCESSIBILITY_DISPLAY_MAGNIFICATION_NAVBAR_ENABLED_VALIDATOR);
+ VALIDATORS.put(AUTOFILL_SERVICE, AUTOFILL_SERVICE_VALIDATOR);
+ VALIDATORS.put(ACCESSIBILITY_DISPLAY_MAGNIFICATION_SCALE,
+ ACCESSIBILITY_DISPLAY_MAGNIFICATION_SCALE_VALIDATOR);
+ VALIDATORS.put(ENABLED_ACCESSIBILITY_SERVICES,
+ ENABLED_ACCESSIBILITY_SERVICES_VALIDATOR);
+ VALIDATORS.put(ENABLED_VR_LISTENERS, ENABLED_VR_LISTENERS_VALIDATOR);
+ VALIDATORS.put(ENABLED_INPUT_METHODS, ENABLED_INPUT_METHODS_VALIDATOR);
+ VALIDATORS.put(TOUCH_EXPLORATION_GRANTED_ACCESSIBILITY_SERVICES,
+ TOUCH_EXPLORATION_GRANTED_ACCESSIBILITY_SERVICES_VALIDATOR);
+ VALIDATORS.put(TOUCH_EXPLORATION_ENABLED, TOUCH_EXPLORATION_ENABLED_VALIDATOR);
+ VALIDATORS.put(ACCESSIBILITY_ENABLED, ACCESSIBILITY_ENABLED_VALIDATOR);
+ VALIDATORS.put(ACCESSIBILITY_SHORTCUT_TARGET_SERVICE,
+ ACCESSIBILITY_SHORTCUT_TARGET_SERVICE_VALIDATOR);
+ VALIDATORS.put(ACCESSIBILITY_BUTTON_TARGET_COMPONENT,
+ ACCESSIBILITY_BUTTON_TARGET_COMPONENT_VALIDATOR);
+ VALIDATORS.put(ACCESSIBILITY_SHORTCUT_DIALOG_SHOWN,
+ ACCESSIBILITY_SHORTCUT_DIALOG_SHOWN_VALIDATOR);
+ VALIDATORS.put(ACCESSIBILITY_SHORTCUT_ENABLED,
+ ACCESSIBILITY_SHORTCUT_ENABLED_VALIDATOR);
+ VALIDATORS.put(ACCESSIBILITY_SHORTCUT_ON_LOCK_SCREEN,
+ ACCESSIBILITY_SHORTCUT_ON_LOCK_SCREEN_VALIDATOR);
+ VALIDATORS.put(ACCESSIBILITY_SPEAK_PASSWORD, ACCESSIBILITY_SPEAK_PASSWORD_VALIDATOR);
+ VALIDATORS.put(ACCESSIBILITY_HIGH_TEXT_CONTRAST_ENABLED,
+ ACCESSIBILITY_HIGH_TEXT_CONTRAST_ENABLED_VALIDATOR);
+ VALIDATORS.put(ACCESSIBILITY_CAPTIONING_PRESET,
+ ACCESSIBILITY_CAPTIONING_PRESET_VALIDATOR);
+ VALIDATORS.put(ACCESSIBILITY_CAPTIONING_ENABLED,
+ ACCESSIBILITY_CAPTIONING_ENABLED_VALIDATOR);
+ VALIDATORS.put(ACCESSIBILITY_CAPTIONING_LOCALE,
+ ACCESSIBILITY_CAPTIONING_LOCALE_VALIDATOR);
+ VALIDATORS.put(ACCESSIBILITY_CAPTIONING_BACKGROUND_COLOR,
+ ACCESSIBILITY_CAPTIONING_BACKGROUND_COLOR_VALIDATOR);
+ VALIDATORS.put(ACCESSIBILITY_CAPTIONING_FOREGROUND_COLOR,
+ ACCESSIBILITY_CAPTIONING_FOREGROUND_COLOR_VALIDATOR);
+ VALIDATORS.put(ACCESSIBILITY_CAPTIONING_EDGE_TYPE,
+ ACCESSIBILITY_CAPTIONING_EDGE_TYPE_VALIDATOR);
+ VALIDATORS.put(ACCESSIBILITY_CAPTIONING_EDGE_COLOR,
+ ACCESSIBILITY_CAPTIONING_EDGE_COLOR_VALIDATOR);
+ VALIDATORS.put(ACCESSIBILITY_CAPTIONING_TYPEFACE,
+ ACCESSIBILITY_CAPTIONING_TYPEFACE_VALIDATOR);
+ VALIDATORS.put(ACCESSIBILITY_CAPTIONING_FONT_SCALE,
+ ACCESSIBILITY_CAPTIONING_FONT_SCALE_VALIDATOR);
+ VALIDATORS.put(ACCESSIBILITY_CAPTIONING_WINDOW_COLOR,
+ ACCESSIBILITY_CAPTIONING_WINDOW_COLOR_VALIDATOR);
+ VALIDATORS.put(TTS_DEFAULT_RATE, TTS_DEFAULT_RATE_VALIDATOR);
+ VALIDATORS.put(TTS_DEFAULT_PITCH, TTS_DEFAULT_PITCH_VALIDATOR);
+ VALIDATORS.put(TTS_DEFAULT_SYNTH, TTS_DEFAULT_SYNTH_VALIDATOR);
+ VALIDATORS.put(TTS_ENABLED_PLUGINS, TTS_ENABLED_PLUGINS_VALIDATOR);
+ VALIDATORS.put(TTS_DEFAULT_LOCALE, TTS_DEFAULT_LOCALE_VALIDATOR);
+ VALIDATORS.put(SHOW_IME_WITH_HARD_KEYBOARD, SHOW_IME_WITH_HARD_KEYBOARD_VALIDATOR);
+ VALIDATORS.put(WIFI_NETWORKS_AVAILABLE_NOTIFICATION_ON,
+ WIFI_NETWORKS_AVAILABLE_NOTIFICATION_ON_VALIDATOR);
+ VALIDATORS.put(WIFI_NETWORKS_AVAILABLE_REPEAT_DELAY,
+ WIFI_NETWORKS_AVAILABLE_REPEAT_DELAY_VALIDATOR);
+ VALIDATORS.put(WIFI_NUM_OPEN_NETWORKS_KEPT, WIFI_NUM_OPEN_NETWORKS_KEPT_VALIDATOR);
+ VALIDATORS.put(SELECTED_SPELL_CHECKER, SELECTED_SPELL_CHECKER_VALIDATOR);
+ VALIDATORS.put(SELECTED_SPELL_CHECKER_SUBTYPE,
+ SELECTED_SPELL_CHECKER_SUBTYPE_VALIDATOR);
+ VALIDATORS.put(SPELL_CHECKER_ENABLED, SPELL_CHECKER_ENABLED_VALIDATOR);
+ VALIDATORS.put(MOUNT_PLAY_NOTIFICATION_SND, MOUNT_PLAY_NOTIFICATION_SND_VALIDATOR);
+ VALIDATORS.put(MOUNT_UMS_AUTOSTART, MOUNT_UMS_AUTOSTART_VALIDATOR);
+ VALIDATORS.put(MOUNT_UMS_PROMPT, MOUNT_UMS_PROMPT_VALIDATOR);
+ VALIDATORS.put(MOUNT_UMS_NOTIFY_ENABLED, MOUNT_UMS_NOTIFY_ENABLED_VALIDATOR);
+ VALIDATORS.put(SLEEP_TIMEOUT, SLEEP_TIMEOUT_VALIDATOR);
+ VALIDATORS.put(DOUBLE_TAP_TO_WAKE, DOUBLE_TAP_TO_WAKE_VALIDATOR);
+ VALIDATORS.put(WAKE_GESTURE_ENABLED, WAKE_GESTURE_ENABLED_VALIDATOR);
+ VALIDATORS.put(LONG_PRESS_TIMEOUT, LONG_PRESS_TIMEOUT_VALIDATOR);
+ VALIDATORS.put(CAMERA_GESTURE_DISABLED, CAMERA_GESTURE_DISABLED_VALIDATOR);
+ VALIDATORS.put(ACCESSIBILITY_AUTOCLICK_ENABLED,
+ ACCESSIBILITY_AUTOCLICK_ENABLED_VALIDATOR);
+ VALIDATORS.put(ACCESSIBILITY_AUTOCLICK_DELAY, ACCESSIBILITY_AUTOCLICK_DELAY_VALIDATOR);
+ VALIDATORS.put(ACCESSIBILITY_LARGE_POINTER_ICON,
+ ACCESSIBILITY_LARGE_POINTER_ICON_VALIDATOR);
+ VALIDATORS.put(PREFERRED_TTY_MODE, PREFERRED_TTY_MODE_VALIDATOR);
+ VALIDATORS.put(ENHANCED_VOICE_PRIVACY_ENABLED,
+ ENHANCED_VOICE_PRIVACY_ENABLED_VALIDATOR);
+ VALIDATORS.put(TTY_MODE_ENABLED, TTY_MODE_ENABLED_VALIDATOR);
+ VALIDATORS.put(INCALL_POWER_BUTTON_BEHAVIOR, INCALL_POWER_BUTTON_BEHAVIOR_VALIDATOR);
+ VALIDATORS.put(NIGHT_DISPLAY_CUSTOM_START_TIME,
+ NIGHT_DISPLAY_CUSTOM_START_TIME_VALIDATOR);
+ VALIDATORS.put(NIGHT_DISPLAY_CUSTOM_END_TIME, NIGHT_DISPLAY_CUSTOM_END_TIME_VALIDATOR);
+ VALIDATORS.put(NIGHT_DISPLAY_COLOR_TEMPERATURE,
+ NIGHT_DISPLAY_COLOR_TEMPERATURE_VALIDATOR);
+ VALIDATORS.put(NIGHT_DISPLAY_AUTO_MODE, NIGHT_DISPLAY_AUTO_MODE_VALIDATOR);
+ VALIDATORS.put(SYNC_PARENT_SOUNDS, SYNC_PARENT_SOUNDS_VALIDATOR);
+ VALIDATORS.put(CAMERA_DOUBLE_TWIST_TO_FLIP_ENABLED,
+ CAMERA_DOUBLE_TWIST_TO_FLIP_ENABLED_VALIDATOR);
+ VALIDATORS.put(CAMERA_DOUBLE_TAP_POWER_GESTURE_DISABLED,
+ CAMERA_DOUBLE_TAP_POWER_GESTURE_DISABLED_VALIDATOR);
+ VALIDATORS.put(SYSTEM_NAVIGATION_KEYS_ENABLED,
+ SYSTEM_NAVIGATION_KEYS_ENABLED_VALIDATOR);
+ VALIDATORS.put(QS_TILES, QS_TILES_VALIDATOR);
+ VALIDATORS.put(DOZE_ENABLED, DOZE_ENABLED_VALIDATOR);
+ VALIDATORS.put(DOZE_PULSE_ON_PICK_UP, DOZE_PULSE_ON_PICK_UP_VALIDATOR);
+ VALIDATORS.put(DOZE_PULSE_ON_DOUBLE_TAP, DOZE_PULSE_ON_DOUBLE_TAP_VALIDATOR);
+ VALIDATORS.put(NFC_PAYMENT_DEFAULT_COMPONENT, NFC_PAYMENT_DEFAULT_COMPONENT_VALIDATOR);
+ VALIDATORS.put(AUTOMATIC_STORAGE_MANAGER_DAYS_TO_RETAIN,
+ AUTOMATIC_STORAGE_MANAGER_DAYS_TO_RETAIN_VALIDATOR);
+ VALIDATORS.put(ASSIST_GESTURE_ENABLED, ASSIST_GESTURE_ENABLED_VALIDATOR);
+ VALIDATORS.put(ASSIST_GESTURE_SENSITIVITY, ASSIST_GESTURE_SENSITIVITY_VALIDATOR);
+ VALIDATORS.put(ASSIST_GESTURE_SETUP_COMPLETE, ASSIST_GESTURE_SETUP_COMPLETE_VALIDATOR);
+ VALIDATORS.put(ASSIST_GESTURE_SILENCE_ALERTS_ENABLED,
+ ASSIST_GESTURE_SILENCE_ALERTS_ENABLED_VALIDATOR);
+ VALIDATORS.put(ASSIST_GESTURE_WAKE_ENABLED, ASSIST_GESTURE_WAKE_ENABLED_VALIDATOR);
+ VALIDATORS.put(VR_DISPLAY_MODE, VR_DISPLAY_MODE_VALIDATOR);
+ VALIDATORS.put(NOTIFICATION_BADGING, NOTIFICATION_BADGING_VALIDATOR);
+ VALIDATORS.put(QS_AUTO_ADDED_TILES, QS_AUTO_ADDED_TILES_VALIDATOR);
+ VALIDATORS.put(SCREENSAVER_ENABLED, SCREENSAVER_ENABLED_VALIDATOR);
+ VALIDATORS.put(SCREENSAVER_COMPONENTS, SCREENSAVER_COMPONENTS_VALIDATOR);
+ VALIDATORS.put(SCREENSAVER_ACTIVATE_ON_DOCK, SCREENSAVER_ACTIVATE_ON_DOCK_VALIDATOR);
+ VALIDATORS.put(SCREENSAVER_ACTIVATE_ON_SLEEP, SCREENSAVER_ACTIVATE_ON_SLEEP_VALIDATOR);
+ VALIDATORS.put(LOCKDOWN_IN_POWER_MENU, LOCKDOWN_IN_POWER_MENU_VALIDATOR);
+ VALIDATORS.put(SHOW_FIRST_CRASH_DIALOG_DEV_OPTION,
+ SHOW_FIRST_CRASH_DIALOG_DEV_OPTION_VALIDATOR);
+ VALIDATORS.put(ENABLED_NOTIFICATION_LISTENERS,
+ ENABLED_NOTIFICATION_LISTENERS_VALIDATOR); //legacy restore setting
+ VALIDATORS.put(ENABLED_NOTIFICATION_ASSISTANT,
+ ENABLED_NOTIFICATION_ASSISTANT_VALIDATOR); //legacy restore setting
+ VALIDATORS.put(ENABLED_NOTIFICATION_POLICY_ACCESS_PACKAGES,
+ ENABLED_NOTIFICATION_POLICY_ACCESS_PACKAGES_VALIDATOR); //legacy restore setting
+ }
+
+ /**
+ * Keys we no longer back up under the current schema, but want to continue to
+ * process when restoring historical backup datasets.
+ *
+ * All settings in {@link LEGACY_RESTORE_SETTINGS} array *must* have a non-null validator,
+ * otherwise they won't be restored.
+ *
+ * @hide
+ */
public static final String[] LEGACY_RESTORE_SETTINGS = {
ENABLED_NOTIFICATION_LISTENERS,
ENABLED_NOTIFICATION_ASSISTANT,
@@ -7805,12 +8240,16 @@ public final class Settings {
*/
public static final String AUTO_TIME = "auto_time";
+ private static final Validator AUTO_TIME_VALIDATOR = BOOLEAN_VALIDATOR;
+
/**
* Value to specify if the user prefers the time zone
* to be automatically fetched from the network (NITZ). 1=yes, 0=no
*/
public static final String AUTO_TIME_ZONE = "auto_time_zone";
+ private static final Validator AUTO_TIME_ZONE_VALIDATOR = BOOLEAN_VALIDATOR;
+
/**
* URI for the car dock "in" event sound.
* @hide
@@ -7841,6 +8280,8 @@ public final class Settings {
*/
public static final String DOCK_SOUNDS_ENABLED = "dock_sounds_enabled";
+ private static final Validator DOCK_SOUNDS_ENABLED_VALIDATOR = BOOLEAN_VALIDATOR;
+
/**
* Whether to play a sound for dock events, only when an accessibility service is on.
* @hide
@@ -7878,6 +8319,8 @@ public final class Settings {
*/
public static final String POWER_SOUNDS_ENABLED = "power_sounds_enabled";
+ private static final Validator POWER_SOUNDS_ENABLED_VALIDATOR = BOOLEAN_VALIDATOR;
+
/**
* URI for the "wireless charging started" sound.
* @hide
@@ -7891,6 +8334,8 @@ public final class Settings {
*/
public static final String CHARGING_SOUNDS_ENABLED = "charging_sounds_enabled";
+ private static final Validator CHARGING_SOUNDS_ENABLED_VALIDATOR = BOOLEAN_VALIDATOR;
+
/**
* Whether we keep the device on while the device is plugged in.
* Supported values are:
@@ -7904,6 +8349,30 @@ public final class Settings {
*/
public static final String STAY_ON_WHILE_PLUGGED_IN = "stay_on_while_plugged_in";
+ private static final Validator STAY_ON_WHILE_PLUGGED_IN_VALIDATOR = new Validator() {
+ @Override
+ public boolean validate(String value) {
+ try {
+ int val = Integer.parseInt(value);
+ return (val == 0)
+ || (val == BatteryManager.BATTERY_PLUGGED_AC)
+ || (val == BatteryManager.BATTERY_PLUGGED_USB)
+ || (val == BatteryManager.BATTERY_PLUGGED_WIRELESS)
+ || (val == (BatteryManager.BATTERY_PLUGGED_AC
+ | BatteryManager.BATTERY_PLUGGED_USB))
+ || (val == (BatteryManager.BATTERY_PLUGGED_AC
+ | BatteryManager.BATTERY_PLUGGED_WIRELESS))
+ || (val == (BatteryManager.BATTERY_PLUGGED_USB
+ | BatteryManager.BATTERY_PLUGGED_WIRELESS))
+ || (val == (BatteryManager.BATTERY_PLUGGED_AC
+ | BatteryManager.BATTERY_PLUGGED_USB
+ | BatteryManager.BATTERY_PLUGGED_WIRELESS));
+ } catch (NumberFormatException e) {
+ return false;
+ }
+ }
+ };
+
/**
* When the user has enable the option to have a "bug report" command
* in the power menu.
@@ -7911,6 +8380,8 @@ public final class Settings {
*/
public static final String BUGREPORT_IN_POWER_MENU = "bugreport_in_power_menu";
+ private static final Validator BUGREPORT_IN_POWER_MENU_VALIDATOR = BOOLEAN_VALIDATOR;
+
/**
* Whether ADB is enabled.
*/
@@ -7934,6 +8405,8 @@ public final class Settings {
*/
public static final String BLUETOOTH_ON = "bluetooth_on";
+ private static final Validator BLUETOOTH_ON_VALIDATOR = BOOLEAN_VALIDATOR;
+
/**
* CDMA Cell Broadcast SMS
* 0 = CDMA Cell Broadcast SMS disabled
@@ -8552,6 +9025,8 @@ public final class Settings {
*/
public static final String USB_MASS_STORAGE_ENABLED = "usb_mass_storage_enabled";
+ private static final Validator USB_MASS_STORAGE_ENABLED_VALIDATOR = BOOLEAN_VALIDATOR;
+
/**
* If this setting is set (to anything), then all references
* to Gmail on the device must change to Google Mail.
@@ -8688,6 +9163,9 @@ public final class Settings {
public static final String WIFI_NETWORKS_AVAILABLE_NOTIFICATION_ON =
"wifi_networks_available_notification_on";
+ private static final Validator WIFI_NETWORKS_AVAILABLE_NOTIFICATION_ON_VALIDATOR =
+ BOOLEAN_VALIDATOR;
+
/**
* {@hide}
*/
@@ -8701,6 +9179,9 @@ public final class Settings {
public static final String WIFI_NETWORKS_AVAILABLE_REPEAT_DELAY =
"wifi_networks_available_repeat_delay";
+ private static final Validator WIFI_NETWORKS_AVAILABLE_REPEAT_DELAY_VALIDATOR =
+ NON_NEGATIVE_INTEGER_VALIDATOR;
+
/**
* 802.11 country code in ISO 3166 format
* @hide
@@ -8730,6 +9211,9 @@ public final class Settings {
*/
public static final String WIFI_NUM_OPEN_NETWORKS_KEPT = "wifi_num_open_networks_kept";
+ private static final Validator WIFI_NUM_OPEN_NETWORKS_KEPT_VALIDATOR =
+ NON_NEGATIVE_INTEGER_VALIDATOR;
+
/**
* Whether the Wi-Fi should be on. Only the Wi-Fi service should touch this.
*/
@@ -8750,6 +9234,8 @@ public final class Settings {
*/
public static final String SOFT_AP_TIMEOUT_ENABLED = "soft_ap_timeout_enabled";
+ private static final Validator SOFT_AP_TIMEOUT_ENABLED_VALIDATOR = BOOLEAN_VALIDATOR;
+
/**
* Value to specify if Wi-Fi Wakeup feature is enabled.
*
@@ -8759,6 +9245,8 @@ public final class Settings {
@SystemApi
public static final String WIFI_WAKEUP_ENABLED = "wifi_wakeup_enabled";
+ private static final Validator WIFI_WAKEUP_ENABLED_VALIDATOR = BOOLEAN_VALIDATOR;
+
/**
* Value to specify if Wi-Fi Wakeup is available.
*
@@ -8805,6 +9293,9 @@ public final class Settings {
public static final String NETWORK_RECOMMENDATIONS_ENABLED =
"network_recommendations_enabled";
+ private static final Validator NETWORK_RECOMMENDATIONS_ENABLED_VALIDATOR =
+ new SettingsValidators.DiscreteValueValidator(new String[] {"-1", "0", "1"});
+
/**
* Which package name to use for network recommendations. If null, network recommendations
* will neither be requested nor accepted.
@@ -8828,6 +9319,13 @@ public final class Settings {
@TestApi
public static final String USE_OPEN_WIFI_PACKAGE = "use_open_wifi_package";
+ private static final Validator USE_OPEN_WIFI_PACKAGE_VALIDATOR = new Validator() {
+ @Override
+ public boolean validate(String value) {
+ return (value == null) || PACKAGE_NAME_VALIDATOR.validate(value);
+ }
+ };
+
/**
* The number of milliseconds the {@link com.android.server.NetworkScoreService}
* will give a recommendation request to complete before returning a default response.
@@ -8907,6 +9405,9 @@ public final class Settings {
public static final String WIFI_WATCHDOG_POOR_NETWORK_TEST_ENABLED =
"wifi_watchdog_poor_network_test_enabled";
+ private static final Validator WIFI_WATCHDOG_POOR_NETWORK_TEST_ENABLED_VALIDATOR =
+ ANY_STRING_VALIDATOR;
+
/**
* Setting to turn on suspend optimizations at screen off on Wi-Fi. Enabled by default and
* needs to be set to 0 to disable it.
@@ -9442,11 +9943,16 @@ public final class Settings {
* @hide
*/
public static final String PRIVATE_DNS_MODE = "private_dns_mode";
+
+ private static final Validator PRIVATE_DNS_MODE_VALIDATOR = ANY_STRING_VALIDATOR;
+
/**
* @hide
*/
public static final String PRIVATE_DNS_SPECIFIER = "private_dns_specifier";
+ private static final Validator PRIVATE_DNS_SPECIFIER_VALIDATOR = ANY_STRING_VALIDATOR;
+
/** {@hide} */
public static final String
BLUETOOTH_HEADSET_PRIORITY_PREFIX = "bluetooth_headset_priority_";
@@ -9673,6 +10179,14 @@ public final class Settings {
public static final String SYS_VDSO = "sys_vdso";
/**
+ * An integer to reduce the FPS by this factor. Only for experiments. Need to reboot the
+ * device for this setting to take full effect.
+ *
+ * @hide
+ */
+ public static final String FPS_DEVISOR = "fps_divisor";
+
+ /**
* App standby (app idle) specific settings.
* This is encoded as a key=value list, separated by commas. Ex:
* <p>
@@ -10011,6 +10525,9 @@ public final class Settings {
*/
public static final String EMERGENCY_TONE = "emergency_tone";
+ private static final Validator EMERGENCY_TONE_VALIDATOR =
+ new SettingsValidators.DiscreteValueValidator(new String[] {"0", "1", "2"});
+
/**
* CDMA only settings
* Whether the auto retry is enabled. The value is
@@ -10019,6 +10536,8 @@ public final class Settings {
*/
public static final String CALL_AUTO_RETRY = "call_auto_retry";
+ private static final Validator CALL_AUTO_RETRY_VALIDATOR = BOOLEAN_VALIDATOR;
+
/**
* A setting that can be read whether the emergency affordance is currently needed.
* The value is a boolean (1 or 0).
@@ -10088,6 +10607,9 @@ public final class Settings {
*/
public static final String LOW_POWER_MODE_TRIGGER_LEVEL = "low_power_trigger_level";
+ private static final Validator LOW_POWER_MODE_TRIGGER_LEVEL_VALIDATOR =
+ new SettingsValidators.InclusiveIntegerRangeValidator(0, 99);
+
/**
* If not 0, the activity manager will aggressively finish activities and
* processes as soon as they are no longer needed. If 0, the normal
@@ -10103,6 +10625,8 @@ public final class Settings {
*/
public static final String DOCK_AUDIO_MEDIA_ENABLED = "dock_audio_media_enabled";
+ private static final Validator DOCK_AUDIO_MEDIA_ENABLED_VALIDATOR = BOOLEAN_VALIDATOR;
+
/**
* The surround sound formats AC3, DTS or IEC61937 are
* available for use if they are detected.
@@ -10149,6 +10673,9 @@ public final class Settings {
*/
public static final String ENCODED_SURROUND_OUTPUT = "encoded_surround_output";
+ private static final Validator ENCODED_SURROUND_OUTPUT_VALIDATOR =
+ new SettingsValidators.DiscreteValueValidator(new String[] {"0", "1", "2"});
+
/**
* Persisted safe headphone volume management state by AudioService
* @hide
@@ -10689,6 +11216,41 @@ public final class Settings {
};
/**
+ * All settings in {@link SETTINGS_TO_BACKUP} array *must* have a non-null validator,
+ * otherwise they won't be restored.
+ *
+ * @hide
+ */
+ public static final Map<String, Validator> VALIDATORS = new ArrayMap<>();
+ static {
+ VALIDATORS.put(BUGREPORT_IN_POWER_MENU, BUGREPORT_IN_POWER_MENU_VALIDATOR);
+ VALIDATORS.put(STAY_ON_WHILE_PLUGGED_IN, STAY_ON_WHILE_PLUGGED_IN_VALIDATOR);
+ VALIDATORS.put(AUTO_TIME, AUTO_TIME_VALIDATOR);
+ VALIDATORS.put(AUTO_TIME_ZONE, AUTO_TIME_ZONE_VALIDATOR);
+ VALIDATORS.put(POWER_SOUNDS_ENABLED, POWER_SOUNDS_ENABLED_VALIDATOR);
+ VALIDATORS.put(DOCK_SOUNDS_ENABLED, DOCK_SOUNDS_ENABLED_VALIDATOR);
+ VALIDATORS.put(CHARGING_SOUNDS_ENABLED, CHARGING_SOUNDS_ENABLED_VALIDATOR);
+ VALIDATORS.put(USB_MASS_STORAGE_ENABLED, USB_MASS_STORAGE_ENABLED_VALIDATOR);
+ VALIDATORS.put(NETWORK_RECOMMENDATIONS_ENABLED,
+ NETWORK_RECOMMENDATIONS_ENABLED_VALIDATOR);
+ VALIDATORS.put(WIFI_WAKEUP_ENABLED, WIFI_WAKEUP_ENABLED_VALIDATOR);
+ VALIDATORS.put(WIFI_NETWORKS_AVAILABLE_NOTIFICATION_ON,
+ WIFI_NETWORKS_AVAILABLE_NOTIFICATION_ON_VALIDATOR);
+ VALIDATORS.put(USE_OPEN_WIFI_PACKAGE, USE_OPEN_WIFI_PACKAGE_VALIDATOR);
+ VALIDATORS.put(WIFI_WATCHDOG_POOR_NETWORK_TEST_ENABLED,
+ WIFI_WATCHDOG_POOR_NETWORK_TEST_ENABLED_VALIDATOR);
+ VALIDATORS.put(EMERGENCY_TONE, EMERGENCY_TONE_VALIDATOR);
+ VALIDATORS.put(CALL_AUTO_RETRY, CALL_AUTO_RETRY_VALIDATOR);
+ VALIDATORS.put(DOCK_AUDIO_MEDIA_ENABLED, DOCK_AUDIO_MEDIA_ENABLED_VALIDATOR);
+ VALIDATORS.put(ENCODED_SURROUND_OUTPUT, ENCODED_SURROUND_OUTPUT_VALIDATOR);
+ VALIDATORS.put(LOW_POWER_MODE_TRIGGER_LEVEL, LOW_POWER_MODE_TRIGGER_LEVEL_VALIDATOR);
+ VALIDATORS.put(BLUETOOTH_ON, BLUETOOTH_ON_VALIDATOR);
+ VALIDATORS.put(PRIVATE_DNS_MODE, PRIVATE_DNS_MODE_VALIDATOR);
+ VALIDATORS.put(PRIVATE_DNS_SPECIFIER, PRIVATE_DNS_SPECIFIER_VALIDATOR);
+ VALIDATORS.put(SOFT_AP_TIMEOUT_ENABLED, SOFT_AP_TIMEOUT_ENABLED_VALIDATOR);
+ }
+
+ /**
* Global settings that shouldn't be persisted.
*
* @hide
@@ -10697,7 +11259,15 @@ public final class Settings {
LOCATION_GLOBAL_KILL_SWITCH,
};
- /** @hide */
+ /**
+ * Keys we no longer back up under the current schema, but want to continue to
+ * process when restoring historical backup datasets.
+ *
+ * All settings in {@link LEGACY_RESTORE_SETTINGS} array *must* have a non-null validator,
+ * otherwise they won't be restored.
+ *
+ * @hide
+ */
public static final String[] LEGACY_RESTORE_SETTINGS = {
};
diff --git a/core/java/android/provider/SettingsValidators.java b/core/java/android/provider/SettingsValidators.java
new file mode 100644
index 000000000000..84c9e8867c44
--- /dev/null
+++ b/core/java/android/provider/SettingsValidators.java
@@ -0,0 +1,249 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.provider;
+
+import android.content.ComponentName;
+import android.net.Uri;
+
+import com.android.internal.util.ArrayUtils;
+
+import java.util.Locale;
+
+/**
+ * This class provides both interface for validation and common validators
+ * used to ensure Settings have meaningful values.
+ *
+ * @hide
+ */
+public class SettingsValidators {
+
+ public static final Validator BOOLEAN_VALIDATOR =
+ new DiscreteValueValidator(new String[] {"0", "1"});
+
+ public static final Validator ANY_STRING_VALIDATOR = new Validator() {
+ @Override
+ public boolean validate(String value) {
+ return true;
+ }
+ };
+
+ public static final Validator NON_NEGATIVE_INTEGER_VALIDATOR = new Validator() {
+ @Override
+ public boolean validate(String value) {
+ try {
+ return Integer.parseInt(value) >= 0;
+ } catch (NumberFormatException e) {
+ return false;
+ }
+ }
+ };
+
+ public static final Validator ANY_INTEGER_VALIDATOR = new Validator() {
+ @Override
+ public boolean validate(String value) {
+ try {
+ Integer.parseInt(value);
+ return true;
+ } catch (NumberFormatException e) {
+ return false;
+ }
+ }
+ };
+
+ public static final Validator URI_VALIDATOR = new Validator() {
+ @Override
+ public boolean validate(String value) {
+ try {
+ Uri.decode(value);
+ return true;
+ } catch (IllegalArgumentException e) {
+ return false;
+ }
+ }
+ };
+
+ public static final Validator COMPONENT_NAME_VALIDATOR = new Validator() {
+ @Override
+ public boolean validate(String value) {
+ return ComponentName.unflattenFromString(value) != null;
+ }
+ };
+
+ public static final Validator PACKAGE_NAME_VALIDATOR = new Validator() {
+ @Override
+ public boolean validate(String value) {
+ return value != null && isStringPackageName(value);
+ }
+
+ private boolean isStringPackageName(String value) {
+ // The name may contain uppercase or lowercase letters ('A' through 'Z'), numbers,
+ // and underscores ('_'). However, individual package name parts may only
+ // start with letters.
+ // (https://developer.android.com/guide/topics/manifest/manifest-element.html#package)
+ if (value == null) {
+ return false;
+ }
+ String[] subparts = value.split("\\.");
+ boolean isValidPackageName = true;
+ for (String subpart : subparts) {
+ isValidPackageName |= isSubpartValidForPackageName(subpart);
+ if (!isValidPackageName) break;
+ }
+ return isValidPackageName;
+ }
+
+ private boolean isSubpartValidForPackageName(String subpart) {
+ if (subpart.length() == 0) return false;
+ boolean isValidSubpart = Character.isLetter(subpart.charAt(0));
+ for (int i = 1; i < subpart.length(); i++) {
+ isValidSubpart |= (Character.isLetterOrDigit(subpart.charAt(i))
+ || (subpart.charAt(i) == '_'));
+ if (!isValidSubpart) break;
+ }
+ return isValidSubpart;
+ }
+ };
+
+ public static final Validator LENIENT_IP_ADDRESS_VALIDATOR = new Validator() {
+ private static final int MAX_IPV6_LENGTH = 45;
+
+ @Override
+ public boolean validate(String value) {
+ if (value == null) {
+ return false;
+ }
+ return value.length() <= MAX_IPV6_LENGTH;
+ }
+ };
+
+ public static final Validator LOCALE_VALIDATOR = new Validator() {
+ @Override
+ public boolean validate(String value) {
+ if (value == null) {
+ return false;
+ }
+ Locale[] validLocales = Locale.getAvailableLocales();
+ for (Locale locale : validLocales) {
+ if (value.equals(locale.toString())) {
+ return true;
+ }
+ }
+ return false;
+ }
+ };
+
+ public interface Validator {
+ boolean validate(String value);
+ }
+
+ public static final class DiscreteValueValidator implements Validator {
+ private final String[] mValues;
+
+ public DiscreteValueValidator(String[] values) {
+ mValues = values;
+ }
+
+ @Override
+ public boolean validate(String value) {
+ return ArrayUtils.contains(mValues, value);
+ }
+ }
+
+ public static final class InclusiveIntegerRangeValidator implements Validator {
+ private final int mMin;
+ private final int mMax;
+
+ public InclusiveIntegerRangeValidator(int min, int max) {
+ mMin = min;
+ mMax = max;
+ }
+
+ @Override
+ public boolean validate(String value) {
+ try {
+ final int intValue = Integer.parseInt(value);
+ return intValue >= mMin && intValue <= mMax;
+ } catch (NumberFormatException e) {
+ return false;
+ }
+ }
+ }
+
+ public static final class InclusiveFloatRangeValidator implements Validator {
+ private final float mMin;
+ private final float mMax;
+
+ public InclusiveFloatRangeValidator(float min, float max) {
+ mMin = min;
+ mMax = max;
+ }
+
+ @Override
+ public boolean validate(String value) {
+ try {
+ final float floatValue = Float.parseFloat(value);
+ return floatValue >= mMin && floatValue <= mMax;
+ } catch (NumberFormatException e) {
+ return false;
+ }
+ }
+ }
+
+ public static final class ComponentNameListValidator implements Validator {
+ private final String mSeparator;
+
+ public ComponentNameListValidator(String separator) {
+ mSeparator = separator;
+ }
+
+ @Override
+ public boolean validate(String value) {
+ if (value == null) {
+ return false;
+ }
+ String[] elements = value.split(mSeparator);
+ for (String element : elements) {
+ if (!COMPONENT_NAME_VALIDATOR.validate(element)) {
+ return false;
+ }
+ }
+ return true;
+ }
+ }
+
+ public static final class PackageNameListValidator implements Validator {
+ private final String mSeparator;
+
+ public PackageNameListValidator(String separator) {
+ mSeparator = separator;
+ }
+
+ @Override
+ public boolean validate(String value) {
+ if (value == null) {
+ return false;
+ }
+ String[] elements = value.split(mSeparator);
+ for (String element : elements) {
+ if (!PACKAGE_NAME_VALIDATOR.validate(element)) {
+ return false;
+ }
+ }
+ return true;
+ }
+ }
+}
diff --git a/core/java/android/security/keystore/KeychainSnapshot.java b/core/java/android/security/keystore/KeychainSnapshot.java
index 2029114f9060..e03dd4a62ca0 100644
--- a/core/java/android/security/keystore/KeychainSnapshot.java
+++ b/core/java/android/security/keystore/KeychainSnapshot.java
@@ -43,7 +43,14 @@ import java.util.List;
* @hide
*/
public final class KeychainSnapshot implements Parcelable {
+ private static final int DEFAULT_MAX_ATTEMPTS = 10;
+ private static final long DEFAULT_COUNTER_ID = 1L;
+
private int mSnapshotVersion;
+ private int mMaxAttempts = DEFAULT_MAX_ATTEMPTS;
+ private long mCounterId = DEFAULT_COUNTER_ID;
+ private byte[] mServerParams;
+ private byte[] mPublicKey;
private List<KeychainProtectionParams> mKeychainProtectionParams;
private List<WrappedApplicationKey> mEntryRecoveryData;
private byte[] mEncryptedRecoveryKeyBlob;
@@ -79,6 +86,37 @@ public final class KeychainSnapshot implements Parcelable {
}
/**
+ * Number of user secret guesses allowed during Keychain recovery.
+ */
+ public int getMaxAttempts() {
+ return mMaxAttempts;
+ }
+
+ /**
+ * CounterId which is rotated together with user secret.
+ */
+ public long getCounterId() {
+ return mCounterId;
+ }
+
+ /**
+ * Server parameters.
+ */
+ public @NonNull byte[] getServerParams() {
+ return mServerParams;
+ }
+
+ /**
+ * Public key used to encrypt {@code encryptedRecoveryKeyBlob}.
+ *
+ * See implementation for binary key format
+ */
+ // TODO: document key format.
+ public @NonNull byte[] getTrustedHardwarePublicKey() {
+ return mPublicKey;
+ }
+
+ /**
* UI and key derivation parameters. Note that combination of secrets may be used.
*/
public @NonNull List<KeychainProtectionParams> getKeychainProtectionParams() {
@@ -129,6 +167,50 @@ public final class KeychainSnapshot implements Parcelable {
}
/**
+ * Sets the number of user secret guesses allowed during Keychain recovery.
+ *
+ * @param maxAttempts The maximum number of guesses.
+ * @return This builder.
+ */
+ public Builder setMaxAttempts(int maxAttempts) {
+ mInstance.mMaxAttempts = maxAttempts;
+ return this;
+ }
+
+ /**
+ * Sets counter id.
+ *
+ * @param counterId The counter id.
+ * @return This builder.
+ */
+ public Builder setCounterId(long counterId) {
+ mInstance.mCounterId = counterId;
+ return this;
+ }
+
+ /**
+ * Sets server parameters.
+ *
+ * @param serverParams The server parameters
+ * @return This builder.
+ */
+ public Builder setServerParams(byte[] serverParams) {
+ mInstance.mServerParams = serverParams;
+ return this;
+ }
+
+ /**
+ * Sets public key used to encrypt recovery blob.
+ *
+ * @param publicKey The public key
+ * @return This builder.
+ */
+ public Builder setTrustedHardwarePublicKey(byte[] publicKey) {
+ mInstance.mPublicKey = publicKey;
+ return this;
+ }
+
+ /**
* Sets UI and key derivation parameters
*
* @param recoveryMetadata The UI and key derivation parameters
@@ -175,6 +257,8 @@ public final class KeychainSnapshot implements Parcelable {
Preconditions.checkCollectionElementsNotNull(mInstance.mEntryRecoveryData,
"entryRecoveryData");
Preconditions.checkNotNull(mInstance.mEncryptedRecoveryKeyBlob);
+ Preconditions.checkNotNull(mInstance.mServerParams);
+ Preconditions.checkNotNull(mInstance.mPublicKey);
return mInstance;
}
}
diff --git a/core/java/android/service/autofill/AutofillFieldClassificationService.java b/core/java/android/service/autofill/AutofillFieldClassificationService.java
index 18f6dab9fc59..4e4caf04579f 100644
--- a/core/java/android/service/autofill/AutofillFieldClassificationService.java
+++ b/core/java/android/service/autofill/AutofillFieldClassificationService.java
@@ -15,9 +15,6 @@
*/
package android.service.autofill;
-import static android.view.autofill.AutofillManager.EXTRA_AVAILABLE_ALGORITHMS;
-import static android.view.autofill.AutofillManager.EXTRA_DEFAULT_ALGORITHM;
-
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.annotation.SystemApi;
@@ -58,9 +55,7 @@ public abstract class AutofillFieldClassificationService extends Service {
private static final String TAG = "AutofillFieldClassificationService";
- private static final int MSG_GET_AVAILABLE_ALGORITHMS = 1;
- private static final int MSG_GET_DEFAULT_ALGORITHM = 2;
- private static final int MSG_GET_SCORES = 3;
+ private static final int MSG_GET_SCORES = 1;
/**
* The {@link Intent} action that must be declared as handled by a service
@@ -69,6 +64,20 @@ public abstract class AutofillFieldClassificationService extends Service {
public static final String SERVICE_INTERFACE =
"android.service.autofill.AutofillFieldClassificationService";
+ /**
+ * Manifest metadata key for the resource string containing the name of the default field
+ * classification algorithm.
+ */
+ public static final String SERVICE_META_DATA_KEY_DEFAULT_ALGORITHM =
+ "android.autofill.field_classification.default_algorithm";
+ /**
+ * Manifest metadata key for the resource string array containing the names of all field
+ * classification algorithms provided by the service.
+ */
+ public static final String SERVICE_META_DATA_KEY_AVAILABLE_ALGORITHMS =
+ "android.autofill.field_classification.available_algorithms";
+
+
/** {@hide} **/
public static final String EXTRA_SCORES = "scores";
@@ -79,21 +88,6 @@ public abstract class AutofillFieldClassificationService extends Service {
final Bundle data = new Bundle();
final RemoteCallback callback;
switch (action) {
- case MSG_GET_AVAILABLE_ALGORITHMS:
- callback = (RemoteCallback) msg.obj;
- final List<String> availableAlgorithms = onGetAvailableAlgorithms();
- String[] asArray = null;
- if (availableAlgorithms != null) {
- asArray = new String[availableAlgorithms.size()];
- availableAlgorithms.toArray(asArray);
- }
- data.putStringArray(EXTRA_AVAILABLE_ALGORITHMS, asArray);
- break;
- case MSG_GET_DEFAULT_ALGORITHM:
- callback = (RemoteCallback) msg.obj;
- final String defaultAlgorithm = onGetDefaultAlgorithm();
- data.putString(EXTRA_DEFAULT_ALGORITHM, defaultAlgorithm);
- break;
case MSG_GET_SCORES:
final SomeArgs args = (SomeArgs) msg.obj;
callback = (RemoteCallback) args.arg1;
@@ -103,9 +97,9 @@ public abstract class AutofillFieldClassificationService extends Service {
final List<AutofillValue> actualValues = ((List<AutofillValue>) args.arg4);
@SuppressWarnings("unchecked")
final String[] userDataValues = (String[]) args.arg5;
- final Scores scores = onGetScores(algorithmName, algorithmArgs, actualValues,
+ final float[][] scores = onGetScores(algorithmName, algorithmArgs, actualValues,
Arrays.asList(userDataValues));
- data.putParcelable(EXTRA_SCORES, scores);
+ data.putParcelable(EXTRA_SCORES, new Scores(scores));
break;
default:
Log.w(TAG, "Handling unknown message: " + action);
@@ -134,27 +128,6 @@ public abstract class AutofillFieldClassificationService extends Service {
}
/**
- * Gets the name of all available algorithms.
- *
- * @throws UnsupportedOperationException if not implemented by service.
- */
- // TODO(b/70939974): rename to onGetAvailableAlgorithms if not removed
- @NonNull
- public List<String> onGetAvailableAlgorithms() {
- throw new UnsupportedOperationException("Must be implemented by external service");
- }
-
- /**
- * Gets the default algorithm that's used when an algorithm is not specified or is invalid.
- *
- * @throws UnsupportedOperationException if not implemented by service.
- */
- @NonNull
- public String onGetDefaultAlgorithm() {
- throw new UnsupportedOperationException("Must be implemented by external service");
- }
-
- /**
* Calculates field classification scores in a batch.
*
* <p>See {@link AutofillFieldClassificationService} for more info about field classification
@@ -165,13 +138,14 @@ public abstract class AutofillFieldClassificationService extends Service {
* @param args optional arguments to be passed to the algorithm.
* @param actualValues values entered by the user.
* @param userDataValues values predicted from the user data.
- * @return the calculated scores and the algorithm used.
+ * @return the calculated scores, with the first dimension representing actual values and the
+ * second dimension values from {@link UserData}.
*
* {@hide}
*/
@Nullable
@SystemApi
- public Scores onGetScores(@Nullable String algorithm,
+ public float[][] onGetScores(@Nullable String algorithm,
@Nullable Bundle args, @NonNull List<AutofillValue> actualValues,
@NonNull List<String> userDataValues) {
throw new UnsupportedOperationException("Must be implemented by external service");
@@ -179,17 +153,6 @@ public abstract class AutofillFieldClassificationService extends Service {
private final class AutofillFieldClassificationServiceWrapper
extends IAutofillFieldClassificationService.Stub {
-
- @Override
- public void getAvailableAlgorithms(RemoteCallback callback) throws RemoteException {
- mHandlerCaller.obtainMessageO(MSG_GET_AVAILABLE_ALGORITHMS, callback).sendToTarget();
- }
-
- @Override
- public void getDefaultAlgorithm(RemoteCallback callback) throws RemoteException {
- mHandlerCaller.obtainMessageO(MSG_GET_DEFAULT_ALGORITHM, callback).sendToTarget();
- }
-
@Override
public void getScores(RemoteCallback callback, String algorithmName, Bundle algorithmArgs,
List<AutofillValue> actualValues, String[] userDataValues)
@@ -200,52 +163,27 @@ public abstract class AutofillFieldClassificationService extends Service {
}
}
-
- // TODO(b/70939974): it might be simpler to remove this class and return the float[][] directly,
- // ignoring the request if the algorithm name is invalid.
/**
- * Represents field classification scores used in a batch calculation.
+ * Helper class used to encapsulate a float[][] in a Parcelable.
*
* {@hide}
*/
- @SystemApi
public static final class Scores implements Parcelable {
- private final String mAlgorithmName;
- private final float[][] mScores;
-
- /* @hide */
- public Scores(String algorithmName, int size1, int size2) {
- mAlgorithmName = algorithmName;
- mScores = new float[size1][size2];
- }
+ public final float[][] scores;
- public Scores(Parcel parcel) {
- mAlgorithmName = parcel.readString();
+ private Scores(Parcel parcel) {
final int size1 = parcel.readInt();
final int size2 = parcel.readInt();
- mScores = new float[size1][size2];
+ scores = new float[size1][size2];
for (int i = 0; i < size1; i++) {
for (int j = 0; j < size2; j++) {
- mScores[i][j] = parcel.readFloat();
+ scores[i][j] = parcel.readFloat();
}
}
}
- /**
- * Gets the name of algorithm used to calculate the score.
- */
- @NonNull
- public String getAlgorithm() {
- return mAlgorithmName;
- }
-
- /**
- * Gets the resulting scores, with the 1st dimension representing actual values and the 2nd
- * dimension values from {@link UserData}.
- */
- @NonNull
- public float[][] getScores() {
- return mScores;
+ private Scores(float[][] scores) {
+ this.scores = scores;
}
@Override
@@ -255,20 +193,18 @@ public abstract class AutofillFieldClassificationService extends Service {
@Override
public void writeToParcel(Parcel parcel, int flags) {
- parcel.writeString(mAlgorithmName);
- int size1 = mScores.length;
- int size2 = mScores[0].length;
+ int size1 = scores.length;
+ int size2 = scores[0].length;
parcel.writeInt(size1);
parcel.writeInt(size2);
for (int i = 0; i < size1; i++) {
for (int j = 0; j < size2; j++) {
- parcel.writeFloat(mScores[i][j]);
+ parcel.writeFloat(scores[i][j]);
}
}
}
public static final Creator<Scores> CREATOR = new Creator<Scores>() {
-
@Override
public Scores createFromParcel(Parcel parcel) {
return new Scores(parcel);
@@ -278,7 +214,6 @@ public abstract class AutofillFieldClassificationService extends Service {
public Scores[] newArray(int size) {
return new Scores[size];
}
-
};
}
}
diff --git a/core/java/android/service/autofill/FieldClassification.java b/core/java/android/service/autofill/FieldClassification.java
index 536180335a83..cd1efd68df6f 100644
--- a/core/java/android/service/autofill/FieldClassification.java
+++ b/core/java/android/service/autofill/FieldClassification.java
@@ -105,21 +105,16 @@ public final class FieldClassification {
/**
* Represents the score of a {@link UserData} entry for the field.
- *
- * <p>The score is calculated by the given {@link #getAlgorithm() algorithm} and
- * the entry is identified by {@link #getRemoteId()}.
*/
public static final class Match {
private final String mRemoteId;
private final float mScore;
- private final String mAlgorithm;
/** @hide */
- public Match(String remoteId, float score, String algorithm) {
+ public Match(String remoteId, float score) {
mRemoteId = Preconditions.checkNotNull(remoteId);
mScore = score;
- mAlgorithm = algorithm;
}
/**
@@ -150,38 +145,22 @@ public final class FieldClassification {
return mScore;
}
- /**
- * Gets the algorithm used to calculate this score.
- *
- * <p>Typically, this is either the algorithm set by
- * {@link UserData.Builder#setFieldClassificationAlgorithm(String, android.os.Bundle)},
- * or the
- * {@link android.view.autofill.AutofillManager#getDefaultFieldClassificationAlgorithm()}.
- */
- @NonNull
- public String getAlgorithm() {
- return mAlgorithm;
- }
-
@Override
public String toString() {
if (!sDebug) return super.toString();
final StringBuilder string = new StringBuilder("Match: remoteId=");
Helper.appendRedacted(string, mRemoteId);
- return string.append(", score=").append(mScore)
- .append(", algorithm=").append(mAlgorithm)
- .toString();
+ return string.append(", score=").append(mScore).toString();
}
private void writeToParcel(@NonNull Parcel parcel) {
parcel.writeString(mRemoteId);
parcel.writeFloat(mScore);
- parcel.writeString(mAlgorithm);
}
private static Match readFromParcel(@NonNull Parcel parcel) {
- return new Match(parcel.readString(), parcel.readFloat(), parcel.readString());
+ return new Match(parcel.readString(), parcel.readFloat());
}
}
}
diff --git a/core/java/android/service/autofill/IAutofillFieldClassificationService.aidl b/core/java/android/service/autofill/IAutofillFieldClassificationService.aidl
index d8e829d8f67c..398557d5ad2e 100644
--- a/core/java/android/service/autofill/IAutofillFieldClassificationService.aidl
+++ b/core/java/android/service/autofill/IAutofillFieldClassificationService.aidl
@@ -27,8 +27,6 @@ import java.util.List;
* @hide
*/
oneway interface IAutofillFieldClassificationService {
- void getAvailableAlgorithms(in RemoteCallback callback);
- void getDefaultAlgorithm(in RemoteCallback callback);
void getScores(in RemoteCallback callback, String algorithmName, in Bundle algorithmArgs,
- in List<AutofillValue> actualValues, in String[] userDataValues);
+ in List<AutofillValue> actualValues, in String[] userDataValues);
}
diff --git a/core/java/android/service/autofill/UserData.java b/core/java/android/service/autofill/UserData.java
index 2f9225acc520..9017848055e2 100644
--- a/core/java/android/service/autofill/UserData.java
+++ b/core/java/android/service/autofill/UserData.java
@@ -155,12 +155,9 @@ public final class UserData implements Parcelable {
* <p>The currently available algorithms can be retrieve through
* {@link AutofillManager#getAvailableFieldClassificationAlgorithms()}.
*
- * <p><b>Note: </b>The available algorithms in the Android System can change dinamically,
- * so it's not guaranteed that the algorithm set here is the one that will be effectually
- * used. If the algorithm set here is not available at runtime, the
- * {@link AutofillManager#getDefaultFieldClassificationAlgorithm()} is used instead.
- * You can verify which algorithm was used by calling
- * {@link FieldClassification.Match#getAlgorithm()}.
+ * <p>If not set, the
+ * {@link AutofillManager#getDefaultFieldClassificationAlgorithm() default algorithm} is
+ * used instead.
*
* @param name name of the algorithm or {@code null} to used default.
* @param args optional arguments to the algorithm.
diff --git a/core/java/android/text/style/BackgroundColorSpan.java b/core/java/android/text/style/BackgroundColorSpan.java
index de05f50c9860..4f471a8a2f85 100644
--- a/core/java/android/text/style/BackgroundColorSpan.java
+++ b/core/java/android/text/style/BackgroundColorSpan.java
@@ -16,24 +16,48 @@
package android.text.style;
+import android.annotation.ColorInt;
+import android.annotation.NonNull;
import android.os.Parcel;
import android.text.ParcelableSpan;
import android.text.TextPaint;
import android.text.TextUtils;
+/**
+ * Changes the background color of the text to which the span is attached.
+ * <p>
+ * For example, to set a green background color for a text you would create a {@link
+ * android.text.SpannableStringBuilder} based on the text and set the span.
+ * <pre>{@code
+ * SpannableString string = new SpannableString("Text with a background color span");
+ *string.setSpan(new BackgroundColorSpan(color), 12, 28, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
+ * }</pre>
+ * <img src="{@docRoot}reference/android/images/text/style/backgroundcolorspan.png" />
+ * <figcaption>Set a background color for the text.</figcaption>
+ */
public class BackgroundColorSpan extends CharacterStyle
implements UpdateAppearance, ParcelableSpan {
private final int mColor;
- public BackgroundColorSpan(int color) {
+ /**
+ * Creates a {@link BackgroundColorSpan} from a color integer.
+ * <p>
+ *
+ * @param color color integer that defines the background color
+ * @see android.content.res.Resources#getColor(int, Resources.Theme)
+ */
+ public BackgroundColorSpan(@ColorInt int color) {
mColor = color;
}
- public BackgroundColorSpan(Parcel src) {
+ /**
+ * Creates a {@link BackgroundColorSpan} from a parcel.
+ */
+ public BackgroundColorSpan(@NonNull Parcel src) {
mColor = src.readInt();
}
-
+
public int getSpanTypeId() {
return getSpanTypeIdInternal();
}
@@ -42,26 +66,40 @@ public class BackgroundColorSpan extends CharacterStyle
public int getSpanTypeIdInternal() {
return TextUtils.BACKGROUND_COLOR_SPAN;
}
-
+
public int describeContents() {
return 0;
}
- public void writeToParcel(Parcel dest, int flags) {
+ /**
+ * Flatten this object into a Parcel.
+ *
+ * @param dest The Parcel in which the object should be written.
+ * @param flags Additional flags about how the object should be written.
+ */
+ public void writeToParcel(@NonNull Parcel dest, int flags) {
writeToParcelInternal(dest, flags);
}
/** @hide */
- public void writeToParcelInternal(Parcel dest, int flags) {
+ public void writeToParcelInternal(@NonNull Parcel dest, int flags) {
dest.writeInt(mColor);
}
+ /**
+ * @return the background color of this span.
+ * @see BackgroundColorSpan#BackgroundColorSpan(int)
+ */
+ @ColorInt
public int getBackgroundColor() {
return mColor;
}
+ /**
+ * Updates the background color of the TextPaint.
+ */
@Override
- public void updateDrawState(TextPaint ds) {
- ds.bgColor = mColor;
+ public void updateDrawState(@NonNull TextPaint textPaint) {
+ textPaint.bgColor = mColor;
}
}
diff --git a/core/java/android/text/style/ForegroundColorSpan.java b/core/java/android/text/style/ForegroundColorSpan.java
index 2bc6d5406ade..08ab2a1f1a20 100644
--- a/core/java/android/text/style/ForegroundColorSpan.java
+++ b/core/java/android/text/style/ForegroundColorSpan.java
@@ -17,24 +17,48 @@
package android.text.style;
import android.annotation.ColorInt;
+import android.annotation.NonNull;
import android.os.Parcel;
import android.text.ParcelableSpan;
import android.text.TextPaint;
import android.text.TextUtils;
+/**
+ * Changes the color of the text to which the span is attached.
+ * <p>
+ * For example, to set a green text color you would create a {@link
+ * android.text.SpannableStringBuilder} based on the text and set the span.
+ * <pre>{@code
+ * SpannableString string = new SpannableString("Text with a foreground color span");
+ *string.setSpan(new ForegroundColorSpan(color), 12, 28, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
+ * }</pre>
+ * <img src="{@docRoot}reference/android/images/text/style/foregroundcolorspan.png" />
+ * <figcaption>Set a text color.</figcaption>
+ */
public class ForegroundColorSpan extends CharacterStyle
implements UpdateAppearance, ParcelableSpan {
private final int mColor;
+ /**
+ * Creates a {@link ForegroundColorSpan} from a color integer.
+ * <p>
+ * To get the color integer associated with a particular color resource ID, use
+ * {@link android.content.res.Resources#getColor(int, Resources.Theme)}
+ *
+ * @param color color integer that defines the text color
+ */
public ForegroundColorSpan(@ColorInt int color) {
mColor = color;
}
- public ForegroundColorSpan(Parcel src) {
+ /**
+ * Creates a {@link ForegroundColorSpan} from a parcel.
+ */
+ public ForegroundColorSpan(@NonNull Parcel src) {
mColor = src.readInt();
}
-
+
public int getSpanTypeId() {
return getSpanTypeIdInternal();
}
@@ -48,22 +72,35 @@ public class ForegroundColorSpan extends CharacterStyle
return 0;
}
- public void writeToParcel(Parcel dest, int flags) {
+ /**
+ * Flatten this object into a Parcel.
+ *
+ * @param dest The Parcel in which the object should be written.
+ * @param flags Additional flags about how the object should be written.
+ */
+ public void writeToParcel(@NonNull Parcel dest, int flags) {
writeToParcelInternal(dest, flags);
}
/** @hide */
- public void writeToParcelInternal(Parcel dest, int flags) {
+ public void writeToParcelInternal(@NonNull Parcel dest, int flags) {
dest.writeInt(mColor);
}
+ /**
+ * @return the foreground color of this span.
+ * @see ForegroundColorSpan#ForegroundColorSpan(int)
+ */
@ColorInt
public int getForegroundColor() {
return mColor;
}
+ /**
+ * Updates the color of the TextPaint to the foreground color.
+ */
@Override
- public void updateDrawState(TextPaint ds) {
- ds.setColor(mColor);
+ public void updateDrawState(@NonNull TextPaint textPaint) {
+ textPaint.setColor(mColor);
}
}
diff --git a/core/java/android/util/DataUnit.java b/core/java/android/util/DataUnit.java
index 3cc1bd899eeb..ea4266ecb790 100644
--- a/core/java/android/util/DataUnit.java
+++ b/core/java/android/util/DataUnit.java
@@ -20,12 +20,15 @@ import java.time.temporal.ChronoUnit;
import java.util.concurrent.TimeUnit;
/**
- * Constants for common byte-related units. Note that both SI and IEC units are
- * supported, and you'll need to pick the correct one for your use-case.
+ * A {@code DataUnit} represents data sizes at a given unit of granularity and
+ * provides utility methods to convert across units.
+ * <p>
+ * Note that both SI units (powers of 10) and IEC units (powers of 2) are
+ * supported, and you'll need to pick the correct one for your use-case. For
+ * example, Wikipedia defines a "kilobyte" as an SI unit of 1000 bytes, and a
+ * "kibibyte" as an IEC unit of 1024 bytes.
* <p>
* This design is mirrored after {@link TimeUnit} and {@link ChronoUnit}.
- *
- * @hide
*/
public enum DataUnit {
KILOBYTES { @Override public long toBytes(long v) { return v * 1_000; } },
diff --git a/core/java/android/util/apk/ApkSignatureSchemeV2Verifier.java b/core/java/android/util/apk/ApkSignatureSchemeV2Verifier.java
index ce8998fcb863..5a09dab552e3 100644
--- a/core/java/android/util/apk/ApkSignatureSchemeV2Verifier.java
+++ b/core/java/android/util/apk/ApkSignatureSchemeV2Verifier.java
@@ -16,6 +16,7 @@
package android.util.apk;
+import static android.util.apk.ApkSigningBlockUtils.CONTENT_DIGEST_VERITY_CHUNKED_SHA256;
import static android.util.apk.ApkSigningBlockUtils.SIGNATURE_DSA_WITH_SHA256;
import static android.util.apk.ApkSigningBlockUtils.SIGNATURE_ECDSA_WITH_SHA256;
import static android.util.apk.ApkSigningBlockUtils.SIGNATURE_ECDSA_WITH_SHA512;
@@ -42,6 +43,7 @@ import java.io.IOException;
import java.io.RandomAccessFile;
import java.nio.BufferUnderflowException;
import java.nio.ByteBuffer;
+import java.security.DigestException;
import java.security.InvalidAlgorithmParameterException;
import java.security.InvalidKeyException;
import java.security.KeyFactory;
@@ -105,7 +107,8 @@ public class ApkSignatureSchemeV2Verifier {
*/
public static X509Certificate[][] verify(String apkFile)
throws SignatureNotFoundException, SecurityException, IOException {
- return verify(apkFile, true);
+ VerifiedSigner vSigner = verify(apkFile, true);
+ return vSigner.certs;
}
/**
@@ -119,10 +122,11 @@ public class ApkSignatureSchemeV2Verifier {
*/
public static X509Certificate[][] plsCertsNoVerifyOnlyCerts(String apkFile)
throws SignatureNotFoundException, SecurityException, IOException {
- return verify(apkFile, false);
+ VerifiedSigner vSigner = verify(apkFile, false);
+ return vSigner.certs;
}
- private static X509Certificate[][] verify(String apkFile, boolean verifyIntegrity)
+ private static VerifiedSigner verify(String apkFile, boolean verifyIntegrity)
throws SignatureNotFoundException, SecurityException, IOException {
try (RandomAccessFile apk = new RandomAccessFile(apkFile, "r")) {
return verify(apk, verifyIntegrity);
@@ -138,7 +142,7 @@ public class ApkSignatureSchemeV2Verifier {
* verify.
* @throws IOException if an I/O error occurs while reading the APK file.
*/
- private static X509Certificate[][] verify(RandomAccessFile apk, boolean verifyIntegrity)
+ private static VerifiedSigner verify(RandomAccessFile apk, boolean verifyIntegrity)
throws SignatureNotFoundException, SecurityException, IOException {
SignatureInfo signatureInfo = findSignature(apk);
return verify(apk, signatureInfo, verifyIntegrity);
@@ -163,7 +167,7 @@ public class ApkSignatureSchemeV2Verifier {
* @param signatureInfo APK Signature Scheme v2 Block and information relevant for verifying it
* against the APK file.
*/
- private static X509Certificate[][] verify(
+ private static VerifiedSigner verify(
RandomAccessFile apk,
SignatureInfo signatureInfo,
boolean doVerifyIntegrity) throws SecurityException, IOException {
@@ -207,7 +211,14 @@ public class ApkSignatureSchemeV2Verifier {
ApkSigningBlockUtils.verifyIntegrity(contentDigests, apk, signatureInfo);
}
- return signerCerts.toArray(new X509Certificate[signerCerts.size()][]);
+ byte[] verityRootHash = null;
+ if (contentDigests.containsKey(CONTENT_DIGEST_VERITY_CHUNKED_SHA256)) {
+ verityRootHash = contentDigests.get(CONTENT_DIGEST_VERITY_CHUNKED_SHA256);
+ }
+
+ return new VerifiedSigner(
+ signerCerts.toArray(new X509Certificate[signerCerts.size()][]),
+ verityRootHash);
}
private static X509Certificate[] verifySigner(
@@ -383,6 +394,24 @@ public class ApkSignatureSchemeV2Verifier {
return;
}
+ static byte[] getVerityRootHash(String apkPath)
+ throws IOException, SignatureNotFoundException, SecurityException {
+ try (RandomAccessFile apk = new RandomAccessFile(apkPath, "r")) {
+ SignatureInfo signatureInfo = findSignature(apk);
+ VerifiedSigner vSigner = verify(apk, false);
+ return vSigner.verityRootHash;
+ }
+ }
+
+ static byte[] generateApkVerity(String apkPath, ByteBufferFactory bufferFactory)
+ throws IOException, SignatureNotFoundException, SecurityException, DigestException,
+ NoSuchAlgorithmException {
+ try (RandomAccessFile apk = new RandomAccessFile(apkPath, "r")) {
+ SignatureInfo signatureInfo = findSignature(apk);
+ return ApkSigningBlockUtils.generateApkVerity(apkPath, bufferFactory, signatureInfo);
+ }
+ }
+
private static boolean isSupportedSignatureAlgorithm(int sigAlgorithm) {
switch (sigAlgorithm) {
case SIGNATURE_RSA_PSS_WITH_SHA256:
@@ -400,4 +429,20 @@ public class ApkSignatureSchemeV2Verifier {
return false;
}
}
+
+ /**
+ * Verified APK Signature Scheme v2 signer.
+ *
+ * @hide for internal use only.
+ */
+ public static class VerifiedSigner {
+ public final X509Certificate[][] certs;
+ public final byte[] verityRootHash;
+
+ public VerifiedSigner(X509Certificate[][] certs, byte[] verityRootHash) {
+ this.certs = certs;
+ this.verityRootHash = verityRootHash;
+ }
+
+ }
}
diff --git a/core/java/android/util/apk/ApkSignatureSchemeV3Verifier.java b/core/java/android/util/apk/ApkSignatureSchemeV3Verifier.java
index c9e67fe1c9ef..1b04eb2f7d44 100644
--- a/core/java/android/util/apk/ApkSignatureSchemeV3Verifier.java
+++ b/core/java/android/util/apk/ApkSignatureSchemeV3Verifier.java
@@ -16,6 +16,7 @@
package android.util.apk;
+import static android.util.apk.ApkSigningBlockUtils.CONTENT_DIGEST_VERITY_CHUNKED_SHA256;
import static android.util.apk.ApkSigningBlockUtils.SIGNATURE_DSA_WITH_SHA256;
import static android.util.apk.ApkSigningBlockUtils.SIGNATURE_ECDSA_WITH_SHA256;
import static android.util.apk.ApkSigningBlockUtils.SIGNATURE_ECDSA_WITH_SHA512;
@@ -43,6 +44,7 @@ import java.io.IOException;
import java.io.RandomAccessFile;
import java.nio.BufferUnderflowException;
import java.nio.ByteBuffer;
+import java.security.DigestException;
import java.security.InvalidAlgorithmParameterException;
import java.security.InvalidKeyException;
import java.security.KeyFactory;
@@ -211,6 +213,10 @@ public class ApkSignatureSchemeV3Verifier {
ApkSigningBlockUtils.verifyIntegrity(contentDigests, apk, signatureInfo);
}
+ if (contentDigests.containsKey(CONTENT_DIGEST_VERITY_CHUNKED_SHA256)) {
+ result.verityRootHash = contentDigests.get(CONTENT_DIGEST_VERITY_CHUNKED_SHA256);
+ }
+
return result;
}
@@ -499,6 +505,24 @@ public class ApkSignatureSchemeV3Verifier {
return new VerifiedProofOfRotation(certs, flagsList);
}
+ static byte[] getVerityRootHash(String apkPath)
+ throws IOException, SignatureNotFoundException, SecurityException {
+ try (RandomAccessFile apk = new RandomAccessFile(apkPath, "r")) {
+ SignatureInfo signatureInfo = findSignature(apk);
+ VerifiedSigner vSigner = verify(apk, false);
+ return vSigner.verityRootHash;
+ }
+ }
+
+ static byte[] generateApkVerity(String apkPath, ByteBufferFactory bufferFactory)
+ throws IOException, SignatureNotFoundException, SecurityException, DigestException,
+ NoSuchAlgorithmException {
+ try (RandomAccessFile apk = new RandomAccessFile(apkPath, "r")) {
+ SignatureInfo signatureInfo = findSignature(apk);
+ return ApkSigningBlockUtils.generateApkVerity(apkPath, bufferFactory, signatureInfo);
+ }
+ }
+
private static boolean isSupportedSignatureAlgorithm(int sigAlgorithm) {
switch (sigAlgorithm) {
case SIGNATURE_RSA_PSS_WITH_SHA256:
@@ -541,6 +565,8 @@ public class ApkSignatureSchemeV3Verifier {
public final X509Certificate[] certs;
public final VerifiedProofOfRotation por;
+ public byte[] verityRootHash;
+
public VerifiedSigner(X509Certificate[] certs, VerifiedProofOfRotation por) {
this.certs = certs;
this.por = por;
diff --git a/core/java/android/util/apk/ApkSignatureVerifier.java b/core/java/android/util/apk/ApkSignatureVerifier.java
index 555c4740389a..a2a76169c83a 100644
--- a/core/java/android/util/apk/ApkSignatureVerifier.java
+++ b/core/java/android/util/apk/ApkSignatureVerifier.java
@@ -36,7 +36,9 @@ import libcore.io.IoUtils;
import java.io.IOException;
import java.io.InputStream;
+import java.security.DigestException;
import java.security.GeneralSecurityException;
+import java.security.NoSuchAlgorithmException;
import java.security.cert.Certificate;
import java.security.cert.CertificateEncodingException;
import java.util.ArrayList;
@@ -367,4 +369,51 @@ public class ApkSignatureVerifier {
// v2 didn't work, try jarsigner
return verifyV1Signature(apkPath, false);
}
+
+ /**
+ * @return the verity root hash in the Signing Block.
+ */
+ public static byte[] getVerityRootHash(String apkPath)
+ throws IOException, SignatureNotFoundException, SecurityException {
+ // first try v3
+ try {
+ return ApkSignatureSchemeV3Verifier.getVerityRootHash(apkPath);
+ } catch (SignatureNotFoundException e) {
+ // try older version
+ }
+ return ApkSignatureSchemeV2Verifier.getVerityRootHash(apkPath);
+ }
+
+ /**
+ * Generates the Merkle tree and verity metadata to the buffer allocated by the {@code
+ * ByteBufferFactory}.
+ *
+ * @return the verity root hash of the generated Merkle tree.
+ */
+ public static byte[] generateApkVerity(String apkPath, ByteBufferFactory bufferFactory)
+ throws IOException, SignatureNotFoundException, SecurityException, DigestException,
+ NoSuchAlgorithmException {
+ // first try v3
+ try {
+ return ApkSignatureSchemeV3Verifier.generateApkVerity(apkPath, bufferFactory);
+ } catch (SignatureNotFoundException e) {
+ // try older version
+ }
+ return ApkSignatureSchemeV2Verifier.generateApkVerity(apkPath, bufferFactory);
+ }
+
+ /**
+ * Result of a successful APK verification operation.
+ */
+ public static class Result {
+ public final Certificate[][] certs;
+ public final Signature[] sigs;
+ public final int signatureSchemeVersion;
+
+ public Result(Certificate[][] certs, Signature[] sigs, int signingVersion) {
+ this.certs = certs;
+ this.sigs = sigs;
+ this.signatureSchemeVersion = signingVersion;
+ }
+ }
}
diff --git a/core/java/android/util/apk/ApkSigningBlockUtils.java b/core/java/android/util/apk/ApkSigningBlockUtils.java
index 9d53847f8110..4146f6fab011 100644
--- a/core/java/android/util/apk/ApkSigningBlockUtils.java
+++ b/core/java/android/util/apk/ApkSigningBlockUtils.java
@@ -306,6 +306,26 @@ final class ApkSigningBlockUtils {
}
/**
+ * Generates the fsverity header and hash tree to be used by kernel for the given apk. This
+ * method does not check whether the root hash exists in the Signing Block or not.
+ *
+ * <p>The output is stored in the {@link ByteBuffer} created by the given {@link
+ * ByteBufferFactory}.
+ *
+ * @return the root hash of the generated hash tree.
+ */
+ public static byte[] generateApkVerity(String apkPath, ByteBufferFactory bufferFactory,
+ SignatureInfo signatureInfo)
+ throws IOException, SignatureNotFoundException, SecurityException, DigestException,
+ NoSuchAlgorithmException {
+ try (RandomAccessFile apk = new RandomAccessFile(apkPath, "r")) {
+ ApkVerityBuilder.ApkVerityResult result = ApkVerityBuilder.generateApkVerity(apk,
+ signatureInfo, bufferFactory);
+ return result.rootHash;
+ }
+ }
+
+ /**
* Returns the ZIP End of Central Directory (EoCD) and its offset in the file.
*
* @throws IOException if an I/O error occurs while reading the file.
diff --git a/core/java/android/util/apk/ApkVerityBuilder.java b/core/java/android/util/apk/ApkVerityBuilder.java
index 7412ef411fb4..a0d5e4c2dd8e 100644
--- a/core/java/android/util/apk/ApkVerityBuilder.java
+++ b/core/java/android/util/apk/ApkVerityBuilder.java
@@ -164,11 +164,11 @@ abstract class ApkVerityBuilder {
}
private void fillUpLastOutputChunk() {
- int extra = (int) (BUFFER_SIZE - mOutput.position() % BUFFER_SIZE);
- if (extra == 0) {
+ int lastBlockSize = (int) (mOutput.position() % BUFFER_SIZE);
+ if (lastBlockSize == 0) {
return;
}
- mOutput.put(ByteBuffer.allocate(extra));
+ mOutput.put(ByteBuffer.allocate(BUFFER_SIZE - lastBlockSize));
}
}
diff --git a/core/java/android/view/DisplayCutout.java b/core/java/android/view/DisplayCutout.java
index 1ef5f0950b16..a61c8c1dba68 100644
--- a/core/java/android/view/DisplayCutout.java
+++ b/core/java/android/view/DisplayCutout.java
@@ -23,6 +23,8 @@ import static android.view.Surface.ROTATION_180;
import static android.view.Surface.ROTATION_270;
import static android.view.Surface.ROTATION_90;
+import android.content.res.Resources;
+import android.graphics.Matrix;
import android.graphics.Path;
import android.graphics.Point;
import android.graphics.Rect;
@@ -30,8 +32,12 @@ import android.graphics.RectF;
import android.graphics.Region;
import android.os.Parcel;
import android.os.Parcelable;
+import android.text.TextUtils;
+import android.util.Log;
+import android.util.PathParser;
import android.util.proto.ProtoOutputStream;
+import com.android.internal.R;
import com.android.internal.annotations.VisibleForTesting;
import java.util.List;
@@ -43,6 +49,9 @@ import java.util.List;
*/
public final class DisplayCutout {
+ private static final String TAG = "DisplayCutout";
+ private static final String DP_MARKER = "@dp";
+
private static final Rect ZERO_RECT = new Rect();
private static final Region EMPTY_REGION = new Region();
@@ -312,6 +321,40 @@ public final class DisplayCutout {
}
/**
+ * Creates an instance according to @android:string/config_mainBuiltInDisplayCutout.
+ *
+ * @hide
+ */
+ public static DisplayCutout fromResources(Resources res, int displayWidth) {
+ String spec = res.getString(R.string.config_mainBuiltInDisplayCutout);
+ if (TextUtils.isEmpty(spec)) {
+ return null;
+ }
+ spec = spec.trim();
+ final boolean inDp = spec.endsWith(DP_MARKER);
+ if (inDp) {
+ spec = spec.substring(0, spec.length() - DP_MARKER.length());
+ }
+
+ Path p;
+ try {
+ p = PathParser.createPathFromPathData(spec);
+ } catch (Throwable e) {
+ Log.wtf(TAG, "Could not inflate cutout: ", e);
+ return null;
+ }
+
+ final Matrix m = new Matrix();
+ if (inDp) {
+ final float dpToPx = res.getDisplayMetrics().density;
+ m.postScale(dpToPx, dpToPx);
+ }
+ m.postTranslate(displayWidth / 2f, 0);
+ p.transform(m);
+ return fromBounds(p);
+ }
+
+ /**
* Helper class for passing {@link DisplayCutout} through binder.
*
* Needed, because {@code readFromParcel} cannot be used with immutable classes.
diff --git a/core/java/android/view/IWindowSession.aidl b/core/java/android/view/IWindowSession.aidl
index 49f14442868b..17b6ddca6394 100644
--- a/core/java/android/view/IWindowSession.aidl
+++ b/core/java/android/view/IWindowSession.aidl
@@ -29,6 +29,7 @@ import android.view.IWindowId;
import android.view.MotionEvent;
import android.view.WindowManager;
import android.view.Surface;
+import android.view.SurfaceControl;
/**
* System private per-application interface to the window manager.
@@ -150,25 +151,32 @@ interface IWindowSession {
boolean performHapticFeedback(IWindow window, int effectId, boolean always);
/**
- * Allocate the drag's thumbnail surface. Also assigns a token that identifies
- * the drag to the OS and passes that as the return value. A return value of
- * null indicates failure.
- */
- IBinder prepareDrag(IWindow window, int flags,
- int thumbnailWidth, int thumbnailHeight, out Surface outSurface);
-
- /**
* Initiate the drag operation itself
- */
- boolean performDrag(IWindow window, IBinder dragToken, int touchSource,
+ *
+ * @param window Window which initiates drag operation.
+ * @param flags See {@code View#startDragAndDrop}
+ * @param surface Surface containing drag shadow image
+ * @param touchSource See {@code InputDevice#getSource()}
+ * @param touchX TODO (b/72072998): Fix the issue that the system server misuse the arguments as
+ * initial touch point while the framework passes drag shadow size.
+ * @param touchY TODO (b/72072998): Fix the issue that the system server misuse the arguments as
+ * initial touch point while the framework passes drag shadow size.
+ * @param thumbCenterX X coordinate for the position within the shadow image that should be
+ * underneath the touch point during the drag and drop operation.
+ * @param thumbCenterY Y coordinate for the position within the shadow image that should be
+ * underneath the touch point during the drag and drop operation.
+ * @param data Data transferred by drag and drop
+ * @return Token of drag operation which will be passed to cancelDragAndDrop.
+ */
+ IBinder performDrag(IWindow window, int flags, in SurfaceControl surface, int touchSource,
float touchX, float touchY, float thumbCenterX, float thumbCenterY, in ClipData data);
- /**
+ /**
* Report the result of a drop action targeted to the given window.
* consumed is 'true' when the drop was accepted by a valid recipient,
* 'false' otherwise.
*/
- void reportDropResult(IWindow window, boolean consumed);
+ void reportDropResult(IWindow window, boolean consumed);
/**
* Cancel the current drag operation.
diff --git a/core/java/android/view/SurfaceControl.aidl b/core/java/android/view/SurfaceControl.aidl
new file mode 100644
index 000000000000..744ead2be643
--- /dev/null
+++ b/core/java/android/view/SurfaceControl.aidl
@@ -0,0 +1,19 @@
+/*
+ * 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;
+
+parcelable SurfaceControl;
diff --git a/core/java/android/view/View.java b/core/java/android/view/View.java
index 3242ff1a0b90..47bdf9df4719 100644
--- a/core/java/android/view/View.java
+++ b/core/java/android/view/View.java
@@ -16,6 +16,8 @@
package android.view;
+import static android.view.accessibility.AccessibilityEvent.CONTENT_CHANGE_TYPE_UNDEFINED;
+
import static java.lang.Math.max;
import android.animation.AnimatorInflater;
@@ -8548,6 +8550,12 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
info.setLongClickable(isLongClickable());
info.setContextClickable(isContextClickable());
info.setLiveRegion(getAccessibilityLiveRegion());
+ if ((mTooltipInfo != null) && (mTooltipInfo.mTooltipText != null)) {
+ info.setTooltipText(mTooltipInfo.mTooltipText);
+ info.addAction((mTooltipInfo.mTooltipPopup == null)
+ ? AccessibilityNodeInfo.AccessibilityAction.ACTION_SHOW_TOOLTIP
+ : AccessibilityNodeInfo.AccessibilityAction.ACTION_HIDE_TOOLTIP);
+ }
// TODO: These make sense only if we are in an AdapterView but all
// views can be selected. Maybe from accessibility perspective
@@ -8951,8 +8959,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
return;
}
mAccessibilityTraversalBeforeId = beforeId;
- notifyAccessibilityStateChanged(
- AccessibilityEvent.CONTENT_CHANGE_TYPE_UNDEFINED);
+ notifyAccessibilityStateChanged(CONTENT_CHANGE_TYPE_UNDEFINED);
}
/**
@@ -8995,8 +9002,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
return;
}
mAccessibilityTraversalAfterId = afterId;
- notifyAccessibilityStateChanged(
- AccessibilityEvent.CONTENT_CHANGE_TYPE_UNDEFINED);
+ notifyAccessibilityStateChanged(CONTENT_CHANGE_TYPE_UNDEFINED);
}
/**
@@ -9038,8 +9044,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
&& mID == View.NO_ID) {
mID = generateViewId();
}
- notifyAccessibilityStateChanged(
- AccessibilityEvent.CONTENT_CHANGE_TYPE_UNDEFINED);
+ notifyAccessibilityStateChanged(CONTENT_CHANGE_TYPE_UNDEFINED);
}
/**
@@ -10539,7 +10544,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
if (pflags3 != mPrivateFlags3) {
mPrivateFlags3 = pflags3;
- notifyAccessibilityStateChanged(AccessibilityEvent.CONTENT_CHANGE_TYPE_UNDEFINED);
+ notifyAccessibilityStateChanged(CONTENT_CHANGE_TYPE_UNDEFINED);
}
}
@@ -11367,8 +11372,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
mPrivateFlags2 &= ~PFLAG2_ACCESSIBILITY_LIVE_REGION_MASK;
mPrivateFlags2 |= (mode << PFLAG2_ACCESSIBILITY_LIVE_REGION_SHIFT)
& PFLAG2_ACCESSIBILITY_LIVE_REGION_MASK;
- notifyAccessibilityStateChanged(
- AccessibilityEvent.CONTENT_CHANGE_TYPE_UNDEFINED);
+ notifyAccessibilityStateChanged(CONTENT_CHANGE_TYPE_UNDEFINED);
}
}
@@ -11427,8 +11431,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
if (!maySkipNotify || oldIncludeForAccessibility != includeForAccessibility()) {
notifyAccessibilitySubtreeChanged();
} else {
- notifyAccessibilityStateChanged(
- AccessibilityEvent.CONTENT_CHANGE_TYPE_UNDEFINED);
+ notifyAccessibilityStateChanged(CONTENT_CHANGE_TYPE_UNDEFINED);
}
}
}
@@ -11838,8 +11841,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
|| getAccessibilitySelectionEnd() != end)
&& (start == end)) {
setAccessibilitySelection(start, end);
- notifyAccessibilityStateChanged(
- AccessibilityEvent.CONTENT_CHANGE_TYPE_UNDEFINED);
+ notifyAccessibilityStateChanged(CONTENT_CHANGE_TYPE_UNDEFINED);
return true;
}
} break;
@@ -11856,6 +11858,21 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
return true;
}
} break;
+ case R.id.accessibilityActionShowTooltip: {
+ if ((mTooltipInfo != null) && (mTooltipInfo.mTooltipPopup != null)) {
+ // Tooltip already showing
+ return false;
+ }
+ return showLongClickTooltip(0, 0);
+ }
+ case R.id.accessibilityActionHideTooltip: {
+ if ((mTooltipInfo == null) || (mTooltipInfo.mTooltipPopup == null)) {
+ // No tooltip showing
+ return false;
+ }
+ hideTooltip();
+ return true;
+ }
}
return false;
}
@@ -13889,12 +13906,10 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
if (oldIncludeForAccessibility != includeForAccessibility()) {
notifyAccessibilitySubtreeChanged();
} else {
- notifyAccessibilityStateChanged(
- AccessibilityEvent.CONTENT_CHANGE_TYPE_UNDEFINED);
+ notifyAccessibilityStateChanged(CONTENT_CHANGE_TYPE_UNDEFINED);
}
} else if ((changed & ENABLED_MASK) != 0) {
- notifyAccessibilityStateChanged(
- AccessibilityEvent.CONTENT_CHANGE_TYPE_UNDEFINED);
+ notifyAccessibilityStateChanged(CONTENT_CHANGE_TYPE_UNDEFINED);
}
}
}
@@ -21854,8 +21869,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
if (selected) {
sendAccessibilityEvent(AccessibilityEvent.TYPE_VIEW_SELECTED);
} else {
- notifyAccessibilityStateChanged(
- AccessibilityEvent.CONTENT_CHANGE_TYPE_UNDEFINED);
+ notifyAccessibilityStateChanged(CONTENT_CHANGE_TYPE_UNDEFINED);
}
}
}
@@ -23562,15 +23576,13 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
data.prepareToLeaveProcess((flags & View.DRAG_FLAG_GLOBAL) != 0);
}
- boolean okay = false;
-
Point shadowSize = new Point();
Point shadowTouchPoint = new Point();
shadowBuilder.onProvideShadowMetrics(shadowSize, shadowTouchPoint);
- if ((shadowSize.x < 0) || (shadowSize.y < 0) ||
- (shadowTouchPoint.x < 0) || (shadowTouchPoint.y < 0)) {
- throw new IllegalStateException("Drag shadow dimensions must not be negative");
+ if ((shadowSize.x <= 0) || (shadowSize.y <= 0)
+ || (shadowTouchPoint.x < 0) || (shadowTouchPoint.y < 0)) {
+ throw new IllegalStateException("Drag shadow dimensions must be positive");
}
if (ViewDebug.DEBUG_DRAG) {
@@ -23581,40 +23593,50 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
mAttachInfo.mDragSurface.release();
}
mAttachInfo.mDragSurface = new Surface();
+ mAttachInfo.mDragToken = null;
+
+ final ViewRootImpl root = mAttachInfo.mViewRootImpl;
+ final SurfaceSession session = new SurfaceSession(root.mSurface);
+ final SurfaceControl surface = new SurfaceControl.Builder(session)
+ .setName("drag surface")
+ .setSize(shadowSize.x, shadowSize.y)
+ .setFormat(PixelFormat.TRANSLUCENT)
+ .build();
try {
- mAttachInfo.mDragToken = mAttachInfo.mSession.prepareDrag(mAttachInfo.mWindow,
- flags, shadowSize.x, shadowSize.y, mAttachInfo.mDragSurface);
- if (ViewDebug.DEBUG_DRAG) Log.d(VIEW_LOG_TAG, "prepareDrag returned token="
- + mAttachInfo.mDragToken + " surface=" + mAttachInfo.mDragSurface);
- if (mAttachInfo.mDragToken != null) {
- Canvas canvas = mAttachInfo.mDragSurface.lockCanvas(null);
- try {
- canvas.drawColor(0, PorterDuff.Mode.CLEAR);
- shadowBuilder.onDrawShadow(canvas);
- } finally {
- mAttachInfo.mDragSurface.unlockCanvasAndPost(canvas);
- }
-
- final ViewRootImpl root = getViewRootImpl();
+ mAttachInfo.mDragSurface.copyFrom(surface);
+ final Canvas canvas = mAttachInfo.mDragSurface.lockCanvas(null);
+ try {
+ canvas.drawColor(0, PorterDuff.Mode.CLEAR);
+ shadowBuilder.onDrawShadow(canvas);
+ } finally {
+ mAttachInfo.mDragSurface.unlockCanvasAndPost(canvas);
+ }
- // Cache the local state object for delivery with DragEvents
- root.setLocalDragState(myLocalState);
+ // Cache the local state object for delivery with DragEvents
+ root.setLocalDragState(myLocalState);
- // repurpose 'shadowSize' for the last touch point
- root.getLastTouchPoint(shadowSize);
+ // repurpose 'shadowSize' for the last touch point
+ root.getLastTouchPoint(shadowSize);
- okay = mAttachInfo.mSession.performDrag(mAttachInfo.mWindow, mAttachInfo.mDragToken,
- root.getLastTouchSource(), shadowSize.x, shadowSize.y,
- shadowTouchPoint.x, shadowTouchPoint.y, data);
- if (ViewDebug.DEBUG_DRAG) Log.d(VIEW_LOG_TAG, "performDrag returned " + okay);
+ mAttachInfo.mDragToken = mAttachInfo.mSession.performDrag(
+ mAttachInfo.mWindow, flags, surface, root.getLastTouchSource(),
+ shadowSize.x, shadowSize.y, shadowTouchPoint.x, shadowTouchPoint.y, data);
+ if (ViewDebug.DEBUG_DRAG) {
+ Log.d(VIEW_LOG_TAG, "performDrag returned " + mAttachInfo.mDragToken);
}
+
+ return mAttachInfo.mDragToken != null;
} catch (Exception e) {
Log.e(VIEW_LOG_TAG, "Unable to initiate drag", e);
- mAttachInfo.mDragSurface.destroy();
- mAttachInfo.mDragSurface = null;
+ return false;
+ } finally {
+ if (mAttachInfo.mDragToken == null) {
+ mAttachInfo.mDragSurface.destroy();
+ mAttachInfo.mDragSurface = null;
+ root.setLocalDragState(null);
+ }
+ session.kill();
}
-
- return okay;
}
/**
@@ -27026,6 +27048,8 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
final boolean fromTouch = (mPrivateFlags3 & PFLAG3_FINGER_DOWN) == PFLAG3_FINGER_DOWN;
mTooltipInfo.mTooltipPopup.show(this, x, y, fromTouch, mTooltipInfo.mTooltipText);
mAttachInfo.mTooltipHost = this;
+ // The available accessibility actions have changed
+ notifyAccessibilityStateChanged(CONTENT_CHANGE_TYPE_UNDEFINED);
return true;
}
@@ -27044,6 +27068,8 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
if (mAttachInfo != null) {
mAttachInfo.mTooltipHost = null;
}
+ // The available accessibility actions have changed
+ notifyAccessibilityStateChanged(CONTENT_CHANGE_TYPE_UNDEFINED);
}
private boolean showLongClickTooltip(int x, int y) {
@@ -27052,8 +27078,8 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
return showTooltip(x, y, true);
}
- private void showHoverTooltip() {
- showTooltip(mTooltipInfo.mAnchorX, mTooltipInfo.mAnchorY, false);
+ private boolean showHoverTooltip() {
+ return showTooltip(mTooltipInfo.mAnchorX, mTooltipInfo.mAnchorY, false);
}
boolean dispatchTooltipHoverEvent(MotionEvent event) {
diff --git a/core/java/android/view/accessibility/AccessibilityNodeInfo.java b/core/java/android/view/accessibility/AccessibilityNodeInfo.java
index 311dd4b8b294..909032a0c279 100644
--- a/core/java/android/view/accessibility/AccessibilityNodeInfo.java
+++ b/core/java/android/view/accessibility/AccessibilityNodeInfo.java
@@ -639,6 +639,8 @@ public class AccessibilityNodeInfo implements Parcelable {
private static final int BOOLEAN_PROPERTY_IS_SHOWING_HINT = 0x0100000;
+ private static final int BOOLEAN_PROPERTY_IS_HEADING = 0x0200000;
+
/**
* Bits that provide the id of a virtual descendant of a view.
*/
@@ -725,6 +727,7 @@ public class AccessibilityNodeInfo implements Parcelable {
private CharSequence mError;
private CharSequence mPaneTitle;
private CharSequence mContentDescription;
+ private CharSequence mTooltipText;
private String mViewIdResourceName;
private ArrayList<String> mExtraDataKeys;
@@ -2409,6 +2412,30 @@ public class AccessibilityNodeInfo implements Parcelable {
}
/**
+ * Returns whether node represents a heading.
+ *
+ * @return {@code true} if the node is a heading, {@code false} otherwise.
+ */
+ public boolean isHeading() {
+ return getBooleanProperty(BOOLEAN_PROPERTY_IS_HEADING);
+ }
+
+ /**
+ * Sets whether the node represents a heading.
+ *
+ * <p>
+ * <strong>Note:</strong> Cannot be called from an
+ * {@link android.accessibilityservice.AccessibilityService}.
+ * This class is made immutable before being delivered to an AccessibilityService.
+ * </p>
+ *
+ * @param isHeading {@code true} if the node is a heading, {@code false} otherwise.
+ */
+ public void setHeading(boolean isHeading) {
+ setBooleanProperty(BOOLEAN_PROPERTY_IS_HEADING, isHeading);
+ }
+
+ /**
* Gets the package this node comes from.
*
* @return The package name.
@@ -2629,6 +2656,34 @@ public class AccessibilityNodeInfo implements Parcelable {
}
/**
+ * Gets the tooltip text of this node.
+ *
+ * @return The tooltip text.
+ */
+ @Nullable
+ public CharSequence getTooltipText() {
+ return mTooltipText;
+ }
+
+ /**
+ * Sets the tooltip text of this node.
+ * <p>
+ * <strong>Note:</strong> Cannot be called from an
+ * {@link android.accessibilityservice.AccessibilityService}.
+ * This class is made immutable before being delivered to an AccessibilityService.
+ * </p>
+ *
+ * @param tooltipText The tooltip text.
+ *
+ * @throws IllegalStateException If called from an AccessibilityService.
+ */
+ public void setTooltipText(@Nullable CharSequence tooltipText) {
+ enforceNotSealed();
+ mTooltipText = (tooltipText == null) ? null
+ : tooltipText.subSequence(0, tooltipText.length());
+ }
+
+ /**
* Sets the view for which the view represented by this info serves as a
* label for accessibility purposes.
*
@@ -3182,6 +3237,9 @@ public class AccessibilityNodeInfo implements Parcelable {
if (!Objects.equals(mPaneTitle, DEFAULT.mPaneTitle)) {
nonDefaultFields |= bitAt(fieldIndex);
}
+ if (!Objects.equals(mTooltipText, DEFAULT.mTooltipText)) {
+ nonDefaultFields |= bitAt(fieldIndex);
+ }
fieldIndex++;
if (!Objects.equals(mViewIdResourceName, DEFAULT.mViewIdResourceName)) {
nonDefaultFields |= bitAt(fieldIndex);
@@ -3303,6 +3361,8 @@ public class AccessibilityNodeInfo implements Parcelable {
parcel.writeCharSequence(mContentDescription);
}
if (isBitSet(nonDefaultFields, fieldIndex++)) parcel.writeCharSequence(mPaneTitle);
+ if (isBitSet(nonDefaultFields, fieldIndex++)) parcel.writeCharSequence(mTooltipText);
+
if (isBitSet(nonDefaultFields, fieldIndex++)) parcel.writeString(mViewIdResourceName);
if (isBitSet(nonDefaultFields, fieldIndex++)) parcel.writeInt(mTextSelectionStart);
@@ -3375,6 +3435,7 @@ public class AccessibilityNodeInfo implements Parcelable {
mError = other.mError;
mContentDescription = other.mContentDescription;
mPaneTitle = other.mPaneTitle;
+ mTooltipText = other.mTooltipText;
mViewIdResourceName = other.mViewIdResourceName;
if (mActions != null) mActions.clear();
@@ -3496,6 +3557,7 @@ public class AccessibilityNodeInfo implements Parcelable {
mContentDescription = parcel.readCharSequence();
}
if (isBitSet(nonDefaultFields, fieldIndex++)) mPaneTitle = parcel.readString();
+ if (isBitSet(nonDefaultFields, fieldIndex++)) mTooltipText = parcel.readCharSequence();
if (isBitSet(nonDefaultFields, fieldIndex++)) mViewIdResourceName = parcel.readString();
if (isBitSet(nonDefaultFields, fieldIndex++)) mTextSelectionStart = parcel.readInt();
@@ -3658,6 +3720,10 @@ public class AccessibilityNodeInfo implements Parcelable {
return "ACTION_SET_PROGRESS";
case R.id.accessibilityActionContextClick:
return "ACTION_CONTEXT_CLICK";
+ case R.id.accessibilityActionShowTooltip:
+ return "ACTION_SHOW_TOOLTIP";
+ case R.id.accessibilityActionHideTooltip:
+ return "ACTION_HIDE_TOOLTIP";
default:
return "ACTION_UNKNOWN";
}
@@ -3771,6 +3837,7 @@ public class AccessibilityNodeInfo implements Parcelable {
builder.append("; error: ").append(mError);
builder.append("; maxTextLength: ").append(mMaxTextLength);
builder.append("; contentDescription: ").append(mContentDescription);
+ builder.append("; tooltipText: ").append(mTooltipText);
builder.append("; viewIdResName: ").append(mViewIdResourceName);
builder.append("; checkable: ").append(isCheckable());
@@ -4185,6 +4252,20 @@ public class AccessibilityNodeInfo implements Parcelable {
public static final AccessibilityAction ACTION_MOVE_WINDOW =
new AccessibilityAction(R.id.accessibilityActionMoveWindow);
+ /**
+ * Action to show a tooltip. A node should expose this action only for views with tooltip
+ * text that but are not currently showing a tooltip.
+ */
+ public static final AccessibilityAction ACTION_SHOW_TOOLTIP =
+ new AccessibilityAction(R.id.accessibilityActionShowTooltip);
+
+ /**
+ * Action to hide a tooltip. A node should expose this action only for views that are
+ * currently showing a tooltip.
+ */
+ public static final AccessibilityAction ACTION_HIDE_TOOLTIP =
+ new AccessibilityAction(R.id.accessibilityActionHideTooltip);
+
private final int mActionId;
private final CharSequence mLabel;
@@ -4597,7 +4678,8 @@ public class AccessibilityNodeInfo implements Parcelable {
* @param rowSpan The number of rows the item spans.
* @param columnIndex The column index at which the item is located.
* @param columnSpan The number of columns the item spans.
- * @param heading Whether the item is a heading.
+ * @param heading Whether the item is a heading. (Prefer
+ * {@link AccessibilityNodeInfo#setHeading(boolean)}).
*/
public static CollectionItemInfo obtain(int rowIndex, int rowSpan,
int columnIndex, int columnSpan, boolean heading) {
@@ -4611,7 +4693,8 @@ public class AccessibilityNodeInfo implements Parcelable {
* @param rowSpan The number of rows the item spans.
* @param columnIndex The column index at which the item is located.
* @param columnSpan The number of columns the item spans.
- * @param heading Whether the item is a heading.
+ * @param heading Whether the item is a heading. (Prefer
+ * {@link AccessibilityNodeInfo#setHeading(boolean)})
* @param selected Whether the item is selected.
*/
public static CollectionItemInfo obtain(int rowIndex, int rowSpan,
@@ -4698,6 +4781,7 @@ public class AccessibilityNodeInfo implements Parcelable {
* heading, table header, etc.
*
* @return If the item is a heading.
+ * @deprecated Use {@link AccessibilityNodeInfo#isHeading()}
*/
public boolean isHeading() {
return mHeading;
diff --git a/core/java/android/view/autofill/AutofillManager.java b/core/java/android/view/autofill/AutofillManager.java
index f54561bfb423..4b24a71c8bfb 100644
--- a/core/java/android/view/autofill/AutofillManager.java
+++ b/core/java/android/view/autofill/AutofillManager.java
@@ -33,7 +33,6 @@ import android.metrics.LogMaker;
import android.os.Bundle;
import android.os.IBinder;
import android.os.Parcelable;
-import android.os.RemoteCallback;
import android.os.RemoteException;
import android.service.autofill.AutofillService;
import android.service.autofill.FillEventHistory;
@@ -58,8 +57,6 @@ import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import java.util.Objects;
-import java.util.concurrent.CountDownLatch;
-import java.util.concurrent.TimeUnit;
// TODO: use java.lang.ref.Cleaner once Android supports Java 9
import sun.misc.Cleaner;
@@ -177,11 +174,6 @@ public final class AutofillManager {
public static final String EXTRA_RESTORE_SESSION_TOKEN =
"android.view.autofill.extra.RESTORE_SESSION_TOKEN";
- /** @hide */
- public static final String EXTRA_AVAILABLE_ALGORITHMS = "available_algorithms";
- /** @hide */
- public static final String EXTRA_DEFAULT_ALGORITHM = "default_algorithm";
-
private static final String SESSION_ID_TAG = "android:sessionId";
private static final String STATE_TAG = "android:state";
private static final String LAST_AUTOFILLED_DATA_TAG = "android:lastAutoFilledData";
@@ -1174,22 +1166,10 @@ public final class AutofillManager {
* and it's ignored if the caller currently doesn't have an enabled autofill service for
* the user.
*/
- // TODO(b/70939974): refactor this method to be "purely" sync by getting the info from the
- // the ExtService manifest (instead of calling the service)
@Nullable
public String getDefaultFieldClassificationAlgorithm() {
- final SyncRemoteCallbackListener<String> listener =
- new SyncRemoteCallbackListener<String>() {
-
- @Override
- String getResult(Bundle result) {
- return result == null ? null : result.getString(EXTRA_DEFAULT_ALGORITHM);
- }
- };
-
try {
- mService.getDefaultFieldClassificationAlgorithm(new RemoteCallback(listener));
- return listener.getResult(FC_SERVICE_TIMEOUT);
+ return mService.getDefaultFieldClassificationAlgorithm();
} catch (RemoteException e) {
e.rethrowFromSystemServer();
return null;
@@ -1204,29 +1184,12 @@ public final class AutofillManager {
* and it returns an empty list if the caller currently doesn't have an enabled autofill service
* for the user.
*/
- // TODO(b/70939974): refactor this method to be "purely" sync by getting the info from the
- // the ExtService manifest (instead of calling the service)
@NonNull
public List<String> getAvailableFieldClassificationAlgorithms() {
- final SyncRemoteCallbackListener<List<String>> listener =
- new SyncRemoteCallbackListener<List<String>>() {
-
- @Override
- List<String> getResult(Bundle result) {
- List<String> algorithms = null;
- if (result != null) {
- final String[] asArray = result.getStringArray(EXTRA_AVAILABLE_ALGORITHMS);
- if (asArray != null) {
- algorithms = Arrays.asList(asArray);
- }
- }
- return algorithms != null ? algorithms : Collections.emptyList();
- }
- };
-
+ final String[] algorithms;
try {
- mService.getAvailableFieldClassificationAlgorithms(new RemoteCallback(listener));
- return listener.getResult(FC_SERVICE_TIMEOUT);
+ algorithms = mService.getAvailableFieldClassificationAlgorithms();
+ return algorithms != null ? Arrays.asList(algorithms) : Collections.emptyList();
} catch (RemoteException e) {
e.rethrowFromSystemServer();
return null;
@@ -2322,36 +2285,4 @@ public final class AutofillManager {
}
}
}
-
- private abstract static class SyncRemoteCallbackListener<T>
- implements RemoteCallback.OnResultListener {
-
- private final CountDownLatch mLatch = new CountDownLatch(1);
- private T mResult;
-
- @Override
- public void onResult(Bundle result) {
- if (sVerbose) Log.w(TAG, "SyncRemoteCallbackListener.onResult(): " + result);
- mResult = getResult(result);
- mLatch.countDown();
- }
-
- T getResult(int timeoutMs) {
- T result = null;
- try {
- if (mLatch.await(timeoutMs, TimeUnit.MILLISECONDS)) {
- result = mResult;
- } else {
- Log.w(TAG, "SyncRemoteCallbackListener not called in " + timeoutMs + "ms");
- }
- } catch (InterruptedException e) {
- Log.w(TAG, "SyncRemoteCallbackListener interrupted: " + e);
- Thread.currentThread().interrupt();
- }
- if (sVerbose) Log.w(TAG, "SyncRemoteCallbackListener: returning " + result);
- return result;
- }
-
- abstract T getResult(Bundle result);
- }
}
diff --git a/core/java/android/view/autofill/IAutoFillManager.aidl b/core/java/android/view/autofill/IAutoFillManager.aidl
index 41672e7aeb9b..1a11fbba0011 100644
--- a/core/java/android/view/autofill/IAutoFillManager.aidl
+++ b/core/java/android/view/autofill/IAutoFillManager.aidl
@@ -59,6 +59,6 @@ interface IAutoFillManager {
void setUserData(in UserData userData);
boolean isFieldClassificationEnabled();
ComponentName getAutofillServiceComponentName();
- void getAvailableFieldClassificationAlgorithms(in RemoteCallback callback);
- void getDefaultFieldClassificationAlgorithm(in RemoteCallback callback);
+ String[] getAvailableFieldClassificationAlgorithms();
+ String getDefaultFieldClassificationAlgorithm();
}
diff --git a/core/java/android/widget/MediaController2.java b/core/java/android/widget/MediaControlView2.java
index 9035137d5362..6e85ece291b2 100644
--- a/core/java/android/widget/MediaController2.java
+++ b/core/java/android/widget/MediaControlView2.java
@@ -19,130 +19,145 @@ package android.widget;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.content.Context;
-import android.graphics.Canvas;
import android.media.session.MediaController;
import android.media.update.ApiLoader;
-import android.media.update.MediaController2Provider;
+import android.media.update.MediaControlView2Provider;
import android.media.update.ViewProvider;
import android.util.AttributeSet;
import android.view.KeyEvent;
import android.view.MotionEvent;
-import android.view.View;
-import android.view.View.OnClickListener;
/**
* TODO PUBLIC API
* @hide
*/
-public class MediaController2 extends FrameLayout {
- private final MediaController2Provider mProvider;
+public class MediaControlView2 extends FrameLayout {
+ private final MediaControlView2Provider mProvider;
- public MediaController2(@NonNull Context context) {
+ public MediaControlView2(@NonNull Context context) {
this(context, null);
}
- public MediaController2(@NonNull Context context, @Nullable AttributeSet attrs) {
+ public MediaControlView2(@NonNull Context context, @Nullable AttributeSet attrs) {
this(context, attrs, 0);
}
- public MediaController2(@NonNull Context context, @Nullable AttributeSet attrs,
+ public MediaControlView2(@NonNull Context context, @Nullable AttributeSet attrs,
int defStyleAttr) {
this(context, attrs, defStyleAttr, 0);
}
- public MediaController2(@NonNull Context context, @Nullable AttributeSet attrs,
+ public MediaControlView2(@NonNull Context context, @Nullable AttributeSet attrs,
int defStyleAttr, int defStyleRes) {
super(context, attrs, defStyleAttr, defStyleRes);
mProvider = ApiLoader.getProvider(context)
- .createMediaController2(this, new SuperProvider());
+ .createMediaControlView2(this, new SuperProvider());
}
- public void setController(MediaController controller) {
- mProvider.setController_impl(controller);
+ public MediaControlView2Provider getProvider() {
+ return mProvider;
}
- public void setAnchorView(View view) {
- mProvider.setAnchorView_impl(view);
+ /**
+ * TODO: add docs
+ */
+ public void setController(MediaController controller) {
+ mProvider.setController_impl(controller);
}
+ /**
+ * TODO: add docs
+ */
public void show() {
mProvider.show_impl();
}
+ /**
+ * TODO: add docs
+ */
public void show(int timeout) {
mProvider.show_impl(timeout);
}
+ /**
+ * TODO: add docs
+ */
public boolean isShowing() {
return mProvider.isShowing_impl();
}
+ /**
+ * TODO: add docs
+ */
public void hide() {
mProvider.hide_impl();
}
- public void setPrevNextListeners(OnClickListener next, OnClickListener prev) {
- mProvider.setPrevNextListeners_impl(next, prev);
- }
-
+ /**
+ * TODO: add docs
+ */
public void showCCButton() {
mProvider.showCCButton_impl();
}
+ /**
+ * TODO: add docs
+ */
public boolean isPlaying() {
return mProvider.isPlaying_impl();
}
+ /**
+ * TODO: add docs
+ */
public int getCurrentPosition() {
return mProvider.getCurrentPosition_impl();
}
+ /**
+ * TODO: add docs
+ */
public int getBufferPercentage() {
return mProvider.getBufferPercentage_impl();
}
+ /**
+ * TODO: add docs
+ */
public boolean canPause() {
return mProvider.canPause_impl();
}
+ /**
+ * TODO: add docs
+ */
public boolean canSeekBackward() {
return mProvider.canSeekBackward_impl();
}
+ /**
+ * TODO: add docs
+ */
public boolean canSeekForward() {
return mProvider.canSeekForward_impl();
}
+ /**
+ * TODO: add docs
+ */
public void showSubtitle() {
mProvider.showSubtitle_impl();
}
+ /**
+ * TODO: add docs
+ */
public void hideSubtitle() {
mProvider.hideSubtitle_impl();
}
@Override
- protected void onAttachedToWindow() {
- mProvider.onAttachedToWindow_impl();
- }
-
- @Override
- protected void onDetachedFromWindow() {
- mProvider.onDetachedFromWindow_impl();
- }
-
- @Override
- protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
- mProvider.onLayout_impl(changed, left, top, right, bottom);
- }
-
- @Override
- public void draw(Canvas canvas) {
- mProvider.draw_impl(canvas);
- }
-
- @Override
public CharSequence getAccessibilityClassName() {
return mProvider.getAccessibilityClassName_impl();
}
@@ -179,58 +194,38 @@ public class MediaController2 extends FrameLayout {
private class SuperProvider implements ViewProvider {
@Override
- public void onAttachedToWindow_impl() {
- MediaController2.super.onAttachedToWindow();
- }
-
- @Override
- public void onDetachedFromWindow_impl() {
- MediaController2.super.onDetachedFromWindow();
- }
-
- @Override
- public void onLayout_impl(boolean changed, int left, int top, int right, int bottom) {
- MediaController2.super.onLayout(changed, left, top, right, bottom);
- }
-
- @Override
- public void draw_impl(Canvas canvas) {
- MediaController2.super.draw(canvas);
- }
-
- @Override
public CharSequence getAccessibilityClassName_impl() {
- return MediaController2.super.getAccessibilityClassName();
+ return MediaControlView2.super.getAccessibilityClassName();
}
@Override
public boolean onTouchEvent_impl(MotionEvent ev) {
- return MediaController2.super.onTouchEvent(ev);
+ return MediaControlView2.super.onTouchEvent(ev);
}
@Override
public boolean onTrackballEvent_impl(MotionEvent ev) {
- return MediaController2.super.onTrackballEvent(ev);
+ return MediaControlView2.super.onTrackballEvent(ev);
}
@Override
public boolean onKeyDown_impl(int keyCode, KeyEvent event) {
- return MediaController2.super.onKeyDown(keyCode, event);
+ return MediaControlView2.super.onKeyDown(keyCode, event);
}
@Override
public void onFinishInflate_impl() {
- MediaController2.super.onFinishInflate();
+ MediaControlView2.super.onFinishInflate();
}
@Override
public boolean dispatchKeyEvent_impl(KeyEvent event) {
- return MediaController2.super.dispatchKeyEvent(event);
+ return MediaControlView2.super.dispatchKeyEvent(event);
}
@Override
public void setEnabled_impl(boolean enabled) {
- MediaController2.super.setEnabled(enabled);
+ MediaControlView2.super.setEnabled(enabled);
}
}
}
diff --git a/core/java/android/widget/TextView.java b/core/java/android/widget/TextView.java
index dac6c0269539..7d3fcf469551 100644
--- a/core/java/android/widget/TextView.java
+++ b/core/java/android/widget/TextView.java
@@ -309,6 +309,7 @@ import java.util.Locale;
* @attr ref android.R.styleable#TextView_autoSizeMaxTextSize
* @attr ref android.R.styleable#TextView_autoSizeStepGranularity
* @attr ref android.R.styleable#TextView_autoSizePresetSizes
+ * @attr ref android.R.styleable#TextView_accessibilityHeading
*/
@RemoteView
public class TextView extends View implements ViewTreeObserver.OnPreDrawListener {
@@ -403,6 +404,7 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
private int mCurTextColor;
private int mCurHintTextColor;
private boolean mFreezesText;
+ private boolean mIsAccessibilityHeading;
private Editable.Factory mEditableFactory = Editable.Factory.getInstance();
private Spannable.Factory mSpannableFactory = Spannable.Factory.getInstance();
@@ -1267,6 +1269,8 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
case com.android.internal.R.styleable.TextView_lineHeight:
lineHeight = a.getDimensionPixelSize(attr, -1);
break;
+ case com.android.internal.R.styleable.TextView_accessibilityHeading:
+ mIsAccessibilityHeading = a.getBoolean(attr, false);
}
}
@@ -5128,6 +5132,31 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
}
/**
+ * Gets whether this view is a heading for accessibility purposes.
+ *
+ * @return {@code true} if the view is a heading, {@code false} otherwise.
+ *
+ * @attr ref android.R.styleable#TextView_accessibilityHeading
+ */
+ public boolean isAccessibilityHeading() {
+ return mIsAccessibilityHeading;
+ }
+
+ /**
+ * Set if view is a heading for a section of content for accessibility purposes.
+ *
+ * @param isHeading {@code true} if the view is a heading, {@code false} otherwise.
+ *
+ * @attr ref android.R.styleable#TextView_accessibilityHeading
+ */
+ public void setAccessibilityHeading(boolean isHeading) {
+ if (isHeading != mIsAccessibilityHeading) {
+ mIsAccessibilityHeading = isHeading;
+ notifyAccessibilityStateChanged(AccessibilityEvent.CONTENT_CHANGE_TYPE_UNDEFINED);
+ }
+ }
+
+ /**
* Convenience method to append the specified text to the TextView's
* display buffer, upgrading it to {@link android.widget.TextView.BufferType#EDITABLE}
* if it was not already editable.
@@ -10677,6 +10706,7 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
info.setText(getTextForAccessibility());
info.setHintText(mHint);
info.setShowingHintText(isShowingHint());
+ info.setHeading(mIsAccessibilityHeading);
if (mBufferType == BufferType.EDITABLE) {
info.setEditable(true);
diff --git a/core/java/android/widget/VideoView2.java b/core/java/android/widget/VideoView2.java
index 310a7bbdcabf..955f0532471a 100644
--- a/core/java/android/widget/VideoView2.java
+++ b/core/java/android/widget/VideoView2.java
@@ -20,9 +20,8 @@ import android.annotation.IntDef;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.content.Context;
-import android.graphics.Canvas;
import android.media.AudioAttributes;
-import android.media.MediaPlayer;
+import android.media.AudioManager;
import android.media.update.ApiLoader;
import android.media.update.VideoView2Provider;
import android.media.update.ViewProvider;
@@ -80,7 +79,8 @@ public class VideoView2 extends FrameLayout {
int defStyleAttr, int defStyleRes) {
super(context, attrs, defStyleAttr, defStyleRes);
- mProvider = ApiLoader.getProvider(context).createVideoView2(this, new SuperProvider());
+ mProvider = ApiLoader.getProvider(context).createVideoView2(this, new SuperProvider(),
+ attrs, defStyleAttr, defStyleRes);
}
/**
@@ -93,6 +93,20 @@ public class VideoView2 extends FrameLayout {
/**
* @hide
*/
+ public void setMediaControlView2(MediaControlView2 mediaControlView) {
+ mProvider.setMediaControlView2_impl(mediaControlView);
+ }
+
+ /**
+ * @hide
+ */
+ public MediaControlView2 getMediaControlView2() {
+ return mProvider.getMediaControlView2_impl();
+ }
+
+ /**
+ * @hide
+ */
public void start() {
mProvider.start_impl();
}
@@ -161,6 +175,45 @@ public class VideoView2 extends FrameLayout {
}
/**
+ * Sets playback speed.
+ *
+ * It is expressed as a multiplicative factor, where normal speed is 1.0f. If it is less than
+ * or equal to zero, it will be just ignored and nothing will be changed. If it exceeds the
+ * maximum speed that internal engine supports, system will determine best handling or it will
+ * be reset to the normal speed 1.0f.
+ * TODO: This should be revised after integration with MediaPlayer2.
+ * @param speed the playback speed. It should be positive.
+ * @hide
+ */
+ public void setSpeed(float speed) {
+ mProvider.setSpeed_impl(speed);
+ }
+
+ /**
+ * Returns current speed setting.
+ *
+ * If setSpeed() has never been called, returns the default value 1.0f.
+ * @return current speed setting
+ * @hide
+ */
+ public float getSpeed() {
+ return mProvider.getSpeed_impl();
+ }
+
+ /**
+ * Sets which type of audio focus will be requested during the playback, or configures playback
+ * to not request audio focus. Valid values for focus requests are
+ * {@link AudioManager#AUDIOFOCUS_GAIN}, {@link AudioManager#AUDIOFOCUS_GAIN_TRANSIENT},
+ * {@link AudioManager#AUDIOFOCUS_GAIN_TRANSIENT_MAY_DUCK}, and
+ * {@link AudioManager#AUDIOFOCUS_GAIN_TRANSIENT_EXCLUSIVE}. Or use
+ * {@link AudioManager#AUDIOFOCUS_NONE} to express that audio focus should not be
+ * requested when playback starts. You can for instance use this when playing a silent animation
+ * through this class, and you don't want to affect other audio applications playing in the
+ * background.
+ *
+ * @param focusGain the type of audio focus gain that will be requested, or
+ * {@link AudioManager#AUDIOFOCUS_NONE} to disable the use audio focus during playback.
+ *
* @hide
*/
public void setAudioFocusRequest(int focusGain) {
@@ -168,6 +221,10 @@ public class VideoView2 extends FrameLayout {
}
/**
+ * Sets the {@link AudioAttributes} to be used during the playback of the video.
+ *
+ * @param attributes non-null <code>AudioAttributes</code>.
+ *
* @hide
*/
public void setAudioAttributes(@NonNull AudioAttributes attributes) {
@@ -175,6 +232,9 @@ public class VideoView2 extends FrameLayout {
}
/**
+ * Sets video path.
+ *
+ * @param path the path of the video.
* @hide
*/
public void setVideoPath(String path) {
@@ -198,13 +258,6 @@ public class VideoView2 extends FrameLayout {
/**
* @hide
*/
- public void setMediaController2(MediaController2 controllerView) {
- mProvider.setMediaController2_impl(controllerView);
- }
-
- /**
- * @hide
- */
public void setViewType(@ViewType int viewType) {
mProvider.setViewType_impl(viewType);
}
@@ -227,28 +280,28 @@ public class VideoView2 extends FrameLayout {
/**
* @hide
*/
- public void setOnPreparedListener(MediaPlayer.OnPreparedListener l) {
+ public void setOnPreparedListener(OnPreparedListener l) {
mProvider.setOnPreparedListener_impl(l);
}
/**
* @hide
*/
- public void setOnCompletionListener(MediaPlayer.OnCompletionListener l) {
+ public void setOnCompletionListener(OnCompletionListener l) {
mProvider.setOnCompletionListener_impl(l);
}
/**
* @hide
*/
- public void setOnErrorListener(MediaPlayer.OnErrorListener l) {
+ public void setOnErrorListener(OnErrorListener l) {
mProvider.setOnErrorListener_impl(l);
}
/**
* @hide
*/
- public void setOnInfoListener(MediaPlayer.OnInfoListener l) {
+ public void setOnInfoListener(OnInfoListener l) {
mProvider.setOnInfoListener_impl(l);
}
@@ -260,15 +313,61 @@ public class VideoView2 extends FrameLayout {
}
/**
+ * Interface definition of a callback to be invoked when the viw type has been changed.
* @hide
*/
public interface OnViewTypeChangedListener {
/**
- * @hide
+ * Called when the view type has been changed.
+ * @see VideoView2#setViewType(int)
*/
void onViewTypeChanged(@ViewType int viewType);
}
+ /**
+ * @hide
+ */
+ public interface OnPreparedListener {
+ /**
+ * Called when the media file is ready for playback.
+ */
+ void onPrepared();
+ }
+
+ /**
+ * @hide
+ */
+ public interface OnCompletionListener {
+ /**
+ * Called when the end of a media source is reached during playback.
+ */
+ void onCompletion();
+ }
+
+ /**
+ * @hide
+ */
+ public interface OnErrorListener {
+ /**
+ * Called to indicate an error.
+ */
+ boolean onError(int what, int extra);
+ }
+
+ /**
+ * @hide
+ */
+ public interface OnInfoListener {
+ /**
+ * Called to indicate an info or a warning.
+ * @see MediaPlayer#OnInfoListener
+ *
+ * @param what the type of info or warning.
+ * @param extra an extra code, specific to the info.
+ */
+ void onInfo(int what, int extra);
+ }
+
@Override
public CharSequence getAccessibilityClassName() {
return mProvider.getAccessibilityClassName_impl();
@@ -306,26 +405,6 @@ public class VideoView2 extends FrameLayout {
private class SuperProvider implements ViewProvider {
@Override
- public void onAttachedToWindow_impl() {
- VideoView2.super.onAttachedToWindow();
- }
-
- @Override
- public void onDetachedFromWindow_impl() {
- VideoView2.super.onDetachedFromWindow();
- }
-
- @Override
- public void onLayout_impl(boolean changed, int left, int top, int right, int bottom) {
- VideoView2.super.onLayout(changed, left, top, right, bottom);
- }
-
- @Override
- public void draw_impl(Canvas canvas) {
- VideoView2.super.draw(canvas);
- }
-
- @Override
public CharSequence getAccessibilityClassName_impl() {
return VideoView2.super.getAccessibilityClassName();
}
diff --git a/core/java/com/android/internal/app/IBatteryStats.aidl b/core/java/com/android/internal/app/IBatteryStats.aidl
index 388180dc61e0..e2d1ad59043e 100644
--- a/core/java/com/android/internal/app/IBatteryStats.aidl
+++ b/core/java/com/android/internal/app/IBatteryStats.aidl
@@ -23,6 +23,7 @@ import android.net.wifi.WifiActivityEnergyInfo;
import android.os.ParcelFileDescriptor;
import android.os.WorkSource;
import android.os.connectivity.CellularBatteryStats;
+import android.os.connectivity.GpsBatteryStats;
import android.os.health.HealthStatsParceler;
import android.telephony.DataConnectionRealTimeInfo;
import android.telephony.ModemActivityInfo;
@@ -91,6 +92,7 @@ interface IBatteryStats {
void noteVibratorOff(int uid);
void noteStartGps(int uid);
void noteStopGps(int uid);
+ void noteGpsSignalQuality(int signalLevel);
void noteScreenState(int state);
void noteScreenBrightness(int brightness);
void noteUserActivity(int uid, int event);
@@ -140,6 +142,9 @@ interface IBatteryStats {
/** {@hide} */
CellularBatteryStats getCellularBatteryStats();
+ /** {@hide} */
+ GpsBatteryStats getGpsBatteryStats();
+
HealthStatsParceler takeUidSnapshot(int uid);
HealthStatsParceler[] takeUidSnapshots(in int[] uid);
diff --git a/core/java/com/android/internal/net/NetworkStatsFactory.java b/core/java/com/android/internal/net/NetworkStatsFactory.java
index 5eda81baa364..02cd09f78af3 100644
--- a/core/java/com/android/internal/net/NetworkStatsFactory.java
+++ b/core/java/com/android/internal/net/NetworkStatsFactory.java
@@ -219,7 +219,7 @@ public class NetworkStatsFactory {
}
NetworkStats.Entry adjust =
- new NetworkStats.Entry(baseIface, 0, 0, 0, 0L, 0L, 0L, 0L, 0L);
+ new NetworkStats.Entry(baseIface, 0, 0, 0, 0, 0, 0, 0L, 0L, 0L, 0L, 0L);
// Subtract any 464lat traffic seen for the root UID on the current base interface.
adjust.rxBytes -= (entry.rxBytes + entry.rxPackets * IPV4V6_HEADER_DELTA);
adjust.txBytes -= (entry.txBytes + entry.txPackets * IPV4V6_HEADER_DELTA);
diff --git a/core/java/com/android/internal/os/BatteryStatsHelper.java b/core/java/com/android/internal/os/BatteryStatsHelper.java
index 15dc6f507093..5a59e70865e5 100644
--- a/core/java/com/android/internal/os/BatteryStatsHelper.java
+++ b/core/java/com/android/internal/os/BatteryStatsHelper.java
@@ -665,14 +665,14 @@ public class BatteryStatsHelper {
/**
* Calculate the baseline power usage for the device when it is in suspend and idle.
- * The device is drawing POWER_CPU_IDLE power at its lowest power state.
- * The device is drawing POWER_CPU_IDLE + POWER_CPU_AWAKE power when a wakelock is held.
+ * The device is drawing POWER_CPU_SUSPEND power at its lowest power state.
+ * The device is drawing POWER_CPU_SUSPEND + POWER_CPU_IDLE power when a wakelock is held.
*/
private void addIdleUsage() {
final double suspendPowerMaMs = (mTypeBatteryRealtimeUs / 1000) *
- mPowerProfile.getAveragePower(PowerProfile.POWER_CPU_IDLE);
+ mPowerProfile.getAveragePower(PowerProfile.POWER_CPU_SUSPEND);
final double idlePowerMaMs = (mTypeBatteryUptimeUs / 1000) *
- mPowerProfile.getAveragePower(PowerProfile.POWER_CPU_AWAKE);
+ mPowerProfile.getAveragePower(PowerProfile.POWER_CPU_IDLE);
final double totalPowerMah = (suspendPowerMaMs + idlePowerMaMs) / (60 * 60 * 1000);
if (DEBUG && totalPowerMah != 0) {
Log.d(TAG, "Suspend: time=" + (mTypeBatteryRealtimeUs / 1000)
diff --git a/core/java/com/android/internal/os/BatteryStatsImpl.java b/core/java/com/android/internal/os/BatteryStatsImpl.java
index ac5dbc4e175a..799e3e8d38d0 100644
--- a/core/java/com/android/internal/os/BatteryStatsImpl.java
+++ b/core/java/com/android/internal/os/BatteryStatsImpl.java
@@ -34,6 +34,7 @@ import android.os.BatteryManager;
import android.os.BatteryStats;
import android.os.Build;
import android.os.connectivity.CellularBatteryStats;
+import android.os.connectivity.GpsBatteryStats;
import android.os.FileUtils;
import android.os.Handler;
import android.os.IBatteryPropertiesRegistrar;
@@ -78,6 +79,7 @@ import android.view.Display;
import com.android.internal.annotations.GuardedBy;
import com.android.internal.annotations.VisibleForTesting;
+import com.android.internal.location.gnssmetrics.GnssMetrics;
import com.android.internal.net.NetworkStatsFactory;
import com.android.internal.util.ArrayUtils;
import com.android.internal.util.FastPrintWriter;
@@ -153,11 +155,11 @@ public class BatteryStatsImpl extends BatteryStats {
MAX_HISTORY_BUFFER = 96*1024; // 96KB
MAX_MAX_HISTORY_BUFFER = 128*1024; // 128KB
} else {
- MAX_HISTORY_ITEMS = 2000;
- MAX_MAX_HISTORY_ITEMS = 3000;
- MAX_WAKELOCKS_PER_UID = 100;
- MAX_HISTORY_BUFFER = 256*1024; // 256KB
- MAX_MAX_HISTORY_BUFFER = 320*1024; // 256KB
+ MAX_HISTORY_ITEMS = 4000;
+ MAX_MAX_HISTORY_ITEMS = 6000;
+ MAX_WAKELOCKS_PER_UID = 200;
+ MAX_HISTORY_BUFFER = 512*1024; // 512KB
+ MAX_MAX_HISTORY_BUFFER = 640*1024; // 640KB
}
}
@@ -198,6 +200,12 @@ public class BatteryStatsImpl extends BatteryStats {
protected KernelUidCpuFreqTimeReader mKernelUidCpuFreqTimeReader =
new KernelUidCpuFreqTimeReader();
@VisibleForTesting
+ protected KernelUidCpuActiveTimeReader mKernelUidCpuActiveTimeReader =
+ new KernelUidCpuActiveTimeReader();
+ @VisibleForTesting
+ protected KernelUidCpuClusterTimeReader mKernelUidCpuClusterTimeReader =
+ new KernelUidCpuClusterTimeReader();
+ @VisibleForTesting
protected KernelSingleUidTimeReader mKernelSingleUidTimeReader;
private final KernelMemoryBandwidthStats mKernelMemoryBandwidthStats
@@ -666,6 +674,10 @@ public class BatteryStatsImpl extends BatteryStats {
int mCameraOnNesting;
StopwatchTimer mCameraOnTimer;
+ int mGpsSignalQualityBin = -1;
+ final StopwatchTimer[] mGpsSignalQualityTimer =
+ new StopwatchTimer[GnssMetrics.NUM_GPS_SIGNAL_QUALITY_LEVELS];
+
int mPhoneSignalStrengthBin = -1;
int mPhoneSignalStrengthBinRaw = -1;
final StopwatchTimer[] mPhoneSignalStrengthsTimer =
@@ -3880,6 +3892,8 @@ public class BatteryStatsImpl extends BatteryStats {
}
mKernelUidCpuTimeReader.removeUid(isolatedUid);
mKernelUidCpuFreqTimeReader.removeUid(isolatedUid);
+ mKernelUidCpuActiveTimeReader.removeUid(isolatedUid);
+ mKernelUidCpuClusterTimeReader.removeUid(isolatedUid);
}
public int mapUid(int uid) {
@@ -4575,10 +4589,37 @@ public class BatteryStatsImpl extends BatteryStats {
if (DEBUG_HISTORY) Slog.v(TAG, "Stop GPS to: "
+ Integer.toHexString(mHistoryCur.states));
addHistoryRecordLocked(elapsedRealtime, uptime);
+ stopAllGpsSignalQualityTimersLocked(-1);
+ mGpsSignalQualityBin = -1;
}
getUidStatsLocked(uid).noteStopGps(elapsedRealtime);
}
+ public void noteGpsSignalQualityLocked(int signalLevel) {
+ if (mGpsNesting == 0) {
+ return;
+ }
+ if (signalLevel < 0 || signalLevel >= GnssMetrics.NUM_GPS_SIGNAL_QUALITY_LEVELS) {
+ stopAllGpsSignalQualityTimersLocked(-1);
+ return;
+ }
+ final long elapsedRealtime = mClocks.elapsedRealtime();
+ final long uptime = mClocks.uptimeMillis();
+ if (mGpsSignalQualityBin != signalLevel) {
+ if (mGpsSignalQualityBin >= 0) {
+ mGpsSignalQualityTimer[mGpsSignalQualityBin].stopRunningLocked(elapsedRealtime);
+ }
+ if(!mGpsSignalQualityTimer[signalLevel].isRunningLocked()) {
+ mGpsSignalQualityTimer[signalLevel].startRunningLocked(elapsedRealtime);
+ }
+ mHistoryCur.states2 = (mHistoryCur.states2&~HistoryItem.STATE2_GPS_SIGNAL_QUALITY_MASK)
+ | (signalLevel << HistoryItem.STATE2_GPS_SIGNAL_QUALITY_SHIFT);
+ addHistoryRecordLocked(elapsedRealtime, uptime);
+ mGpsSignalQualityBin = signalLevel;
+ }
+ return;
+ }
+
public void noteScreenStateLocked(int state) {
state = mPretendScreenOff ? Display.STATE_OFF : state;
@@ -4912,6 +4953,18 @@ public class BatteryStatsImpl extends BatteryStats {
mDailyPackageChanges.add(pc);
}
+ void stopAllGpsSignalQualityTimersLocked(int except) {
+ final long elapsedRealtime = mClocks.elapsedRealtime();
+ for (int i = 0; i < GnssMetrics.NUM_GPS_SIGNAL_QUALITY_LEVELS; i++) {
+ if (i == except) {
+ continue;
+ }
+ while (mGpsSignalQualityTimer[i].isRunningLocked()) {
+ mGpsSignalQualityTimer[i].stopRunningLocked(elapsedRealtime);
+ }
+ }
+ }
+
public void notePhoneOnLocked() {
if (!mPhoneOn) {
final long elapsedRealtime = mClocks.elapsedRealtime();
@@ -6123,6 +6176,20 @@ public class BatteryStatsImpl extends BatteryStats {
return val;
}
+ @Override public long getGpsSignalQualityTime(int strengthBin,
+ long elapsedRealtimeUs, int which) {
+ if (strengthBin < 0 || strengthBin >= GnssMetrics.NUM_GPS_SIGNAL_QUALITY_LEVELS) {
+ return 0;
+ }
+ return mGpsSignalQualityTimer[strengthBin].getTotalTimeLocked(
+ elapsedRealtimeUs, which);
+ }
+
+ @Override public long getGpsBatteryDrainMaMs() {
+ //TODO: Add GPS power computation (b/67213967)
+ return 0;
+ }
+
@Override public long getPhoneOnTime(long elapsedRealtimeUs, int which) {
return mPhoneOnTimer.getTotalTimeLocked(elapsedRealtimeUs, which);
}
@@ -6479,9 +6546,11 @@ public class BatteryStatsImpl extends BatteryStats {
LongSamplingCounter mUserCpuTime;
LongSamplingCounter mSystemCpuTime;
LongSamplingCounter[][] mCpuClusterSpeedTimesUs;
+ LongSamplingCounter mCpuActiveTimeMs;
LongSamplingCounterArray mCpuFreqTimeMs;
LongSamplingCounterArray mScreenOffCpuFreqTimeMs;
+ LongSamplingCounterArray mCpuClusterTimesMs;
LongSamplingCounterArray[] mProcStateTimeMs;
LongSamplingCounterArray[] mProcStateScreenOffTimeMs;
@@ -6551,6 +6620,8 @@ public class BatteryStatsImpl extends BatteryStats {
mUserCpuTime = new LongSamplingCounter(mBsi.mOnBatteryTimeBase);
mSystemCpuTime = new LongSamplingCounter(mBsi.mOnBatteryTimeBase);
+ mCpuActiveTimeMs = new LongSamplingCounter(mBsi.mOnBatteryTimeBase);
+ mCpuClusterTimesMs = new LongSamplingCounterArray(mBsi.mOnBatteryTimeBase);
mWakelockStats = mBsi.new OverflowArrayMap<Wakelock>(uid) {
@Override public Wakelock instantiateObject() {
@@ -6598,6 +6669,17 @@ public class BatteryStatsImpl extends BatteryStats {
}
@Override
+ public long getCpuActiveTime() {
+ return mCpuActiveTimeMs.getCountLocked(STATS_SINCE_CHARGED);
+ }
+
+ @Override
+ public long[] getCpuClusterTimes() {
+ return nullIfAllZeros(mCpuClusterTimesMs, STATS_SINCE_CHARGED);
+ }
+
+
+ @Override
public long[] getCpuFreqTimes(int which, int procState) {
if (which < 0 || which >= NUM_PROCESS_STATE) {
return null;
@@ -7660,6 +7742,9 @@ public class BatteryStatsImpl extends BatteryStats {
mScreenOffCpuFreqTimeMs.reset(false);
}
+ mCpuActiveTimeMs.reset(false);
+ mCpuClusterTimesMs.reset(false);
+
if (mProcStateTimeMs != null) {
for (LongSamplingCounterArray counters : mProcStateTimeMs) {
if (counters != null) {
@@ -7864,6 +7949,8 @@ public class BatteryStatsImpl extends BatteryStats {
if (mScreenOffCpuFreqTimeMs != null) {
mScreenOffCpuFreqTimeMs.detach();
}
+ mCpuActiveTimeMs.detach();
+ mCpuClusterTimesMs.detach();
if (mProcStateTimeMs != null) {
for (LongSamplingCounterArray counters : mProcStateTimeMs) {
@@ -8139,6 +8226,10 @@ public class BatteryStatsImpl extends BatteryStats {
LongSamplingCounterArray.writeToParcel(out, mCpuFreqTimeMs);
LongSamplingCounterArray.writeToParcel(out, mScreenOffCpuFreqTimeMs);
+
+ mCpuActiveTimeMs.writeToParcel(out);
+ mCpuClusterTimesMs.writeToParcel(out);
+
if (mProcStateTimeMs != null) {
out.writeInt(mProcStateTimeMs.length);
for (LongSamplingCounterArray counters : mProcStateTimeMs) {
@@ -8456,6 +8547,9 @@ public class BatteryStatsImpl extends BatteryStats {
mScreenOffCpuFreqTimeMs = LongSamplingCounterArray.readFromParcel(
in, mBsi.mOnBatteryScreenOffTimeBase);
+ mCpuActiveTimeMs = new LongSamplingCounter(mBsi.mOnBatteryTimeBase, in);
+ mCpuClusterTimesMs = new LongSamplingCounterArray(mBsi.mOnBatteryTimeBase, in);
+
int length = in.readInt();
if (length == NUM_PROCESS_STATE) {
mProcStateTimeMs = new LongSamplingCounterArray[length];
@@ -9822,6 +9916,10 @@ public class BatteryStatsImpl extends BatteryStats {
mWifiSignalStrengthsTimer[i] = new StopwatchTimer(mClocks, null, -800-i, null,
mOnBatteryTimeBase);
}
+ for (int i=0; i< GnssMetrics.NUM_GPS_SIGNAL_QUALITY_LEVELS; i++) {
+ mGpsSignalQualityTimer[i] = new StopwatchTimer(mClocks, null, -1000-i, null,
+ mOnBatteryTimeBase);
+ }
mAudioOnTimer = new StopwatchTimer(mClocks, null, -7, null, mOnBatteryTimeBase);
mVideoOnTimer = new StopwatchTimer(mClocks, null, -8, null, mOnBatteryTimeBase);
mFlashlightOnTimer = new StopwatchTimer(mClocks, null, -9, null, mOnBatteryTimeBase);
@@ -10511,6 +10609,9 @@ public class BatteryStatsImpl extends BatteryStats {
mWifiSignalStrengthsTimer[i].reset(false);
}
mWifiMulticastWakelockTimer.reset(false);
+ for (int i=0; i< GnssMetrics.NUM_GPS_SIGNAL_QUALITY_LEVELS; i++) {
+ mGpsSignalQualityTimer[i].reset(false);
+ }
mWifiActivity.reset(false);
mBluetoothActivity.reset(false);
mModemActivity.reset(false);
@@ -11437,6 +11538,8 @@ public class BatteryStatsImpl extends BatteryStats {
if (!mOnBatteryInternal) {
mKernelUidCpuTimeReader.readDelta(null);
mKernelUidCpuFreqTimeReader.readDelta(null);
+ mKernelUidCpuActiveTimeReader.readDelta(null);
+ mKernelUidCpuClusterTimeReader.readDelta(null);
for (int cluster = mKernelCpuSpeedReaders.length - 1; cluster >= 0; --cluster) {
mKernelCpuSpeedReaders[cluster].readDelta();
}
@@ -11453,6 +11556,8 @@ public class BatteryStatsImpl extends BatteryStats {
updateClusterSpeedTimes(updatedUids);
}
readKernelUidCpuFreqTimesLocked(partialTimersToConsider);
+ readKernelUidCpuActiveTimesLocked();
+ readKernelUidCpuClusterTimesLocked();
}
/**
@@ -11764,6 +11869,64 @@ public class BatteryStatsImpl extends BatteryStats {
}
}
+ /**
+ * Take a snapshot of the cpu active times spent by each uid and update the corresponding
+ * counters.
+ */
+ @VisibleForTesting
+ public void readKernelUidCpuActiveTimesLocked() {
+ final long startTimeMs = mClocks.uptimeMillis();
+ mKernelUidCpuActiveTimeReader.readDelta((uid, cpuActiveTimesUs) -> {
+ uid = mapUid(uid);
+ if (Process.isIsolated(uid)) {
+ mKernelUidCpuActiveTimeReader.removeUid(uid);
+ Slog.w(TAG, "Got active times for an isolated uid with no mapping: " + uid);
+ return;
+ }
+ if (!mUserInfoProvider.exists(UserHandle.getUserId(uid))) {
+ Slog.w(TAG, "Got active times for an invalid user's uid " + uid);
+ mKernelUidCpuActiveTimeReader.removeUid(uid);
+ return;
+ }
+ final Uid u = getUidStatsLocked(uid);
+ u.mCpuActiveTimeMs.addCountLocked(cpuActiveTimesUs);
+ });
+
+ final long elapsedTimeMs = mClocks.uptimeMillis() - startTimeMs;
+ if (DEBUG_ENERGY_CPU || elapsedTimeMs >= 100) {
+ Slog.d(TAG, "Reading cpu active times took " + elapsedTimeMs + "ms");
+ }
+ }
+
+ /**
+ * Take a snapshot of the cpu cluster times spent by each uid and update the corresponding
+ * counters.
+ */
+ @VisibleForTesting
+ public void readKernelUidCpuClusterTimesLocked() {
+ final long startTimeMs = mClocks.uptimeMillis();
+ mKernelUidCpuClusterTimeReader.readDelta((uid, cpuClusterTimesUs) -> {
+ uid = mapUid(uid);
+ if (Process.isIsolated(uid)) {
+ mKernelUidCpuClusterTimeReader.removeUid(uid);
+ Slog.w(TAG, "Got cluster times for an isolated uid with no mapping: " + uid);
+ return;
+ }
+ if (!mUserInfoProvider.exists(UserHandle.getUserId(uid))) {
+ Slog.w(TAG, "Got cluster times for an invalid user's uid " + uid);
+ mKernelUidCpuClusterTimeReader.removeUid(uid);
+ return;
+ }
+ final Uid u = getUidStatsLocked(uid);
+ u.mCpuClusterTimesMs.addCountLocked(cpuClusterTimesUs);
+ });
+
+ final long elapsedTimeMs = mClocks.uptimeMillis() - startTimeMs;
+ if (DEBUG_ENERGY_CPU || elapsedTimeMs >= 100) {
+ Slog.d(TAG, "Reading cpu cluster times took " + elapsedTimeMs + "ms");
+ }
+ }
+
boolean setChargingLocked(boolean charging) {
if (mCharging != charging) {
mCharging = charging;
@@ -12367,6 +12530,21 @@ public class BatteryStatsImpl extends BatteryStats {
return s;
}
+ /*@hide */
+ public GpsBatteryStats getGpsBatteryStats() {
+ GpsBatteryStats s = new GpsBatteryStats();
+ final int which = STATS_SINCE_CHARGED;
+ final long rawRealTime = SystemClock.elapsedRealtime() * 1000;
+ s.setLoggingDurationMs(computeBatteryRealtime(rawRealTime, which) / 1000);
+ s.setEnergyConsumedMaMs(getGpsBatteryDrainMaMs());
+ long[] time = new long[GnssMetrics.NUM_GPS_SIGNAL_QUALITY_LEVELS];
+ for (int i=0; i<time.length; i++) {
+ time[i] = getGpsSignalQualityTime(i, rawRealTime, which) / 1000;
+ }
+ s.setTimeInGpsSignalQualityLevel(time);
+ return s;
+ }
+
@Override
public LevelStepTracker getChargeLevelStepTracker() {
return mChargeStepTracker;
@@ -13044,6 +13222,9 @@ public class BatteryStatsImpl extends BatteryStats {
for (int i=0; i<NUM_WIFI_SIGNAL_STRENGTH_BINS; i++) {
mWifiSignalStrengthsTimer[i].readSummaryFromParcelLocked(in);
}
+ for (int i=0; i<GnssMetrics.NUM_GPS_SIGNAL_QUALITY_LEVELS; i++) {
+ mGpsSignalQualityTimer[i].readSummaryFromParcelLocked(in);
+ }
mWifiActivity.readSummaryFromParcel(in);
mBluetoothActivity.readSummaryFromParcel(in);
mModemActivity.readSummaryFromParcel(in);
@@ -13249,6 +13430,10 @@ public class BatteryStatsImpl extends BatteryStats {
in, mOnBatteryTimeBase);
u.mScreenOffCpuFreqTimeMs = LongSamplingCounterArray.readSummaryFromParcelLocked(
in, mOnBatteryScreenOffTimeBase);
+
+ u.mCpuActiveTimeMs.readSummaryFromParcelLocked(in);
+ u.mCpuClusterTimesMs.readSummaryFromParcelLocked(in);
+
int length = in.readInt();
if (length == Uid.NUM_PROCESS_STATE) {
u.mProcStateTimeMs = new LongSamplingCounterArray[length];
@@ -13482,6 +13667,9 @@ public class BatteryStatsImpl extends BatteryStats {
for (int i=0; i<NUM_WIFI_SIGNAL_STRENGTH_BINS; i++) {
mWifiSignalStrengthsTimer[i].writeSummaryFromParcelLocked(out, NOWREAL_SYS);
}
+ for (int i=0; i< GnssMetrics.NUM_GPS_SIGNAL_QUALITY_LEVELS; i++) {
+ mGpsSignalQualityTimer[i].writeSummaryFromParcelLocked(out, NOWREAL_SYS);
+ }
mWifiActivity.writeSummaryToParcel(out);
mBluetoothActivity.writeSummaryToParcel(out);
mModemActivity.writeSummaryToParcel(out);
@@ -13725,6 +13913,9 @@ public class BatteryStatsImpl extends BatteryStats {
LongSamplingCounterArray.writeSummaryToParcelLocked(out, u.mCpuFreqTimeMs);
LongSamplingCounterArray.writeSummaryToParcelLocked(out, u.mScreenOffCpuFreqTimeMs);
+ u.mCpuActiveTimeMs.writeSummaryFromParcelLocked(out);
+ u.mCpuClusterTimesMs.writeSummaryToParcelLocked(out);
+
if (u.mProcStateTimeMs != null) {
out.writeInt(u.mProcStateTimeMs.length);
for (LongSamplingCounterArray counters : u.mProcStateTimeMs) {
@@ -13954,7 +14145,10 @@ public class BatteryStatsImpl extends BatteryStats {
mWifiSignalStrengthsTimer[i] = new StopwatchTimer(mClocks, null, -800-i,
null, mOnBatteryTimeBase, in);
}
-
+ for (int i=0; i<GnssMetrics.NUM_GPS_SIGNAL_QUALITY_LEVELS; i++) {
+ mGpsSignalQualityTimer[i] = new StopwatchTimer(mClocks, null, -1000-i,
+ null, mOnBatteryTimeBase, in);
+ }
mWifiActivity = new ControllerActivityCounterImpl(mOnBatteryTimeBase,
NUM_WIFI_TX_LEVELS, in);
mBluetoothActivity = new ControllerActivityCounterImpl(mOnBatteryTimeBase,
@@ -14154,6 +14348,9 @@ public class BatteryStatsImpl extends BatteryStats {
for (int i=0; i<NUM_WIFI_SIGNAL_STRENGTH_BINS; i++) {
mWifiSignalStrengthsTimer[i].writeToParcel(out, uSecRealtime);
}
+ for (int i=0; i< GnssMetrics.NUM_GPS_SIGNAL_QUALITY_LEVELS; i++) {
+ mGpsSignalQualityTimer[i].writeToParcel(out, uSecRealtime);
+ }
mWifiActivity.writeToParcel(out, 0);
mBluetoothActivity.writeToParcel(out, 0);
mModemActivity.writeToParcel(out, 0);
@@ -14348,6 +14545,10 @@ public class BatteryStatsImpl extends BatteryStats {
pr.println("*** Wifi signal strength #" + i + ":");
mWifiSignalStrengthsTimer[i].logState(pr, " ");
}
+ for (int i=0; i<GnssMetrics.NUM_GPS_SIGNAL_QUALITY_LEVELS; i++) {
+ pr.println("*** GPS signal quality #" + i + ":");
+ mGpsSignalQualityTimer[i].logState(pr, " ");
+ }
pr.println("*** Flashlight timer:");
mFlashlightOnTimer.logState(pr, " ");
pr.println("*** Camera timer:");
diff --git a/core/java/com/android/internal/os/CpuPowerCalculator.java b/core/java/com/android/internal/os/CpuPowerCalculator.java
index bb743c157d1f..a34e7f50c9c9 100644
--- a/core/java/com/android/internal/os/CpuPowerCalculator.java
+++ b/core/java/com/android/internal/os/CpuPowerCalculator.java
@@ -31,8 +31,7 @@ public class CpuPowerCalculator extends PowerCalculator {
@Override
public void calculateApp(BatterySipper app, BatteryStats.Uid u, long rawRealtimeUs,
- long rawUptimeUs, int statsType) {
-
+ long rawUptimeUs, int statsType) {
app.cpuTimeMs = (u.getUserCpuTimeUs(statsType) + u.getSystemCpuTimeUs(statsType)) / 1000;
final int numClusters = mProfile.getNumCpuClusters();
@@ -42,7 +41,7 @@ public class CpuPowerCalculator extends PowerCalculator {
for (int speed = 0; speed < speedsForCluster; speed++) {
final long timeUs = u.getTimeAtCpuSpeed(cluster, speed, statsType);
final double cpuSpeedStepPower = timeUs *
- mProfile.getAveragePowerForCpu(cluster, speed);
+ mProfile.getAveragePowerForCpuCore(cluster, speed);
if (DEBUG) {
Log.d(TAG, "UID " + u.getUid() + ": CPU cluster #" + cluster + " step #"
+ speed + " timeUs=" + timeUs + " power="
@@ -51,6 +50,25 @@ public class CpuPowerCalculator extends PowerCalculator {
cpuPowerMaUs += cpuSpeedStepPower;
}
}
+ cpuPowerMaUs += u.getCpuActiveTime() * mProfile.getAveragePower(
+ PowerProfile.POWER_CPU_ACTIVE);
+ long[] cpuClusterTimes = u.getCpuClusterTimes();
+ if (cpuClusterTimes != null) {
+ if (cpuClusterTimes.length == numClusters) {
+ for (int i = 0; i < numClusters; i++) {
+ double power = cpuClusterTimes[i] * mProfile.getAveragePowerForCpuCluster(i);
+ cpuPowerMaUs += power;
+ if (DEBUG) {
+ Log.d(TAG, "UID " + u.getUid() + ": CPU cluster #" + i + " clusterTimeUs="
+ + cpuClusterTimes[i] + " power="
+ + BatteryStatsHelper.makemAh(power / MICROSEC_IN_HR));
+ }
+ }
+ } else {
+ Log.w(TAG, "UID " + u.getUid() + " CPU cluster # mismatch: Power Profile # "
+ + numClusters + " actual # " + cpuClusterTimes.length);
+ }
+ }
app.cpuPowerMah = cpuPowerMaUs / MICROSEC_IN_HR;
if (DEBUG && (app.cpuTimeMs != 0 || app.cpuPowerMah != 0)) {
diff --git a/core/java/com/android/internal/os/KernelUidCpuActiveTimeReader.java b/core/java/com/android/internal/os/KernelUidCpuActiveTimeReader.java
new file mode 100644
index 000000000000..cb96c5cdfb60
--- /dev/null
+++ b/core/java/com/android/internal/os/KernelUidCpuActiveTimeReader.java
@@ -0,0 +1,146 @@
+/*
+ * 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.os;
+
+import android.annotation.Nullable;
+import android.os.StrictMode;
+import android.os.SystemClock;
+import android.util.Slog;
+import android.util.SparseArray;
+import android.util.TimeUtils;
+
+import com.android.internal.annotations.VisibleForTesting;
+
+import java.io.BufferedReader;
+import java.io.FileReader;
+import java.io.IOException;
+
+/**
+ * Reads /proc/uid_concurrent_active_time which has the format:
+ * active: X (X is # cores)
+ * [uid0]: [time-0] [time-1] [time-2] ... (# entries = # cores)
+ * [uid1]: [time-0] [time-1] [time-2] ... ...
+ * ...
+ * Time-N means the CPU time a UID spent running concurrently with N other processes.
+ * The file contains a monotonically increasing count of time for a single boot. This class
+ * maintains the previous results of a call to {@link #readDelta} in order to provide a
+ * proper delta.
+ */
+public class KernelUidCpuActiveTimeReader {
+ private static final boolean DEBUG = false;
+ private static final String TAG = "KernelUidCpuActiveTimeReader";
+ private static final String UID_TIMES_PROC_FILE = "/proc/uid_concurrent_active_time";
+
+ private int mCoreCount;
+ private long mLastTimeReadMs;
+ private long mNowTimeMs;
+ private SparseArray<long[]> mLastUidCpuActiveTimeMs = new SparseArray<>();
+
+ public interface Callback {
+ void onUidCpuActiveTime(int uid, long cpuActiveTimeMs);
+ }
+
+ public void readDelta(@Nullable Callback cb) {
+ final int oldMask = StrictMode.allowThreadDiskReadsMask();
+ try (BufferedReader reader = new BufferedReader(new FileReader(UID_TIMES_PROC_FILE))) {
+ mNowTimeMs = SystemClock.elapsedRealtime();
+ readDeltaInternal(reader, cb);
+ mLastTimeReadMs = mNowTimeMs;
+ } catch (IOException e) {
+ Slog.e(TAG, "Failed to read " + UID_TIMES_PROC_FILE + ": " + e);
+ } finally {
+ StrictMode.setThreadPolicyMask(oldMask);
+ }
+ }
+
+ public void removeUid(int uid) {
+ mLastUidCpuActiveTimeMs.delete(uid);
+ }
+
+ public void removeUidsInRange(int startUid, int endUid) {
+ if (endUid < startUid) {
+ Slog.w(TAG, "End UID " + endUid + " is smaller than start UID " + startUid);
+ return;
+ }
+ mLastUidCpuActiveTimeMs.put(startUid, null);
+ mLastUidCpuActiveTimeMs.put(endUid, null);
+ final int firstIndex = mLastUidCpuActiveTimeMs.indexOfKey(startUid);
+ final int lastIndex = mLastUidCpuActiveTimeMs.indexOfKey(endUid);
+ mLastUidCpuActiveTimeMs.removeAtRange(firstIndex, lastIndex - firstIndex + 1);
+ }
+
+ @VisibleForTesting
+ public void readDeltaInternal(BufferedReader reader, @Nullable Callback cb) throws IOException {
+ String line = reader.readLine();
+ if (line == null || !line.startsWith("active:")) {
+ Slog.e(TAG, String.format("Malformed proc file: %s ", UID_TIMES_PROC_FILE));
+ return;
+ }
+ if (mCoreCount == 0) {
+ mCoreCount = Integer.parseInt(line.substring(line.indexOf(' ')+1));
+ }
+ while ((line = reader.readLine()) != null) {
+ final int index = line.indexOf(' ');
+ final int uid = Integer.parseInt(line.substring(0, index - 1), 10);
+ readTimesForUid(uid, line.substring(index + 1), cb);
+ }
+ }
+
+ private void readTimesForUid(int uid, String line, @Nullable Callback cb) {
+ long[] lastActiveTime = mLastUidCpuActiveTimeMs.get(uid);
+ if (lastActiveTime == null) {
+ lastActiveTime = new long[mCoreCount];
+ mLastUidCpuActiveTimeMs.put(uid, lastActiveTime);
+ }
+ final String[] timesStr = line.split(" ");
+ if (timesStr.length != mCoreCount) {
+ Slog.e(TAG, String.format("# readings don't match # cores, readings: %d, CPU cores: %d",
+ timesStr.length, mCoreCount));
+ return;
+ }
+ long sumDeltas = 0;
+ final long[] curActiveTime = new long[mCoreCount];
+ boolean notify = false;
+ for (int i = 0; i < mCoreCount; i++) {
+ // Times read will be in units of 10ms
+ curActiveTime[i] = Long.parseLong(timesStr[i], 10) * 10;
+ long delta = curActiveTime[i] - lastActiveTime[i];
+ if (delta < 0 || curActiveTime[i] < 0) {
+ if (DEBUG) {
+ final StringBuilder sb = new StringBuilder();
+ sb.append(String.format("Malformed cpu active time for UID=%d\n", uid));
+ sb.append(String.format("data=(%d,%d)\n", lastActiveTime[i], curActiveTime[i]));
+ sb.append("times=(");
+ TimeUtils.formatDuration(mLastTimeReadMs, sb);
+ sb.append(",");
+ TimeUtils.formatDuration(mNowTimeMs, sb);
+ sb.append(")");
+ Slog.e(TAG, sb.toString());
+ }
+ return;
+ }
+ notify |= delta > 0;
+ sumDeltas += delta / (i + 1);
+ }
+ if (notify) {
+ System.arraycopy(curActiveTime, 0, lastActiveTime, 0, mCoreCount);
+ if (cb != null) {
+ cb.onUidCpuActiveTime(uid, sumDeltas);
+ }
+ }
+ }
+}
diff --git a/core/java/com/android/internal/os/KernelUidCpuClusterTimeReader.java b/core/java/com/android/internal/os/KernelUidCpuClusterTimeReader.java
new file mode 100644
index 000000000000..85153bc45d07
--- /dev/null
+++ b/core/java/com/android/internal/os/KernelUidCpuClusterTimeReader.java
@@ -0,0 +1,178 @@
+/*
+ * 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.os;
+
+import android.annotation.Nullable;
+import android.os.StrictMode;
+import android.os.SystemClock;
+import android.util.Slog;
+import android.util.SparseArray;
+import android.util.TimeUtils;
+
+import com.android.internal.annotations.VisibleForTesting;
+
+import java.io.BufferedReader;
+import java.io.FileReader;
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * Reads /proc/uid_concurrent_policy_time which has the format:
+ * policy0: X policy4: Y (there are X cores on policy0, Y cores on policy4)
+ * [uid0]: [time-0-0] [time-0-1] ... [time-1-0] [time-1-1] ...
+ * [uid1]: [time-0-0] [time-0-1] ... [time-1-0] [time-1-1] ...
+ * ...
+ * Time-X-Y means the time a UID spent on clusterX running concurrently with Y other processes.
+ * The file contains a monotonically increasing count of time for a single boot. This class
+ * maintains the previous results of a call to {@link #readDelta} in order to provide a proper
+ * delta.
+ */
+public class KernelUidCpuClusterTimeReader {
+
+ private static final boolean DEBUG = false;
+ private static final String TAG = "KernelUidCpuClusterTimeReader";
+ private static final String UID_TIMES_PROC_FILE = "/proc/uid_concurrent_policy_time";
+
+ // mCoreOnCluster[i] is the # of cores on cluster i
+ private int[] mCoreOnCluster;
+ private int mCores;
+ private long mLastTimeReadMs;
+ private long mNowTimeMs;
+ private SparseArray<long[]> mLastUidPolicyTimeMs = new SparseArray<>();
+
+ public interface Callback {
+ /**
+ * @param uid
+ * @param cpuActiveTimeMs the first dimension is cluster, the second dimension is the # of
+ * processes running concurrently with this uid.
+ */
+ void onUidCpuPolicyTime(int uid, long[] cpuActiveTimeMs);
+ }
+
+ public void readDelta(@Nullable Callback cb) {
+ final int oldMask = StrictMode.allowThreadDiskReadsMask();
+ try (BufferedReader reader = new BufferedReader(new FileReader(UID_TIMES_PROC_FILE))) {
+ mNowTimeMs = SystemClock.elapsedRealtime();
+ readDeltaInternal(reader, cb);
+ mLastTimeReadMs = mNowTimeMs;
+ } catch (IOException e) {
+ Slog.e(TAG, "Failed to read " + UID_TIMES_PROC_FILE + ": " + e);
+ } finally {
+ StrictMode.setThreadPolicyMask(oldMask);
+ }
+ }
+
+ public void removeUid(int uid) {
+ mLastUidPolicyTimeMs.delete(uid);
+ }
+
+ public void removeUidsInRange(int startUid, int endUid) {
+ if (endUid < startUid) {
+ Slog.w(TAG, "End UID " + endUid + " is smaller than start UID " + startUid);
+ return;
+ }
+ mLastUidPolicyTimeMs.put(startUid, null);
+ mLastUidPolicyTimeMs.put(endUid, null);
+ final int firstIndex = mLastUidPolicyTimeMs.indexOfKey(startUid);
+ final int lastIndex = mLastUidPolicyTimeMs.indexOfKey(endUid);
+ mLastUidPolicyTimeMs.removeAtRange(firstIndex, lastIndex - firstIndex + 1);
+ }
+
+ @VisibleForTesting
+ public void readDeltaInternal(BufferedReader reader, @Nullable Callback cb) throws IOException {
+ String line = reader.readLine();
+ if (line == null || !line.startsWith("policy")) {
+ Slog.e(TAG, String.format("Malformed proc file: %s ", UID_TIMES_PROC_FILE));
+ return;
+ }
+ if (mCoreOnCluster == null) {
+ List<Integer> list = new ArrayList<>();
+ String[] policies = line.split(" ");
+
+ if (policies.length == 0 || policies.length % 2 != 0) {
+ Slog.e(TAG, String.format("Malformed proc file: %s ", UID_TIMES_PROC_FILE));
+ return;
+ }
+
+ for (int i = 0; i < policies.length; i+=2) {
+ list.add(Integer.parseInt(policies[i+1]));
+ }
+
+ mCoreOnCluster = new int[list.size()];
+ for(int i=0;i<list.size();i++){
+ mCoreOnCluster[i] = list.get(i);
+ mCores += mCoreOnCluster[i];
+ }
+ }
+ while ((line = reader.readLine()) != null) {
+ final int index = line.indexOf(' ');
+ final int uid = Integer.parseInt(line.substring(0, index - 1), 10);
+ readTimesForUid(uid, line.substring(index + 1), cb);
+ }
+ }
+
+ private void readTimesForUid(int uid, String line, @Nullable Callback cb) {
+ long[] lastPolicyTime = mLastUidPolicyTimeMs.get(uid);
+ if (lastPolicyTime == null) {
+ lastPolicyTime = new long[mCores];
+ mLastUidPolicyTimeMs.put(uid, lastPolicyTime);
+ }
+ final String[] timeStr = line.split(" ");
+ if (timeStr.length != mCores) {
+ Slog.e(TAG, String.format("# readings don't match # cores, readings: %d, # CPU cores: %d",
+ timeStr.length, mCores));
+ return;
+ }
+ final long[] deltaPolicyTime = new long[mCores];
+ final long[] currPolicyTime = new long[mCores];
+ boolean notify = false;
+ for (int i = 0; i < mCores; i++) {
+ // Times read will be in units of 10ms
+ currPolicyTime[i] = Long.parseLong(timeStr[i], 10) * 10;
+ deltaPolicyTime[i] = currPolicyTime[i] - lastPolicyTime[i];
+ if (deltaPolicyTime[i] < 0 || currPolicyTime[i] < 0) {
+ if (DEBUG) {
+ final StringBuilder sb = new StringBuilder();
+ sb.append(String.format("Malformed cpu policy time for UID=%d\n", uid));
+ sb.append(String.format("data=(%d,%d)\n", lastPolicyTime[i], currPolicyTime[i]));
+ sb.append("times=(");
+ TimeUtils.formatDuration(mLastTimeReadMs, sb);
+ sb.append(",");
+ TimeUtils.formatDuration(mNowTimeMs, sb);
+ sb.append(")");
+ Slog.e(TAG, sb.toString());
+ }
+ return;
+ }
+ notify |= deltaPolicyTime[i] > 0;
+ }
+ if (notify) {
+ System.arraycopy(currPolicyTime, 0, lastPolicyTime, 0, mCores);
+ if (cb != null) {
+ final long[] times = new long[mCoreOnCluster.length];
+ int core = 0;
+ for (int i = 0; i < mCoreOnCluster.length; i++) {
+ for (int j = 0; j < mCoreOnCluster[i]; j++) {
+ times[i] += deltaPolicyTime[core++] / (j+1);
+ }
+ }
+ cb.onUidCpuPolicyTime(uid, times);
+ }
+ }
+ }
+}
diff --git a/core/java/com/android/internal/os/PowerProfile.java b/core/java/com/android/internal/os/PowerProfile.java
index 872b465a9ca5..fcbbcd036740 100644
--- a/core/java/com/android/internal/os/PowerProfile.java
+++ b/core/java/com/android/internal/os/PowerProfile.java
@@ -21,6 +21,7 @@ import android.content.Context;
import android.content.res.Resources;
import android.content.res.XmlResourceParser;
+import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.util.XmlUtils;
import org.xmlpull.v1.XmlPullParser;
@@ -43,23 +44,25 @@ public class PowerProfile {
public static final String POWER_NONE = "none";
/**
- * Power consumption when CPU is in power collapse mode.
+ * POWER_CPU_SUSPEND: Power consumption when CPU is in power collapse mode.
+ * POWER_CPU_IDLE: Power consumption when CPU is awake (when a wake lock is held). This should
+ * be zero on devices that can go into full CPU power collapse even when a wake
+ * lock is held. Otherwise, this is the power consumption in addition to
+ * POWER_CPU_SUSPEND due to a wake lock being held but with no CPU activity.
+ * POWER_CPU_ACTIVE: Power consumption when CPU is running, excluding power consumed by clusters
+ * and cores.
+ *
+ * CPU Power Equation (assume two clusters):
+ * Total power = POWER_CPU_SUSPEND (always added)
+ * + POWER_CPU_IDLE (skip this and below if in power collapse mode)
+ * + POWER_CPU_ACTIVE (skip this and below if CPU is not running, but a wakelock
+ * is held)
+ * + cluster_power.cluster0 + cluster_power.cluster1 (skip cluster not running)
+ * + core_power.cluster0 * num running cores in cluster 0
+ * + core_power.cluster1 * num running cores in cluster 1
*/
+ public static final String POWER_CPU_SUSPEND = "cpu.suspend";
public static final String POWER_CPU_IDLE = "cpu.idle";
-
- /**
- * Power consumption when CPU is awake (when a wake lock is held). This
- * should be 0 on devices that can go into full CPU power collapse even
- * when a wake lock is held. Otherwise, this is the power consumption in
- * addition to POWER_CPU_IDLE due to a wake lock being held but with no
- * CPU activity.
- */
- public static final String POWER_CPU_AWAKE = "cpu.awake";
-
- /**
- * Power consumption when CPU is in power collapse mode.
- */
- @Deprecated
public static final String POWER_CPU_ACTIVE = "cpu.active";
/**
@@ -182,9 +185,6 @@ public class PowerProfile {
*/
public static final String POWER_CAMERA = "camera.avg";
- @Deprecated
- public static final String POWER_CPU_SPEEDS = "cpu.speeds";
-
/**
* Power consumed by wif batched scaning. Broken down into bins by
* Channels Scanned per Hour. May do 1-720 scans per hour of 1-100 channels
@@ -197,7 +197,15 @@ public class PowerProfile {
*/
public static final String POWER_BATTERY_CAPACITY = "battery.capacity";
- static final HashMap<String, Object> sPowerMap = new HashMap<>();
+ /**
+ * A map from Power Use Item to its power consumption.
+ */
+ static final HashMap<String, Double> sPowerItemMap = new HashMap<>();
+ /**
+ * A map from Power Use Item to an array of its power consumption
+ * (for items with variable power e.g. CPU).
+ */
+ static final HashMap<String, Double[]> sPowerArrayMap = new HashMap<>();
private static final String TAG_DEVICE = "device";
private static final String TAG_ITEM = "item";
@@ -207,23 +215,32 @@ public class PowerProfile {
private static final Object sLock = new Object();
+ @VisibleForTesting
public PowerProfile(Context context) {
- // Read the XML file for the given profile (normally only one per
- // device)
+ this(context, false);
+ }
+
+ /**
+ * For PowerProfileTest
+ */
+ @VisibleForTesting
+ public PowerProfile(Context context, boolean forTest) {
+ // Read the XML file for the given profile (normally only one per device)
synchronized (sLock) {
- if (sPowerMap.size() == 0) {
- readPowerValuesFromXml(context);
+ if (sPowerItemMap.size() == 0 && sPowerArrayMap.size() == 0) {
+ readPowerValuesFromXml(context, forTest);
}
initCpuClusters();
}
}
- private void readPowerValuesFromXml(Context context) {
- int id = com.android.internal.R.xml.power_profile;
+ private void readPowerValuesFromXml(Context context, boolean forTest) {
+ final int id = forTest ? com.android.internal.R.xml.power_profile_test :
+ com.android.internal.R.xml.power_profile;
final Resources resources = context.getResources();
XmlResourceParser parser = resources.getXml(id);
boolean parsingArray = false;
- ArrayList<Double> array = new ArrayList<Double>();
+ ArrayList<Double> array = new ArrayList<>();
String arrayName = null;
try {
@@ -237,7 +254,7 @@ public class PowerProfile {
if (parsingArray && !element.equals(TAG_ARRAYITEM)) {
// Finish array
- sPowerMap.put(arrayName, array.toArray(new Double[array.size()]));
+ sPowerArrayMap.put(arrayName, array.toArray(new Double[array.size()]));
parsingArray = false;
}
if (element.equals(TAG_ARRAY)) {
@@ -255,7 +272,7 @@ public class PowerProfile {
} catch (NumberFormatException nfe) {
}
if (element.equals(TAG_ITEM)) {
- sPowerMap.put(name, value);
+ sPowerItemMap.put(name, value);
} else if (parsingArray) {
array.add(value);
}
@@ -263,7 +280,7 @@ public class PowerProfile {
}
}
if (parsingArray) {
- sPowerMap.put(arrayName, array.toArray(new Double[array.size()]));
+ sPowerArrayMap.put(arrayName, array.toArray(new Double[array.size()]));
}
} catch (XmlPullParserException e) {
throw new RuntimeException(e);
@@ -300,52 +317,56 @@ public class PowerProfile {
String key = configResIdKeys[i];
// if we already have some of these parameters in power_profile.xml, ignore the
// value in config.xml
- if ((sPowerMap.containsKey(key) && (Double) sPowerMap.get(key) > 0)) {
+ if ((sPowerItemMap.containsKey(key) && sPowerItemMap.get(key) > 0)) {
continue;
}
int value = resources.getInteger(configResIds[i]);
if (value > 0) {
- sPowerMap.put(key, (double) value);
+ sPowerItemMap.put(key, (double) value);
}
}
}
private CpuClusterKey[] mCpuClusters;
- private static final String POWER_CPU_CLUSTER_CORE_COUNT = "cpu.clusters.cores";
- private static final String POWER_CPU_CLUSTER_SPEED_PREFIX = "cpu.speeds.cluster";
- private static final String POWER_CPU_CLUSTER_ACTIVE_PREFIX = "cpu.active.cluster";
+ private static final String CPU_PER_CLUSTER_CORE_COUNT = "cpu.clusters.cores";
+ private static final String CPU_CLUSTER_POWER_COUNT = "cpu.cluster_power.cluster";
+ private static final String CPU_CORE_SPEED_PREFIX = "cpu.core_speeds.cluster";
+ private static final String CPU_CORE_POWER_PREFIX = "cpu.core_power.cluster";
- @SuppressWarnings("deprecation")
private void initCpuClusters() {
- // Figure out how many CPU clusters we're dealing with
- final Object obj = sPowerMap.get(POWER_CPU_CLUSTER_CORE_COUNT);
- if (obj == null || !(obj instanceof Double[])) {
+ if (sPowerArrayMap.containsKey(CPU_PER_CLUSTER_CORE_COUNT)) {
+ final Double[] data = sPowerArrayMap.get(CPU_PER_CLUSTER_CORE_COUNT);
+ mCpuClusters = new CpuClusterKey[data.length];
+ for (int cluster = 0; cluster < data.length; cluster++) {
+ int numCpusInCluster = (int) Math.round(data[cluster]);
+ mCpuClusters[cluster] = new CpuClusterKey(
+ CPU_CORE_SPEED_PREFIX + cluster, CPU_CLUSTER_POWER_COUNT + cluster,
+ CPU_CORE_POWER_PREFIX + cluster, numCpusInCluster);
+ }
+ } else {
// Default to single.
mCpuClusters = new CpuClusterKey[1];
- mCpuClusters[0] = new CpuClusterKey(POWER_CPU_SPEEDS, POWER_CPU_ACTIVE, 1);
-
- } else {
- final Double[] array = (Double[]) obj;
- mCpuClusters = new CpuClusterKey[array.length];
- for (int cluster = 0; cluster < array.length; cluster++) {
- int numCpusInCluster = (int) Math.round(array[cluster]);
- mCpuClusters[cluster] = new CpuClusterKey(
- POWER_CPU_CLUSTER_SPEED_PREFIX + cluster,
- POWER_CPU_CLUSTER_ACTIVE_PREFIX + cluster,
- numCpusInCluster);
+ int numCpus = 1;
+ if (sPowerItemMap.containsKey(CPU_PER_CLUSTER_CORE_COUNT)) {
+ numCpus = (int) Math.round(sPowerItemMap.get(CPU_PER_CLUSTER_CORE_COUNT));
}
+ mCpuClusters[0] = new CpuClusterKey(CPU_CORE_SPEED_PREFIX + 0,
+ CPU_CLUSTER_POWER_COUNT + 0, CPU_CORE_POWER_PREFIX + 0, numCpus);
}
}
public static class CpuClusterKey {
- private final String timeKey;
- private final String powerKey;
+ private final String freqKey;
+ private final String clusterPowerKey;
+ private final String corePowerKey;
private final int numCpus;
- private CpuClusterKey(String timeKey, String powerKey, int numCpus) {
- this.timeKey = timeKey;
- this.powerKey = powerKey;
+ private CpuClusterKey(String freqKey, String clusterPowerKey,
+ String corePowerKey, int numCpus) {
+ this.freqKey = freqKey;
+ this.clusterPowerKey = clusterPowerKey;
+ this.corePowerKey = corePowerKey;
this.numCpus = numCpus;
}
}
@@ -354,21 +375,30 @@ public class PowerProfile {
return mCpuClusters.length;
}
- public int getNumCoresInCpuCluster(int index) {
- return mCpuClusters[index].numCpus;
+ public int getNumCoresInCpuCluster(int cluster) {
+ return mCpuClusters[cluster].numCpus;
}
- public int getNumSpeedStepsInCpuCluster(int index) {
- Object value = sPowerMap.get(mCpuClusters[index].timeKey);
- if (value != null && value instanceof Double[]) {
- return ((Double[])value).length;
+ public int getNumSpeedStepsInCpuCluster(int cluster) {
+ if (cluster < 0 || cluster >= mCpuClusters.length) {
+ return 0; // index out of bound
+ }
+ if (sPowerArrayMap.containsKey(mCpuClusters[cluster].freqKey)) {
+ return sPowerArrayMap.get(mCpuClusters[cluster].freqKey).length;
}
return 1; // Only one speed
}
- public double getAveragePowerForCpu(int cluster, int step) {
+ public double getAveragePowerForCpuCluster(int cluster) {
if (cluster >= 0 && cluster < mCpuClusters.length) {
- return getAveragePower(mCpuClusters[cluster].powerKey, step);
+ return getAveragePower(mCpuClusters[cluster].clusterPowerKey);
+ }
+ return 0;
+ }
+
+ public double getAveragePowerForCpuCore(int cluster, int step) {
+ if (cluster >= 0 && cluster < mCpuClusters.length) {
+ return getAveragePower(mCpuClusters[cluster].corePowerKey, step);
}
return 0;
}
@@ -379,14 +409,10 @@ public class PowerProfile {
* @return the number of memory bandwidth buckets.
*/
public int getNumElements(String key) {
- if (sPowerMap.containsKey(key)) {
- Object data = sPowerMap.get(key);
- if (data instanceof Double[]) {
- final Double[] values = (Double[]) data;
- return values.length;
- } else {
- return 1;
- }
+ if (sPowerItemMap.containsKey(key)) {
+ return 1;
+ } else if (sPowerArrayMap.containsKey(key)) {
+ return sPowerArrayMap.get(key).length;
}
return 0;
}
@@ -399,13 +425,10 @@ public class PowerProfile {
* @return the average current in milliAmps.
*/
public double getAveragePowerOrDefault(String type, double defaultValue) {
- if (sPowerMap.containsKey(type)) {
- Object data = sPowerMap.get(type);
- if (data instanceof Double[]) {
- return ((Double[])data)[0];
- } else {
- return (Double) sPowerMap.get(type);
- }
+ if (sPowerItemMap.containsKey(type)) {
+ return sPowerItemMap.get(type);
+ } else if (sPowerArrayMap.containsKey(type)) {
+ return sPowerArrayMap.get(type)[0];
} else {
return defaultValue;
}
@@ -429,19 +452,16 @@ public class PowerProfile {
* @return the average current in milliAmps.
*/
public double getAveragePower(String type, int level) {
- if (sPowerMap.containsKey(type)) {
- Object data = sPowerMap.get(type);
- if (data instanceof Double[]) {
- final Double[] values = (Double[]) data;
- if (values.length > level && level >= 0) {
- return values[level];
- } else if (level < 0 || values.length == 0) {
- return 0;
- } else {
- return values[values.length - 1];
- }
+ if (sPowerItemMap.containsKey(type)) {
+ return sPowerItemMap.get(type);
+ } else if (sPowerArrayMap.containsKey(type)) {
+ final Double[] values = sPowerArrayMap.get(type);
+ if (values.length > level && level >= 0) {
+ return values[level];
+ } else if (level < 0 || values.length == 0) {
+ return 0;
} else {
- return (Double) data;
+ return values[values.length - 1];
}
} else {
return 0;
diff --git a/core/java/com/android/internal/os/WakelockPowerCalculator.java b/core/java/com/android/internal/os/WakelockPowerCalculator.java
index c7897b2bbc3b..486b5842400c 100644
--- a/core/java/com/android/internal/os/WakelockPowerCalculator.java
+++ b/core/java/com/android/internal/os/WakelockPowerCalculator.java
@@ -26,7 +26,7 @@ public class WakelockPowerCalculator extends PowerCalculator {
private long mTotalAppWakelockTimeMs = 0;
public WakelockPowerCalculator(PowerProfile profile) {
- mPowerWakelock = profile.getAveragePower(PowerProfile.POWER_CPU_AWAKE);
+ mPowerWakelock = profile.getAveragePower(PowerProfile.POWER_CPU_IDLE);
}
@Override
diff --git a/core/java/com/android/internal/statusbar/IStatusBar.aidl b/core/java/com/android/internal/statusbar/IStatusBar.aidl
index 5ec90941aa88..85655a5dfc6b 100644
--- a/core/java/com/android/internal/statusbar/IStatusBar.aidl
+++ b/core/java/com/android/internal/statusbar/IStatusBar.aidl
@@ -55,7 +55,7 @@ oneway interface IStatusBar
boolean showImeSwitcher);
void setWindowState(int window, int state);
- void showRecentApps(boolean triggeredFromAltTab, boolean fromHome);
+ void showRecentApps(boolean triggeredFromAltTab);
void hideRecentApps(boolean triggeredFromAltTab, boolean triggeredFromHomeKey);
void toggleRecentApps();
void toggleSplitScreen();
diff --git a/core/java/com/android/internal/util/ArrayUtils.java b/core/java/com/android/internal/util/ArrayUtils.java
index 7b023f412cbc..621619c5134d 100644
--- a/core/java/com/android/internal/util/ArrayUtils.java
+++ b/core/java/com/android/internal/util/ArrayUtils.java
@@ -619,6 +619,10 @@ public class ArrayUtils {
return size - leftIdx;
}
+ public static @NonNull int[] defeatNullable(@Nullable int[] val) {
+ return (val != null) ? val : EmptyArray.INT;
+ }
+
public static @NonNull String[] defeatNullable(@Nullable String[] val) {
return (val != null) ? val : EmptyArray.STRING;
}
diff --git a/core/java/com/android/internal/util/ConcurrentUtils.java b/core/java/com/android/internal/util/ConcurrentUtils.java
index e35f9f45acfe..e08eb587ab97 100644
--- a/core/java/com/android/internal/util/ConcurrentUtils.java
+++ b/core/java/com/android/internal/util/ConcurrentUtils.java
@@ -18,11 +18,13 @@ package com.android.internal.util;
import android.os.Process;
+import java.util.concurrent.CountDownLatch;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
import java.util.concurrent.ThreadFactory;
+import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicInteger;
/**
@@ -86,4 +88,27 @@ public class ConcurrentUtils {
}
}
+ /**
+ * Waits for {@link CountDownLatch#countDown()} to be called on the {@param countDownLatch}.
+ * <p>If {@link CountDownLatch#countDown()} doesn't occur within {@param timeoutMs}, this
+ * method will throw {@code IllegalStateException}
+ * <p>If {@code InterruptedException} occurs, this method will interrupt the current thread
+ * and throw {@code IllegalStateException}
+ *
+ * @param countDownLatch the CountDownLatch which {@link CountDownLatch#countDown()} is
+ * being waited on.
+ * @param timeoutMs the maximum time waited for {@link CountDownLatch#countDown()}
+ * @param description a short description of the operation
+ */
+ public static void waitForCountDownNoInterrupt(CountDownLatch countDownLatch, long timeoutMs,
+ String description) {
+ try {
+ if (!countDownLatch.await(timeoutMs, TimeUnit.MILLISECONDS)) {
+ throw new IllegalStateException(description + " timed out.");
+ }
+ } catch (InterruptedException e) {
+ Thread.currentThread().interrupt();
+ throw new IllegalStateException(description + " interrupted.");
+ }
+ }
}
diff --git a/core/java/com/android/internal/util/DumpUtils.java b/core/java/com/android/internal/util/DumpUtils.java
index 66b777e8e8e6..2b5103377ecb 100644
--- a/core/java/com/android/internal/util/DumpUtils.java
+++ b/core/java/com/android/internal/util/DumpUtils.java
@@ -102,6 +102,7 @@ public final class DumpUtils {
case android.os.Process.ROOT_UID:
case android.os.Process.SYSTEM_UID:
case android.os.Process.SHELL_UID:
+ case android.os.Process.INCIDENTD_UID:
return true;
}
diff --git a/core/java/com/android/internal/util/ScreenshotHelper.java b/core/java/com/android/internal/util/ScreenshotHelper.java
index f7ea7875c8df..7fd94c6859fb 100644
--- a/core/java/com/android/internal/util/ScreenshotHelper.java
+++ b/core/java/com/android/internal/util/ScreenshotHelper.java
@@ -1,5 +1,6 @@
package com.android.internal.util;
+import android.annotation.NonNull;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
@@ -32,8 +33,18 @@ public class ScreenshotHelper {
mContext = context;
}
+ /**
+ * Request a screenshot be taken.
+ *
+ * @param screenshotType The type of screenshot, for example either
+ * {@link android.view.WindowManager.TAKE_SCREENSHOT_FULLSCREEN}
+ * or {@link android.view.WindowManager.TAKE_SCREENSHOT_SELECTED_REGION}
+ * @param hasStatus {@code true} if the status bar is currently showing. {@code false} if not.
+ * @param hasNav {@code true} if the navigation bar is currently showing. {@code false} if not.
+ * @param handler A handler used in case the screenshot times out
+ */
public void takeScreenshot(final int screenshotType, final boolean hasStatus,
- final boolean hasNav, Handler handler) {
+ final boolean hasNav, @NonNull Handler handler) {
synchronized (mScreenshotLock) {
if (mScreenshotConnection != null) {
return;
diff --git a/core/jni/android/opengl/util.cpp b/core/jni/android/opengl/util.cpp
index f3aeb32f3f86..888db32fdfac 100644
--- a/core/jni/android/opengl/util.cpp
+++ b/core/jni/android/opengl/util.cpp
@@ -622,7 +622,7 @@ void util_multiplyMV(JNIEnv *env, jclass clazz,
// ---------------------------------------------------------------------------
-static int checkFormat(SkColorType colorType, int format, int type)
+static int checkInternalFormat(SkColorType colorType, int format, int type)
{
switch(colorType) {
case kN32_SkColorType:
@@ -651,6 +651,20 @@ static int checkFormat(SkColorType colorType, int format, int type)
return -1;
}
+// The internal format is no longer the same as pixel format, per Table 2 in
+// https://www.khronos.org/registry/OpenGL-Refpages/es3.1/html/glTexImage2D.xhtml
+static int getPixelFormatFromInternalFormat(uint32_t internalFormat) {
+ switch (internalFormat) {
+ // For sized internal format.
+ case GL_RGBA16F:
+ return GL_RGBA;
+ // Base internal formats and pixel formats are still the same, see Table 1 in
+ // https://www.khronos.org/registry/OpenGL-Refpages/es3.1/html/glTexImage2D.xhtml
+ default:
+ return internalFormat;
+ }
+}
+
static int getInternalFormat(SkColorType colorType)
{
switch(colorType) {
@@ -716,7 +730,7 @@ static jint util_texImage2D(JNIEnv *env, jclass clazz,
if (type < 0) {
type = getType(colorType);
}
- int err = checkFormat(colorType, internalformat, type);
+ int err = checkInternalFormat(colorType, internalformat, type);
if (err)
return err;
const int w = bitmap.width();
@@ -725,7 +739,8 @@ static jint util_texImage2D(JNIEnv *env, jclass clazz,
if (internalformat == GL_PALETTE8_RGBA8_OES) {
err = -1;
} else {
- glTexImage2D(target, level, internalformat, w, h, border, internalformat, type, p);
+ glTexImage2D(target, level, internalformat, w, h, border,
+ getPixelFormatFromInternalFormat(internalformat), type, p);
}
return err;
}
@@ -737,12 +752,13 @@ static jint util_texSubImage2D(JNIEnv *env, jclass clazz,
SkBitmap bitmap;
GraphicsJNI::getSkBitmap(env, jbitmap, &bitmap);
SkColorType colorType = bitmap.colorType();
+ int internalFormat = getInternalFormat(colorType);
if (format < 0) {
- format = getInternalFormat(colorType);
+ format = getPixelFormatFromInternalFormat(internalFormat);
if (format == GL_PALETTE8_RGBA8_OES)
return -1; // glCompressedTexSubImage2D() not supported
}
- int err = checkFormat(colorType, format, type);
+ int err = checkInternalFormat(colorType, internalFormat, type);
if (err)
return err;
const int w = bitmap.width();
diff --git a/core/jni/android_media_AudioFormat.h b/core/jni/android_media_AudioFormat.h
index 092aaf62bbc0..51cefb9accb8 100644
--- a/core/jni/android_media_AudioFormat.h
+++ b/core/jni/android_media_AudioFormat.h
@@ -33,6 +33,8 @@
#define ENCODING_AAC_HE_V2 12
#define ENCODING_IEC61937 13
#define ENCODING_DOLBY_TRUEHD 14
+#define ENCODING_AAC_ELD 15
+#define ENCODING_AAC_XHE 16
#define ENCODING_INVALID 0
#define ENCODING_DEFAULT 1
@@ -71,6 +73,10 @@ static inline audio_format_t audioFormatToNative(int audioFormat)
return AUDIO_FORMAT_DOLBY_TRUEHD;
case ENCODING_IEC61937:
return AUDIO_FORMAT_IEC61937;
+ case ENCODING_AAC_ELD:
+ return AUDIO_FORMAT_AAC_ELD;
+ case ENCODING_AAC_XHE:
+ return AUDIO_FORMAT_AAC; // FIXME temporary value, needs addition of xHE-AAC
case ENCODING_DEFAULT:
return AUDIO_FORMAT_DEFAULT;
default:
@@ -114,6 +120,11 @@ static inline int audioFormatFromNative(audio_format_t nativeFormat)
return ENCODING_IEC61937;
case AUDIO_FORMAT_DOLBY_TRUEHD:
return ENCODING_DOLBY_TRUEHD;
+ case AUDIO_FORMAT_AAC_ELD:
+ return ENCODING_AAC_ELD;
+ // FIXME needs addition of AUDIO_FORMAT_AAC_XHE
+ //case AUDIO_FORMAT_AAC_XHE:
+ // return ENCODING_AAC_XHE;
case AUDIO_FORMAT_DEFAULT:
return ENCODING_DEFAULT;
default:
@@ -121,6 +132,25 @@ static inline int audioFormatFromNative(audio_format_t nativeFormat)
}
}
+// This function converts Java channel masks to a native channel mask.
+// validity should be checked with audio_is_output_channel().
+static inline audio_channel_mask_t nativeChannelMaskFromJavaChannelMasks(
+ jint channelPositionMask, jint channelIndexMask)
+{
+ // 0 is the java android.media.AudioFormat.CHANNEL_INVALID value
+ if (channelIndexMask != 0) { // channel index mask takes priority
+ // To convert to a native channel mask, the Java channel index mask
+ // requires adding the index representation.
+ return audio_channel_mask_from_representation_and_bits(
+ AUDIO_CHANNEL_REPRESENTATION_INDEX,
+ channelIndexMask);
+ }
+ // To convert to a native channel mask, the Java channel position mask
+ // requires a shift by 2 to skip the two deprecated channel
+ // configurations "default" and "mono".
+ return (audio_channel_mask_t)((uint32_t)channelPositionMask >> 2);
+}
+
static inline audio_channel_mask_t outChannelMaskToNative(int channelMask)
{
switch (channelMask) {
diff --git a/core/jni/android_media_AudioSystem.cpp b/core/jni/android_media_AudioSystem.cpp
index 7ec68edddf52..2be947158fc5 100644
--- a/core/jni/android_media_AudioSystem.cpp
+++ b/core/jni/android_media_AudioSystem.cpp
@@ -1770,6 +1770,24 @@ android_media_AudioSystem_getStreamVolumeDB(JNIEnv *env, jobject thiz,
(audio_devices_t)device);
}
+static jboolean
+android_media_AudioSystem_isOffloadSupported(JNIEnv *env, jobject thiz,
+ jint encoding, jint sampleRate, jint channelMask, jint channelIndexMask)
+{
+ audio_offload_info_t format = AUDIO_INFO_INITIALIZER;
+ format.format = (audio_format_t) audioFormatToNative(encoding);
+ format.sample_rate = (uint32_t) sampleRate;
+ format.channel_mask = nativeChannelMaskFromJavaChannelMasks(channelMask, channelIndexMask);
+ format.stream_type = AUDIO_STREAM_MUSIC;
+ format.has_video = false;
+ format.is_streaming = false;
+ // offload duration unknown at this point:
+ // client side code cannot access "audio.offload.min.duration.secs" property to make a query
+ // agnostic of duration, so using acceptable estimate of 2mn
+ format.duration_us = 120 * 1000000;
+ return AudioSystem::isOffloadSupported(format);
+}
+
// ----------------------------------------------------------------------------
static const JNINativeMethod gMethods[] = {
@@ -1823,6 +1841,7 @@ static const JNINativeMethod gMethods[] = {
(void *)android_media_AudioSystem_registerRecordingCallback},
{"systemReady", "()I", (void *)android_media_AudioSystem_systemReady},
{"getStreamVolumeDB", "(III)F", (void *)android_media_AudioSystem_getStreamVolumeDB},
+ {"native_is_offload_supported", "(IIII)Z", (void *)android_media_AudioSystem_isOffloadSupported},
};
diff --git a/core/jni/android_media_AudioTrack.cpp b/core/jni/android_media_AudioTrack.cpp
index 556ac27dfe9e..11011b1d7c16 100644
--- a/core/jni/android_media_AudioTrack.cpp
+++ b/core/jni/android_media_AudioTrack.cpp
@@ -73,6 +73,7 @@ struct audiotrack_callback_cookie {
jobject audioTrack_ref;
bool busy;
Condition cond;
+ bool isOffload;
};
// keep these values in sync with AudioTrack.java
@@ -90,6 +91,7 @@ class AudioTrackJniStorage {
AudioTrackJniStorage() {
mCallbackData.audioTrack_class = 0;
mCallbackData.audioTrack_ref = 0;
+ mCallbackData.isOffload = false;
}
~AudioTrackJniStorage() {
@@ -132,27 +134,34 @@ static void audioCallback(int event, void* user, void *info) {
}
switch (event) {
- case AudioTrack::EVENT_MARKER: {
- JNIEnv *env = AndroidRuntime::getJNIEnv();
- if (user != NULL && env != NULL) {
- env->CallStaticVoidMethod(
- callbackInfo->audioTrack_class,
- javaAudioTrackFields.postNativeEventInJava,
- callbackInfo->audioTrack_ref, event, 0,0, NULL);
- if (env->ExceptionCheck()) {
- env->ExceptionDescribe();
- env->ExceptionClear();
+ // Offload only events
+ case AudioTrack::EVENT_STREAM_END:
+ case AudioTrack::EVENT_MORE_DATA:
+ // a.k.a. tear down
+ case AudioTrack::EVENT_NEW_IAUDIOTRACK:
+ if (callbackInfo->isOffload) {
+ JNIEnv *env = AndroidRuntime::getJNIEnv();
+ if (user != NULL && env != NULL) {
+ env->CallStaticVoidMethod(
+ callbackInfo->audioTrack_class,
+ javaAudioTrackFields.postNativeEventInJava,
+ callbackInfo->audioTrack_ref, event, 0,0, NULL);
+ if (env->ExceptionCheck()) {
+ env->ExceptionDescribe();
+ env->ExceptionClear();
+ }
}
- }
} break;
+ // PCM and offload events
+ case AudioTrack::EVENT_MARKER:
case AudioTrack::EVENT_NEW_POS: {
JNIEnv *env = AndroidRuntime::getJNIEnv();
if (user != NULL && env != NULL) {
env->CallStaticVoidMethod(
- callbackInfo->audioTrack_class,
- javaAudioTrackFields.postNativeEventInJava,
- callbackInfo->audioTrack_ref, event, 0,0, NULL);
+ callbackInfo->audioTrack_class,
+ javaAudioTrackFields.postNativeEventInJava,
+ callbackInfo->audioTrack_ref, event, 0,0, NULL);
if (env->ExceptionCheck()) {
env->ExceptionDescribe();
env->ExceptionClear();
@@ -198,30 +207,12 @@ sp<AudioTrack> android_media_AudioTrack_getAudioTrack(JNIEnv* env, jobject audio
return getAudioTrack(env, audioTrackObj);
}
-// This function converts Java channel masks to a native channel mask.
-// validity should be checked with audio_is_output_channel().
-static inline audio_channel_mask_t nativeChannelMaskFromJavaChannelMasks(
- jint channelPositionMask, jint channelIndexMask)
-{
- if (channelIndexMask != 0) { // channel index mask takes priority
- // To convert to a native channel mask, the Java channel index mask
- // requires adding the index representation.
- return audio_channel_mask_from_representation_and_bits(
- AUDIO_CHANNEL_REPRESENTATION_INDEX,
- channelIndexMask);
- }
- // To convert to a native channel mask, the Java channel position mask
- // requires a shift by 2 to skip the two deprecated channel
- // configurations "default" and "mono".
- return (audio_channel_mask_t)(channelPositionMask >> 2);
-}
-
// ----------------------------------------------------------------------------
static jint
android_media_AudioTrack_setup(JNIEnv *env, jobject thiz, jobject weak_this, jobject jaa,
jintArray jSampleRate, jint channelPositionMask, jint channelIndexMask,
jint audioFormat, jint buffSizeInBytes, jint memoryMode, jintArray jSession,
- jlong nativeAudioTrack) {
+ jlong nativeAudioTrack, jboolean offload) {
ALOGV("sampleRates=%p, channel mask=%x, index mask=%x, audioFormat(Java)=%d, buffSize=%d"
"nativeAudioTrack=0x%" PRIX64,
@@ -322,8 +313,19 @@ android_media_AudioTrack_setup(JNIEnv *env, jobject thiz, jobject weak_this, job
lpJniStorage->mCallbackData.audioTrack_class = (jclass)env->NewGlobalRef(clazz);
// we use a weak reference so the AudioTrack object can be garbage collected.
lpJniStorage->mCallbackData.audioTrack_ref = env->NewGlobalRef(weak_this);
+ lpJniStorage->mCallbackData.isOffload = offload;
lpJniStorage->mCallbackData.busy = false;
+ audio_offload_info_t offloadInfo;
+ if (offload) {
+ offloadInfo = AUDIO_INFO_INITIALIZER;
+ offloadInfo.format = format;
+ offloadInfo.sample_rate = sampleRateInHertz;
+ offloadInfo.channel_mask = nativeChannelMask;
+ offloadInfo.has_video = false;
+ offloadInfo.stream_type = AUDIO_STREAM_MUSIC; //required for offload
+ }
+
// initialize the native AudioTrack object
status_t status = NO_ERROR;
switch (memoryMode) {
@@ -342,7 +344,7 @@ android_media_AudioTrack_setup(JNIEnv *env, jobject thiz, jobject weak_this, job
true,// thread can call Java
sessionId,// audio session ID
AudioTrack::TRANSFER_SYNC,
- NULL, // default offloadInfo
+ offload ? &offloadInfo : NULL,
-1, -1, // default uid, pid values
paa);
break;
@@ -1234,7 +1236,7 @@ static const JNINativeMethod gMethods[] = {
{"native_stop", "()V", (void *)android_media_AudioTrack_stop},
{"native_pause", "()V", (void *)android_media_AudioTrack_pause},
{"native_flush", "()V", (void *)android_media_AudioTrack_flush},
- {"native_setup", "(Ljava/lang/Object;Ljava/lang/Object;[IIIIII[IJ)I",
+ {"native_setup", "(Ljava/lang/Object;Ljava/lang/Object;[IIIIII[IJZ)I",
(void *)android_media_AudioTrack_setup},
{"native_finalize", "()V", (void *)android_media_AudioTrack_finalize},
{"native_release", "()V", (void *)android_media_AudioTrack_release},
diff --git a/core/jni/android_os_HwParcel.cpp b/core/jni/android_os_HwParcel.cpp
index 9494fb8e7eef..061349aee96f 100644
--- a/core/jni/android_os_HwParcel.cpp
+++ b/core/jni/android_os_HwParcel.cpp
@@ -391,6 +391,10 @@ static void JHwParcel_native_verifySuccess(JNIEnv *env, jobject thiz) {
Status status;
status_t err = ::android::hardware::readFromParcel(&status, *parcel);
signalExceptionForError(env, err);
+
+ if (!status.isOk()) {
+ signalExceptionForError(env, UNKNOWN_ERROR, true /* canThrowRemoteException */);
+ }
}
static void JHwParcel_native_release(
diff --git a/core/jni/com_android_internal_net_NetworkStatsFactory.cpp b/core/jni/com_android_internal_net_NetworkStatsFactory.cpp
index 0cb69359901d..d254de65f765 100644
--- a/core/jni/com_android_internal_net_NetworkStatsFactory.cpp
+++ b/core/jni/com_android_internal_net_NetworkStatsFactory.cpp
@@ -45,6 +45,7 @@ static struct {
jfieldID tag;
jfieldID metered;
jfieldID roaming;
+ jfieldID defaultNetwork;
jfieldID rxBytes;
jfieldID rxPackets;
jfieldID txBytes;
@@ -246,6 +247,9 @@ static int readNetworkStatsDetail(JNIEnv* env, jclass clazz, jobject stats,
ScopedIntArrayRW roaming(env, get_int_array(env, stats,
gNetworkStatsClassInfo.roaming, size, grow));
if (roaming.get() == NULL) return -1;
+ ScopedIntArrayRW defaultNetwork(env, get_int_array(env, stats,
+ gNetworkStatsClassInfo.defaultNetwork, size, grow));
+ if (defaultNetwork.get() == NULL) return -1;
ScopedLongArrayRW rxBytes(env, get_long_array(env, stats,
gNetworkStatsClassInfo.rxBytes, size, grow));
if (rxBytes.get() == NULL) return -1;
@@ -269,7 +273,7 @@ static int readNetworkStatsDetail(JNIEnv* env, jclass clazz, jobject stats,
uid[i] = lines[i].uid;
set[i] = lines[i].set;
tag[i] = lines[i].tag;
- // Metered and Roaming are populated in Java-land by inspecting the iface properties.
+ // Metered, roaming and defaultNetwork are populated in Java-land.
rxBytes[i] = lines[i].rxBytes;
rxPackets[i] = lines[i].rxPackets;
txBytes[i] = lines[i].txBytes;
@@ -285,6 +289,8 @@ static int readNetworkStatsDetail(JNIEnv* env, jclass clazz, jobject stats,
env->SetObjectField(stats, gNetworkStatsClassInfo.tag, tag.getJavaArray());
env->SetObjectField(stats, gNetworkStatsClassInfo.metered, metered.getJavaArray());
env->SetObjectField(stats, gNetworkStatsClassInfo.roaming, roaming.getJavaArray());
+ env->SetObjectField(stats, gNetworkStatsClassInfo.defaultNetwork,
+ defaultNetwork.getJavaArray());
env->SetObjectField(stats, gNetworkStatsClassInfo.rxBytes, rxBytes.getJavaArray());
env->SetObjectField(stats, gNetworkStatsClassInfo.rxPackets, rxPackets.getJavaArray());
env->SetObjectField(stats, gNetworkStatsClassInfo.txBytes, txBytes.getJavaArray());
@@ -318,6 +324,7 @@ int register_com_android_internal_net_NetworkStatsFactory(JNIEnv* env) {
gNetworkStatsClassInfo.tag = GetFieldIDOrDie(env, clazz, "tag", "[I");
gNetworkStatsClassInfo.metered = GetFieldIDOrDie(env, clazz, "metered", "[I");
gNetworkStatsClassInfo.roaming = GetFieldIDOrDie(env, clazz, "roaming", "[I");
+ gNetworkStatsClassInfo.defaultNetwork = GetFieldIDOrDie(env, clazz, "defaultNetwork", "[I");
gNetworkStatsClassInfo.rxBytes = GetFieldIDOrDie(env, clazz, "rxBytes", "[J");
gNetworkStatsClassInfo.rxPackets = GetFieldIDOrDie(env, clazz, "rxPackets", "[J");
gNetworkStatsClassInfo.txBytes = GetFieldIDOrDie(env, clazz, "txBytes", "[J");
diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml
index 547e83c144a4..e4e46f6d0a8f 100644
--- a/core/res/AndroidManifest.xml
+++ b/core/res/AndroidManifest.xml
@@ -1747,6 +1747,12 @@
<permission android:name="android.permission.SEND_EMBMS_INTENTS"
android:protectionLevel="signature|privileged" />
+
+ <!-- Allows internal management of the sensor framework
+ @hide -->
+ <permission android:name="android.permission.MANAGE_SENSORS"
+ android:protectionLevel="signature" />
+
<!-- Must be required by an ImsService to ensure that only the
system can bind to it.
<p>Protection level: signature|privileged
@@ -3692,6 +3698,10 @@
<permission android:name="android.permission.READ_RUNTIME_PROFILES"
android:protectionLevel="signature|privileged" />
+ <!-- @hide Allows audio policy management. -->
+ <permission android:name="android.permission.MANAGE_AUDIO_POLICY"
+ android:protectionLevel="signature" />
+
<!-- @SystemApi Allows an application to turn on / off quiet mode.
@hide <p>Not for use by third-party applications. -->
<permission android:name="android.permission.MODIFY_QUIET_MODE"
diff --git a/core/res/res/values/attrs.xml b/core/res/res/values/attrs.xml
index fd33dc9a32dc..4eaf93d822b2 100644
--- a/core/res/res/values/attrs.xml
+++ b/core/res/res/values/attrs.xml
@@ -4876,6 +4876,8 @@
<!-- Justification by stretching word spacing. -->
<enum name="inter_word" value = "1" />
</attr>
+ <!-- Whether or not this view is a heading for accessibility purposes. -->
+ <attr name="accessibilityHeading" format="boolean"/>
</declare-styleable>
<declare-styleable name="TextViewAppearance">
<!-- Base text color, typeface, size, and style. -->
diff --git a/core/res/res/values/config.xml b/core/res/res/values/config.xml
index 3b02a967a4b2..64f291cc92d3 100644
--- a/core/res/res/values/config.xml
+++ b/core/res/res/values/config.xml
@@ -430,7 +430,7 @@
<integer translatable="false" name="config_mobile_hotspot_provision_check_period">24</integer>
<!-- Activity name to enable wifi tethering after provisioning app succeeds -->
- <string translatable="false" name="config_wifi_tether_enable">com.android.settings/.TetherService</string>
+ <string translatable="false" name="config_wifi_tether_enable">com.android.settings/.wifi.tether.TetherService</string>
<!-- Controls the WiFi wakeup feature.
0 = Not available.
@@ -640,6 +640,12 @@
<!-- Wifi driver supports batched scan -->
<bool translatable="false" name="config_wifi_batched_scan_supported">false</bool>
+ <!-- Wifi driver supports Automatic channel selection (ACS) for softap -->
+ <bool translatable="false" name="config_wifi_softap_acs_supported">false</bool>
+
+ <!-- Wifi driver supports IEEE80211AC for softap -->
+ <bool translatable="false" name="config_wifi_softap_ieee80211ac_supported">false</bool>
+
<!-- Idle Receive current for wifi radio. 0 by default-->
<integer translatable="false" name="config_wifi_idle_receive_cur_ma">0</integer>
@@ -2780,8 +2786,22 @@
<!-- The bounding path of the cutout region of the main built-in display.
Must either be empty if there is no cutout region, or a string that is parsable by
{@link android.util.PathParser}.
+
The path is assumed to be specified in display coordinates with pixel units and in
- the display's native orientation. -->
+ the display's native orientation, with the origin of the coordinate system at the
+ center top of the display.
+
+ To facilitate writing device-independent emulation overlays, the marker `@dp` can be
+ appended after the path string to interpret coordinates in dp instead of px units.
+ Note that a physical cutout should be configured in pixels for the best results.
+
+ Example for a 10px x 10px square top-center cutout:
+ <string ...>M -5,0 L -5,10 L 5,10 L 5,0 Z</string>
+ Example for a 10dp x 10dp square top-center cutout:
+ <string ...>M -5,0 L -5,10 L 5,10 L 5,0 Z @dp</string>
+
+ @see https://www.w3.org/TR/SVG/paths.html#PathData
+ -->
<string translatable="false" name="config_mainBuiltInDisplayCutout"></string>
<!-- Whether the display cutout region of the main built-in display should be forced to
@@ -3252,4 +3272,6 @@
<!-- Package name that should be granted Notification Assistant access -->
<string name="config_defaultAssistantAccessPackage" translatable="false">android.ext.services</string>
+
+ <bool name="config_supportBluetoothPersistedState">true</bool>
</resources>
diff --git a/core/res/res/values/ids.xml b/core/res/res/values/ids.xml
index b40117e9e40b..c90a0df5d7b1 100644
--- a/core/res/res/values/ids.xml
+++ b/core/res/res/values/ids.xml
@@ -163,4 +163,9 @@
<!-- Action used to manually trigger an autofill request -->
<item type="id" name="autofill" />
+ <!-- Accessibility action identifier for {@link android.view.accessibility.AccessibilityNodeInfo.AccessibilityAction#ACTION_SHOW_TOOLTIP}. -->
+ <item type="id" name="accessibilityActionShowTooltip" />
+
+ <!-- Accessibility action identifier for {@link android.view.accessibility.AccessibilityNodeInfo.AccessibilityAction#ACTION_HIDE_TOOLTIP}. -->
+ <item type="id" name="accessibilityActionHideTooltip" />
</resources>
diff --git a/core/res/res/values/public.xml b/core/res/res/values/public.xml
index 656add664022..80fc5db5d435 100644
--- a/core/res/res/values/public.xml
+++ b/core/res/res/values/public.xml
@@ -2865,6 +2865,7 @@
<public name="firstBaselineToTopHeight" />
<public name="lastBaselineToBottomHeight" />
<public name="lineHeight" />
+ <public name="accessibilityHeading" />
</public-group>
<public-group type="style" first-id="0x010302e0">
@@ -2873,6 +2874,8 @@
</public-group>
<public-group type="id" first-id="0x01020044">
+ <public name="accessibilityActionShowTooltip" />
+ <public name="accessibilityActionHideTooltip" />
</public-group>
<public-group type="string" first-id="0x0104001b">
diff --git a/core/res/res/values/strings.xml b/core/res/res/values/strings.xml
index b2fa294f77be..2cfe919fb8f5 100644
--- a/core/res/res/values/strings.xml
+++ b/core/res/res/values/strings.xml
@@ -379,6 +379,9 @@
<string name="factory_reset_message">The admin app can\'t be used. Your device will now be
erased.\n\nIf you have questions, contact your organization's admin.</string>
+ <!-- A toast message displayed when printing is attempted but disabled by policy. -->
+ <string name="printing_disabled_by">Printing disabled by <xliff:g id="owner_app">%s</xliff:g>.</string>
+
<!-- Display name for any time a piece of data refers to the owner of the phone. For example, this could be used in place of the phone's phone number. -->
<string name="me">Me</string>
@@ -3754,6 +3757,11 @@
<!-- Notification body when background data usage is limited. -->
<string name="data_usage_restricted_body">Tap to remove restriction.</string>
+ <!-- Notification title when there has been recent excessive data usage. [CHAR LIMIT=32] -->
+ <string name="data_usage_rapid_title">Large data usage</string>
+ <!-- Notification body when there has been recent excessive data usage. [CHAR LIMIT=128] -->
+ <string name="data_usage_rapid_body">Your data usage over the last few days is larger than normal. Tap to view usage and settings.</string>
+
<!-- SSL Certificate dialogs -->
<!-- Title for an SSL Certificate dialog -->
<string name="ssl_certificate">Security certificate</string>
diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml
index 6e33648b6f14..5309115f37bb 100644
--- a/core/res/res/values/symbols.xml
+++ b/core/res/res/values/symbols.xml
@@ -309,6 +309,8 @@
<java-symbol type="bool" name="config_useFixedVolume" />
<java-symbol type="bool" name="config_forceDefaultOrientation" />
<java-symbol type="bool" name="config_wifi_batched_scan_supported" />
+ <java-symbol type="bool" name="config_wifi_softap_acs_supported" />
+ <java-symbol type="bool" name="config_wifi_softap_ieee80211ac_supported" />
<java-symbol type="bool" name="config_enableMultiUserUI"/>
<java-symbol type="bool" name="config_disableUsbPermissionDialogs"/>
<java-symbol type="bool" name="config_hasRecents" />
@@ -878,6 +880,7 @@
<java-symbol type="string" name="preposition_for_time" />
<java-symbol type="string" name="print_service_installed_title" />
<java-symbol type="string" name="print_service_installed_message" />
+ <java-symbol type="string" name="printing_disabled_by" />
<java-symbol type="string" name="progress_erasing" />
<java-symbol type="string" name="mobile_provisioning_apn" />
<java-symbol type="string" name="mobile_provisioning_url" />
@@ -1507,6 +1510,7 @@
<java-symbol type="xml" name="password_kbd_symbols" />
<java-symbol type="xml" name="password_kbd_symbols_shift" />
<java-symbol type="xml" name="power_profile" />
+ <java-symbol type="xml" name="power_profile_test" />
<java-symbol type="xml" name="sms_short_codes" />
<java-symbol type="xml" name="audio_assets" />
<java-symbol type="xml" name="global_keys" />
@@ -1973,6 +1977,8 @@
<java-symbol type="string" name="data_usage_warning_title" />
<java-symbol type="string" name="data_usage_wifi_limit_snoozed_title" />
<java-symbol type="string" name="data_usage_wifi_limit_title" />
+ <java-symbol type="string" name="data_usage_rapid_title" />
+ <java-symbol type="string" name="data_usage_rapid_body" />
<java-symbol type="string" name="default_wallpaper_component" />
<java-symbol type="string" name="device_storage_monitor_notification_channel" />
<java-symbol type="string" name="dlg_ok" />
@@ -3219,4 +3225,6 @@
<java-symbol type="string" name="harmful_app_warning_title" />
<java-symbol type="string" name="config_defaultAssistantAccessPackage" />
+
+ <java-symbol type="bool" name="config_supportBluetoothPersistedState" />
</resources>
diff --git a/core/res/res/xml/power_profile_test.xml b/core/res/res/xml/power_profile_test.xml
new file mode 100644
index 000000000000..cdb71343e5e5
--- /dev/null
+++ b/core/res/res/xml/power_profile_test.xml
@@ -0,0 +1,116 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+**
+** Copyright 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.
+*/
+-->
+<device name="Android">
+ <!-- All values are in mAh except as noted.
+ This file is for PowerProfileTest.java. Changes must be synced between these two. Since
+ power_profile.xml may be overridden by actual device's power_profile.xml at compile time,
+ this test config ensures we have something constant to test against. Values below are
+ sample values, not meant to reflect any real device.
+ -->
+
+ <!-- Nothing -->
+ <item name="none">0</item>
+
+ <!-- This is the battery capacity in mAh -->
+ <item name="battery.capacity">3000</item>
+
+ <!-- Number of cores each CPU cluster contains -->
+ <array name="cpu.clusters.cores">
+ <value>4</value> <!-- Cluster 0 has 4 cores (cpu0, cpu1, cpu2, cpu3) -->
+ <value>4</value> <!-- Cluster 1 has 4 cores (cpu4, cpu5, cpu5, cpu7) -->
+ </array>
+
+ <!-- Power consumption when CPU is suspended -->
+ <item name="cpu.suspend">5</item>
+ <!-- Additional power consumption when CPU is in a kernel idle loop -->
+ <item name="cpu.idle">1.11</item>
+ <!-- Additional power consumption by CPU excluding cluster and core when running -->
+ <item name="cpu.active">2.55</item>
+
+ <!-- Additional power consumption by CPU cluster0 itself when running excluding cores in it -->
+ <item name="cpu.cluster_power.cluster0">2.11</item>
+ <!-- Additional power consumption by CPU cluster1 itself when running excluding cores in it -->
+ <item name="cpu.cluster_power.cluster1">2.22</item>
+
+ <!-- Different CPU speeds as reported in
+ /sys/devices/system/cpu/cpu0/cpufreq/stats/scaling_available_frequencies -->
+ <array name="cpu.core_speeds.cluster0">
+ <value>300000</value> <!-- 300 MHz CPU speed -->
+ <value>1000000</value> <!-- 1000 MHz CPU speed -->
+ <value>2000000</value> <!-- 2000 MHz CPU speed -->
+ </array>
+ <!-- Different CPU speeds as reported in
+ /sys/devices/system/cpu/cpu4/cpufreq/stats/scaling_available_frequencies -->
+ <array name="cpu.core_speeds.cluster1">
+ <value>300000</value> <!-- 300 MHz CPU speed -->
+ <value>1000000</value> <!-- 1000 MHz CPU speed -->
+ <value>2500000</value> <!-- 2500 MHz CPU speed -->
+ <value>3000000</value> <!-- 3000 MHz CPU speed -->
+ </array>
+
+ <!-- Additional power used by a CPU from cluster 0 when running at different
+ speeds. Currently this measurement also includes cluster cost. -->
+ <array name="cpu.core_power.cluster0">
+ <value>10</value> <!-- 300 MHz CPU speed -->
+ <value>20</value> <!-- 1000 MHz CPU speed -->
+ <value>30</value> <!-- 1900 MHz CPU speed -->
+ </array>
+ <!-- Additional power used by a CPU from cluster 1 when running at different
+ speeds. Currently this measurement also includes cluster cost. -->
+ <array name="cpu.core_power.cluster1">
+ <value>25</value> <!-- 300 MHz CPU speed -->
+ <value>35</value> <!-- 1000 MHz CPU speed -->
+ <value>50</value> <!-- 2500 MHz CPU speed -->
+ <value>60</value> <!-- 3000 MHz CPU speed -->
+ </array>
+
+ <!-- Additional power used when screen is turned on at minimum brightness -->
+ <item name="screen.on">100</item>
+ <!-- Additional power used when screen is at maximum brightness, compared to
+ screen at minimum brightness -->
+ <item name="screen.full">800</item>
+
+ <!-- Average power used by the camera flash module when on -->
+ <item name="camera.flashlight">500</item>
+ <!-- Average power use by the camera subsystem for a typical camera
+ application. Intended as a rough estimate for an application running a
+ preview and capturing approximately 10 full-resolution pictures per
+ minute. -->
+ <item name="camera.avg">600</item>
+
+ <!-- Additional power used when audio decoding/encoding via DSP -->
+ <item name="dsp.audio">100</item>
+
+ <!-- Additional power used when GPS is acquiring a signal -->
+ <item name="gps.on">10</item>
+
+ <!-- Additional power used when cellular radio is transmitting/receiving -->
+ <item name="radio.active">60</item>
+ <!-- Additional power used when cellular radio is paging the tower -->
+ <item name="radio.scanning">3</item>
+ <!-- Additional power used when the cellular radio is on. Multi-value entry,
+ one per signal strength (no signal, weak, moderate, strong) -->
+ <array name="radio.on"> <!-- Strength 0 to BINS-1 -->
+ <value>6</value> <!-- none -->
+ <value>5</value> <!-- poor -->
+ <value>4</value> <!-- moderate -->
+ <value>3</value> <!-- good -->
+ <value>3</value> <!-- great -->
+ </array>
+</device>
diff --git a/core/tests/coretests/src/android/graphics/TypefaceSystemFallbackTest.java b/core/tests/coretests/src/android/graphics/TypefaceSystemFallbackTest.java
index 417faf220d39..eaabdc8b815c 100644
--- a/core/tests/coretests/src/android/graphics/TypefaceSystemFallbackTest.java
+++ b/core/tests/coretests/src/android/graphics/TypefaceSystemFallbackTest.java
@@ -505,4 +505,84 @@ public class TypefaceSystemFallbackTest {
assertEquals(GLYPH_3EM_WIDTH, paint.measureText("b"), 0.0f);
assertEquals(GLYPH_1EM_WIDTH, paint.measureText("c"), 0.0f);
}
+
+ @Test
+ public void testBuildSystemFallback_ElegantFallback_customFallback_missingFile() {
+ final String xml = "<?xml version='1.0' encoding='UTF-8'?>"
+ + "<familyset>"
+ + " <family name='sans-serif'>"
+ + " <font weight='400' style='normal'>no_coverage.ttf</font>"
+ + " </family>"
+ + " <family name='serif'>"
+ + " <font weight='400' style='normal'>no_coverage.ttf</font>"
+ + " </family>"
+ + " <family>"
+ + " <font weight='400' style='normal'>a3em.ttf</font>"
+ + " <font weight='400' style='normal' fallbackFor='serif'>NoSuchFont.ttf</font>"
+ + " </family>"
+ + " <family>"
+ + " <font weight='400' style='normal'>b3em.ttf</font>"
+ + " </family>"
+ + "</familyset>";
+ final ArrayMap<String, Typeface> fontMap = new ArrayMap<>();
+ final ArrayMap<String, FontFamily[]> fallbackMap = new ArrayMap<>();
+
+ buildSystemFallback(xml, fontMap, fallbackMap);
+
+ final Paint paint = new Paint();
+
+ Typeface testTypeface = fontMap.get("serif");
+ assertNotNull(testTypeface);
+ paint.setTypeface(testTypeface);
+ assertEquals(GLYPH_3EM_WIDTH, paint.measureText("a"), 0.0f);
+ assertEquals(GLYPH_1EM_WIDTH, paint.measureText("b"), 0.0f);
+ assertEquals(GLYPH_1EM_WIDTH, paint.measureText("c"), 0.0f);
+
+ testTypeface = fontMap.get("sans-serif");
+ assertNotNull(testTypeface);
+ paint.setTypeface(testTypeface);
+ assertEquals(GLYPH_3EM_WIDTH, paint.measureText("a"), 0.0f);
+ assertEquals(GLYPH_1EM_WIDTH, paint.measureText("b"), 0.0f);
+ assertEquals(GLYPH_1EM_WIDTH, paint.measureText("c"), 0.0f);
+ }
+
+ @Test
+ public void testBuildSystemFallback_ElegantFallback_customFallback_missingFile2() {
+ final String xml = "<?xml version='1.0' encoding='UTF-8'?>"
+ + "<familyset>"
+ + " <family name='sans-serif'>"
+ + " <font weight='400' style='normal'>no_coverage.ttf</font>"
+ + " </family>"
+ + " <family name='serif'>"
+ + " <font weight='400' style='normal'>no_coverage.ttf</font>"
+ + " </family>"
+ + " <family>"
+ + " <font weight='400' style='normal' fallbackFor='serif'>NoSuchFont.ttf</font>"
+ + " </family>"
+ + " <family>"
+ + " <font weight='400' style='normal'>a3em.ttf</font>"
+ + " </family>"
+ + "</familyset>";
+ final ArrayMap<String, Typeface> fontMap = new ArrayMap<>();
+ final ArrayMap<String, FontFamily[]> fallbackMap = new ArrayMap<>();
+
+ buildSystemFallback(xml, fontMap, fallbackMap);
+
+ final Paint paint = new Paint();
+
+ Typeface testTypeface = fontMap.get("serif");
+ assertNotNull(testTypeface);
+ paint.setTypeface(testTypeface);
+ assertEquals(GLYPH_3EM_WIDTH, paint.measureText("a"), 0.0f);
+ assertEquals(GLYPH_1EM_WIDTH, paint.measureText("b"), 0.0f);
+ assertEquals(GLYPH_1EM_WIDTH, paint.measureText("c"), 0.0f);
+
+ testTypeface = fontMap.get("sans-serif");
+ assertNotNull(testTypeface);
+ paint.setTypeface(testTypeface);
+ assertEquals(GLYPH_3EM_WIDTH, paint.measureText("a"), 0.0f);
+ assertEquals(GLYPH_1EM_WIDTH, paint.measureText("b"), 0.0f);
+ assertEquals(GLYPH_1EM_WIDTH, paint.measureText("c"), 0.0f);
+ }
+
}
diff --git a/core/tests/coretests/src/android/provider/SettingsBackupTest.java b/core/tests/coretests/src/android/provider/SettingsBackupTest.java
index 8da7cedd7ea1..ec3a6ce18cce 100644
--- a/core/tests/coretests/src/android/provider/SettingsBackupTest.java
+++ b/core/tests/coretests/src/android/provider/SettingsBackupTest.java
@@ -353,6 +353,7 @@ public class SettingsBackupTest {
Settings.Global.SYS_STORAGE_THRESHOLD_MAX_BYTES,
Settings.Global.SYS_STORAGE_THRESHOLD_PERCENTAGE,
Settings.Global.SYS_VDSO,
+ Settings.Global.FPS_DEVISOR,
Settings.Global.TCP_DEFAULT_INIT_RWND,
Settings.Global.TETHER_DUN_APN,
Settings.Global.TETHER_DUN_REQUIRED,
@@ -533,7 +534,9 @@ public class SettingsBackupTest {
Settings.Secure.VOICE_RECOGNITION_SERVICE,
Settings.Secure.INSTANT_APPS_ENABLED,
Settings.Secure.BACKUP_MANAGER_CONSTANTS,
- Settings.Secure.KEYGUARD_SLICE_URI);
+ Settings.Secure.KEYGUARD_SLICE_URI,
+ Settings.Secure.PARENTAL_CONTROL_ENABLED,
+ Settings.Secure.PARENTAL_CONTROL_REDIRECT_URL);
@Test
public void systemSettingsBackedUpOrBlacklisted() {
diff --git a/core/tests/coretests/src/android/provider/SettingsValidatorsTest.java b/core/tests/coretests/src/android/provider/SettingsValidatorsTest.java
new file mode 100644
index 000000000000..4c4aeaf49855
--- /dev/null
+++ b/core/tests/coretests/src/android/provider/SettingsValidatorsTest.java
@@ -0,0 +1,89 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.provider;
+
+import static org.junit.Assert.fail;
+
+import android.platform.test.annotations.Presubmit;
+import android.provider.SettingsValidators.Validator;
+import android.support.test.filters.SmallTest;
+import android.support.test.runner.AndroidJUnit4;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import java.util.Map;
+
+/** Tests that ensure all backed up settings have non-null validators. */
+@Presubmit
+@RunWith(AndroidJUnit4.class)
+@SmallTest
+public class SettingsValidatorsTest {
+
+ @Test
+ public void ensureAllBackedUpSystemSettingsHaveValidators() {
+ String offenders = getOffenders(concat(Settings.System.SETTINGS_TO_BACKUP,
+ Settings.System.LEGACY_RESTORE_SETTINGS), Settings.System.VALIDATORS);
+
+ failIfOffendersPresent(offenders, "Settings.System");
+ }
+
+ @Test
+ public void ensureAllBackedUpGlobalSettingsHaveValidators() {
+ String offenders = getOffenders(concat(Settings.Global.SETTINGS_TO_BACKUP,
+ Settings.Global.LEGACY_RESTORE_SETTINGS), Settings.Global.VALIDATORS);
+
+ failIfOffendersPresent(offenders, "Settings.Global");
+ }
+
+ @Test
+ public void ensureAllBackedUpSecureSettingsHaveValidators() {
+ String offenders = getOffenders(concat(Settings.Secure.SETTINGS_TO_BACKUP,
+ Settings.Secure.LEGACY_RESTORE_SETTINGS), Settings.Secure.VALIDATORS);
+
+ failIfOffendersPresent(offenders, "Settings.Secure");
+ }
+
+ private void failIfOffendersPresent(String offenders, String settingsType) {
+ if (offenders.length() > 0) {
+ fail("All " + settingsType + " settings that are backed up have to have a non-null"
+ + " validator, but those don't: " + offenders);
+ }
+ }
+
+ private String getOffenders(String[] settingsToBackup, Map<String, Validator> validators) {
+ StringBuilder offenders = new StringBuilder();
+ for (String setting : settingsToBackup) {
+ if (validators.get(setting) == null) {
+ offenders.append(setting).append(" ");
+ }
+ }
+ return offenders.toString();
+ }
+
+ private String[] concat(String[] first, String[] second) {
+ if (second == null || second.length == 0) {
+ return first;
+ }
+ final int firstLen = first.length;
+ final int secondLen = second.length;
+ String[] both = new String[firstLen + secondLen];
+ System.arraycopy(first, 0, both, 0, firstLen);
+ System.arraycopy(second, 0, both, firstLen, secondLen);
+ return both;
+ }
+}
diff --git a/core/tests/coretests/src/com/android/internal/os/BatteryStatsCpuTimesTest.java b/core/tests/coretests/src/com/android/internal/os/BatteryStatsCpuTimesTest.java
index b5a7bec75197..32053e30e886 100644
--- a/core/tests/coretests/src/com/android/internal/os/BatteryStatsCpuTimesTest.java
+++ b/core/tests/coretests/src/com/android/internal/os/BatteryStatsCpuTimesTest.java
@@ -62,9 +62,9 @@ import java.util.Arrays;
*
* Build: m FrameworksCoreTests
* Install: adb install -r \
- * ${ANDROID_PRODUCT_OUT}/data/app/FrameworksCoreTests/FrameworksCoreTests.apk
+ * ${ANDROID_PRODUCT_OUT}/data/app/FrameworksCoreTests/FrameworksCoreTests.apk
* Run: adb shell am instrument -e class com.android.internal.os.BatteryStatsCpuTimesTest -w \
- * com.android.frameworks.coretests/android.support.test.runner.AndroidJUnitRunner
+ * com.android.frameworks.coretests/android.support.test.runner.AndroidJUnitRunner
*
* or
*
@@ -73,10 +73,18 @@ import java.util.Arrays;
@SmallTest
@RunWith(AndroidJUnit4.class)
public class BatteryStatsCpuTimesTest {
- @Mock KernelUidCpuTimeReader mKernelUidCpuTimeReader;
- @Mock KernelUidCpuFreqTimeReader mKernelUidCpuFreqTimeReader;
- @Mock BatteryStatsImpl.UserInfoProvider mUserInfoProvider;
- @Mock PowerProfile mPowerProfile;
+ @Mock
+ KernelUidCpuTimeReader mKernelUidCpuTimeReader;
+ @Mock
+ KernelUidCpuFreqTimeReader mKernelUidCpuFreqTimeReader;
+ @Mock
+ KernelUidCpuActiveTimeReader mKernelUidCpuActiveTimeReader;
+ @Mock
+ KernelUidCpuClusterTimeReader mKernelUidCpuClusterTimeReader;
+ @Mock
+ BatteryStatsImpl.UserInfoProvider mUserInfoProvider;
+ @Mock
+ PowerProfile mPowerProfile;
private MockClocks mClocks;
private MockBatteryStatsImpl mBatteryStatsImpl;
@@ -90,6 +98,8 @@ public class BatteryStatsCpuTimesTest {
mBatteryStatsImpl = new MockBatteryStatsImpl(mClocks)
.setKernelUidCpuTimeReader(mKernelUidCpuTimeReader)
.setKernelUidCpuFreqTimeReader(mKernelUidCpuFreqTimeReader)
+ .setKernelUidCpuActiveTimeReader(mKernelUidCpuActiveTimeReader)
+ .setKernelUidCpuClusterTimeReader(mKernelUidCpuClusterTimeReader)
.setUserInfoProvider(mUserInfoProvider);
}
@@ -134,6 +144,10 @@ public class BatteryStatsCpuTimesTest {
verify(mKernelUidCpuFreqTimeReader, times(2)).perClusterTimesAvailable();
verify(mKernelUidCpuFreqTimeReader).readDelta(
any(KernelUidCpuFreqTimeReader.Callback.class));
+ verify(mKernelUidCpuActiveTimeReader).readDelta(
+ any(KernelUidCpuActiveTimeReader.Callback.class));
+ verify(mKernelUidCpuClusterTimeReader).readDelta(
+ any(KernelUidCpuClusterTimeReader.Callback.class));
verifyNoMoreInteractions(mKernelUidCpuFreqTimeReader);
for (int i = 0; i < numClusters; ++i) {
verify(mKernelCpuSpeedReaders[i]).readDelta();
@@ -228,7 +242,7 @@ public class BatteryStatsCpuTimesTest {
updateTimeBasesLocked(true, Display.STATE_ON, 0, 0);
final int testUserId = 11;
when(mUserInfoProvider.exists(testUserId)).thenReturn(true);
- final int[] testUids = getUids(testUserId, new int[] {
+ final int[] testUids = getUids(testUserId, new int[]{
FIRST_APPLICATION_UID + 22,
FIRST_APPLICATION_UID + 27,
FIRST_APPLICATION_UID + 33
@@ -301,7 +315,7 @@ public class BatteryStatsCpuTimesTest {
when(mUserInfoProvider.exists(testUserId)).thenReturn(true);
final int isolatedAppId = FIRST_ISOLATED_UID + 27;
final int isolatedUid = UserHandle.getUid(testUserId, isolatedAppId);
- final int[] testUids = getUids(testUserId, new int[] {
+ final int[] testUids = getUids(testUserId, new int[]{
FIRST_APPLICATION_UID + 22,
isolatedAppId,
FIRST_APPLICATION_UID + 33
@@ -389,7 +403,7 @@ public class BatteryStatsCpuTimesTest {
final int invalidUid = UserHandle.getUid(invalidUserId, FIRST_APPLICATION_UID + 99);
when(mUserInfoProvider.exists(testUserId)).thenReturn(true);
when(mUserInfoProvider.exists(invalidUserId)).thenReturn(false);
- final int[] testUids = getUids(testUserId, new int[] {
+ final int[] testUids = getUids(testUserId, new int[]{
FIRST_APPLICATION_UID + 22,
FIRST_APPLICATION_UID + 27,
FIRST_APPLICATION_UID + 33
@@ -431,7 +445,7 @@ public class BatteryStatsCpuTimesTest {
updateTimeBasesLocked(true, Display.STATE_ON, 0, 0);
final int testUserId = 11;
when(mUserInfoProvider.exists(testUserId)).thenReturn(true);
- final int[] testUids = getUids(testUserId, new int[] {
+ final int[] testUids = getUids(testUserId, new int[]{
FIRST_APPLICATION_UID + 22,
FIRST_APPLICATION_UID + 27,
FIRST_APPLICATION_UID + 33
@@ -514,10 +528,10 @@ public class BatteryStatsCpuTimesTest {
final int testUserId = 11;
when(mUserInfoProvider.exists(testUserId)).thenReturn(true);
- final int[] testUids = getUids(testUserId, new int[] {
- FIRST_APPLICATION_UID + 22,
- FIRST_APPLICATION_UID + 27,
- FIRST_APPLICATION_UID + 33
+ final int[] testUids = getUids(testUserId, new int[]{
+ FIRST_APPLICATION_UID + 22,
+ FIRST_APPLICATION_UID + 27,
+ FIRST_APPLICATION_UID + 33
});
final long[][] uidTimesMs = {
{4, 10, 5, 9, 4},
@@ -589,7 +603,7 @@ public class BatteryStatsCpuTimesTest {
final int testUserId = 11;
when(mUserInfoProvider.exists(testUserId)).thenReturn(true);
- final int[] testUids = getUids(testUserId, new int[] {
+ final int[] testUids = getUids(testUserId, new int[]{
FIRST_APPLICATION_UID + 22,
FIRST_APPLICATION_UID + 27,
FIRST_APPLICATION_UID + 33
@@ -693,7 +707,7 @@ public class BatteryStatsCpuTimesTest {
final int testUserId = 11;
when(mUserInfoProvider.exists(testUserId)).thenReturn(true);
- final int[] testUids = getUids(testUserId, new int[] {
+ final int[] testUids = getUids(testUserId, new int[]{
FIRST_APPLICATION_UID + 22,
FIRST_APPLICATION_UID + 27,
FIRST_APPLICATION_UID + 33
@@ -782,7 +796,7 @@ public class BatteryStatsCpuTimesTest {
}
}
for (int cluster = 0; cluster < clusterFreqs.length; ++cluster) {
- for (int speed = 0 ; speed < clusterFreqs[cluster]; ++speed) {
+ for (int speed = 0; speed < clusterFreqs[cluster]; ++speed) {
assertEquals("There shouldn't be any left-overs: "
+ Arrays.deepToString(expectedWakeLockUidTimesUs),
0, expectedWakeLockUidTimesUs[cluster][speed]);
@@ -797,7 +811,7 @@ public class BatteryStatsCpuTimesTest {
final int testUserId = 11;
when(mUserInfoProvider.exists(testUserId)).thenReturn(true);
- final int[] testUids = getUids(testUserId, new int[] {
+ final int[] testUids = getUids(testUserId, new int[]{
FIRST_APPLICATION_UID + 22,
FIRST_APPLICATION_UID + 27,
FIRST_APPLICATION_UID + 33
@@ -874,7 +888,7 @@ public class BatteryStatsCpuTimesTest {
when(mUserInfoProvider.exists(testUserId)).thenReturn(true);
final int isolatedAppId = FIRST_ISOLATED_UID + 27;
final int isolatedUid = UserHandle.getUid(testUserId, isolatedAppId);
- final int[] testUids = getUids(testUserId, new int[] {
+ final int[] testUids = getUids(testUserId, new int[]{
FIRST_APPLICATION_UID + 22,
isolatedAppId,
FIRST_APPLICATION_UID + 33
@@ -969,7 +983,7 @@ public class BatteryStatsCpuTimesTest {
final int invalidUid = UserHandle.getUid(invalidUserId, FIRST_APPLICATION_UID + 99);
when(mUserInfoProvider.exists(testUserId)).thenReturn(true);
when(mUserInfoProvider.exists(invalidUserId)).thenReturn(false);
- final int[] testUids = getUids(testUserId, new int[] {
+ final int[] testUids = getUids(testUserId, new int[]{
FIRST_APPLICATION_UID + 22,
FIRST_APPLICATION_UID + 27,
FIRST_APPLICATION_UID + 33
@@ -986,7 +1000,7 @@ public class BatteryStatsCpuTimesTest {
callback.onUidCpuFreqTime(testUids[i], uidTimesMs[i]);
}
// And one for the invalid uid
- callback.onUidCpuFreqTime(invalidUid, new long[] {12, 839, 32, 34, 21});
+ callback.onUidCpuFreqTime(invalidUid, new long[]{12, 839, 32, 34, 21});
return null;
}).when(mKernelUidCpuFreqTimeReader).readDelta(
any(KernelUidCpuFreqTimeReader.Callback.class));
@@ -1009,6 +1023,136 @@ public class BatteryStatsCpuTimesTest {
verify(mKernelUidCpuFreqTimeReader).removeUid(invalidUid);
}
+ @Test
+ public void testReadKernelUidCpuActiveTimesLocked() {
+ // PRECONDITIONS
+ updateTimeBasesLocked(true, Display.STATE_ON, 0, 0);
+
+ final int testUserId = 11;
+ when(mUserInfoProvider.exists(testUserId)).thenReturn(true);
+ final int[] testUids = getUids(testUserId, new int[]{
+ FIRST_APPLICATION_UID + 22,
+ FIRST_APPLICATION_UID + 27,
+ FIRST_APPLICATION_UID + 33
+ });
+ final long[] uidTimesMs = {8000, 25000, 3000, 0, 42000};
+ doAnswer(invocation -> {
+ final KernelUidCpuActiveTimeReader.Callback callback =
+ (KernelUidCpuActiveTimeReader.Callback) invocation.getArguments()[0];
+ for (int i = 0; i < testUids.length; ++i) {
+ callback.onUidCpuActiveTime(testUids[i], uidTimesMs[i]);
+ }
+ return null;
+ }).when(mKernelUidCpuActiveTimeReader).readDelta(
+ any(KernelUidCpuActiveTimeReader.Callback.class));
+
+ // RUN
+ mBatteryStatsImpl.readKernelUidCpuActiveTimesLocked();
+
+ // VERIFY
+ for (int i = 0; i < testUids.length; ++i) {
+ final BatteryStats.Uid u = mBatteryStatsImpl.getUidStats().get(testUids[i]);
+ assertNotNull("No entry for uid=" + testUids[i], u);
+ assertEquals("Unexpected cpu active time for uid=" + testUids[i], uidTimesMs[i],
+ u.getCpuActiveTime());
+ }
+
+ // Repeat the test when the screen is off.
+
+ // PRECONDITIONS
+ updateTimeBasesLocked(true, Display.STATE_OFF, 0, 0);
+ final long[] deltasMs = {43000, 3345000, 2143000, 123000, 4554000};
+ doAnswer(invocation -> {
+ final KernelUidCpuActiveTimeReader.Callback callback =
+ (KernelUidCpuActiveTimeReader.Callback) invocation.getArguments()[0];
+ for (int i = 0; i < testUids.length; ++i) {
+ callback.onUidCpuActiveTime(testUids[i], deltasMs[i]);
+ }
+ return null;
+ }).when(mKernelUidCpuActiveTimeReader).readDelta(
+ any(KernelUidCpuActiveTimeReader.Callback.class));
+
+ // RUN
+ mBatteryStatsImpl.readKernelUidCpuActiveTimesLocked();
+
+ // VERIFY
+ for (int i = 0; i < testUids.length; ++i) {
+ final BatteryStats.Uid u = mBatteryStatsImpl.getUidStats().get(testUids[i]);
+ assertNotNull("No entry for uid=" + testUids[i], u);
+ assertEquals("Unexpected cpu active time for uid=" + testUids[i],
+ uidTimesMs[i] + deltasMs[i], u.getCpuActiveTime());
+ }
+ }
+
+ @Test
+ public void testReadKernelUidCpuClusterTimesLocked() {
+ // PRECONDITIONS
+ updateTimeBasesLocked(true, Display.STATE_ON, 0, 0);
+
+ final int testUserId = 11;
+ when(mUserInfoProvider.exists(testUserId)).thenReturn(true);
+ final int[] testUids = getUids(testUserId, new int[]{
+ FIRST_APPLICATION_UID + 22,
+ FIRST_APPLICATION_UID + 27,
+ FIRST_APPLICATION_UID + 33
+ });
+ final long[][] uidTimesMs = {
+ {4000, 10000},
+ {5000, 1000},
+ {8000, 0}
+ };
+ doAnswer(invocation -> {
+ final KernelUidCpuClusterTimeReader.Callback callback =
+ (KernelUidCpuClusterTimeReader.Callback) invocation.getArguments()[0];
+ for (int i = 0; i < testUids.length; ++i) {
+ callback.onUidCpuPolicyTime(testUids[i], uidTimesMs[i]);
+ }
+ return null;
+ }).when(mKernelUidCpuClusterTimeReader).readDelta(
+ any(KernelUidCpuClusterTimeReader.Callback.class));
+
+ // RUN
+ mBatteryStatsImpl.readKernelUidCpuClusterTimesLocked();
+
+ // VERIFY
+ for (int i = 0; i < testUids.length; ++i) {
+ final BatteryStats.Uid u = mBatteryStatsImpl.getUidStats().get(testUids[i]);
+ assertNotNull("No entry for uid=" + testUids[i], u);
+ assertArrayEquals("Unexpected cpu cluster time for uid=" + testUids[i], uidTimesMs[i],
+ u.getCpuClusterTimes());
+ }
+
+ // Repeat the test when the screen is off.
+
+ // PRECONDITIONS
+ updateTimeBasesLocked(true, Display.STATE_OFF, 0, 0);
+ final long[][] deltasMs = {
+ {3000, 12000},
+ {3248327490475L, 0},
+ {43000, 3345000}
+ };
+ doAnswer(invocation -> {
+ final KernelUidCpuClusterTimeReader.Callback callback =
+ (KernelUidCpuClusterTimeReader.Callback) invocation.getArguments()[0];
+ for (int i = 0; i < testUids.length; ++i) {
+ callback.onUidCpuPolicyTime(testUids[i], deltasMs[i]);
+ }
+ return null;
+ }).when(mKernelUidCpuClusterTimeReader).readDelta(
+ any(KernelUidCpuClusterTimeReader.Callback.class));
+
+ // RUN
+ mBatteryStatsImpl.readKernelUidCpuClusterTimesLocked();
+
+ // VERIFY
+ for (int i = 0; i < testUids.length; ++i) {
+ final BatteryStats.Uid u = mBatteryStatsImpl.getUidStats().get(testUids[i]);
+ assertNotNull("No entry for uid=" + testUids[i], u);
+ assertArrayEquals("Unexpected cpu cluster time for uid=" + testUids[i], sum(uidTimesMs[i], deltasMs[i]),
+ u.getCpuClusterTimes());
+ }
+ }
+
private void updateTimeBasesLocked(boolean unplugged, int screenState,
long upTime, long realTime) {
// Set PowerProfile=null before calling updateTimeBasesLocked to avoid execution of
diff --git a/core/tests/coretests/src/com/android/internal/os/BatteryStatsTests.java b/core/tests/coretests/src/com/android/internal/os/BatteryStatsTests.java
index e8f24567599e..702f4b8c0dc5 100644
--- a/core/tests/coretests/src/com/android/internal/os/BatteryStatsTests.java
+++ b/core/tests/coretests/src/com/android/internal/os/BatteryStatsTests.java
@@ -39,8 +39,11 @@ import org.junit.runners.Suite;
KernelMemoryBandwidthStatsTest.class,
KernelSingleUidTimeReaderTest.class,
KernelUidCpuFreqTimeReaderTest.class,
+ KernelUidCpuActiveTimeReaderTest.class,
+ KernelUidCpuClusterTimeReaderTest.class,
KernelWakelockReaderTest.class,
- LongSamplingCounterArrayTest.class
+ LongSamplingCounterArrayTest.class,
+ PowerProfileTest.class
})
public class BatteryStatsTests {
}
diff --git a/core/tests/coretests/src/com/android/internal/os/KernelUidCpuActiveTimeReaderTest.java b/core/tests/coretests/src/com/android/internal/os/KernelUidCpuActiveTimeReaderTest.java
new file mode 100644
index 000000000000..1ac82bd1dc96
--- /dev/null
+++ b/core/tests/coretests/src/com/android/internal/os/KernelUidCpuActiveTimeReaderTest.java
@@ -0,0 +1,240 @@
+/*
+ * 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.os;
+
+import static org.mockito.Mockito.spy;
+import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.verifyNoMoreInteractions;
+import static org.mockito.Mockito.when;
+
+import android.support.test.filters.SmallTest;
+import android.support.test.runner.AndroidJUnit4;
+
+import org.junit.Assert;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.ArgumentCaptor;
+import org.mockito.Mock;
+import org.mockito.Mockito;
+import org.mockito.MockitoAnnotations;
+
+import java.io.BufferedReader;
+import java.util.Arrays;
+import java.util.List;
+import java.util.Random;
+
+/**
+ * Test class for {@link KernelUidCpuActiveTimeReader}.
+ *
+ * To run it:
+ * bit FrameworksCoreTests:com.android.internal.os.KernelUidCpuActiveTimeReaderTest
+ *
+ */
+@SmallTest
+@RunWith(AndroidJUnit4.class)
+public class KernelUidCpuActiveTimeReaderTest {
+ @Mock private BufferedReader mBufferedReader;
+ @Mock private KernelUidCpuActiveTimeReader.Callback mCallback;
+
+ private KernelUidCpuActiveTimeReader mReader;
+
+ @Before
+ public void setUp() {
+ MockitoAnnotations.initMocks(this);
+ mReader = new KernelUidCpuActiveTimeReader();
+ }
+
+ public class Temp {
+
+ public void method() {
+ method1(new long[][]{{1,2,3}, {2,3,4}});
+ method1(new long[][]{{2,2,3}, {2,3,4}});
+ }
+ public int method1(long[][] array) {
+ return array.length * array[0].length;
+ }
+ }
+
+ @Test
+ public void testReadDelta() throws Exception {
+ final int cores = 8;
+ final String info = "active: 8";
+ final int[] uids = {1, 22, 333, 4444, 5555};
+
+ final long[][] times = increaseTime(new long[uids.length][cores]);
+ when(mBufferedReader.readLine()).thenReturn(info, formatTime(uids, times));
+ mReader.readDeltaInternal(mBufferedReader, mCallback);
+ for(int i=0;i<uids.length;i++){
+ verify(mCallback).onUidCpuActiveTime(uids[i], getTotal(times[i]));
+ }
+ verifyNoMoreInteractions(mCallback);
+
+ // Verify that a second call will only return deltas.
+ Mockito.reset(mCallback, mBufferedReader);
+ final long[][] times1 = increaseTime(times);
+ when(mBufferedReader.readLine()).thenReturn(info, formatTime(uids, times1));
+ mReader.readDeltaInternal(mBufferedReader, mCallback);
+ for(int i=0;i<uids.length;i++){
+ verify(mCallback).onUidCpuActiveTime(uids[i], getTotal(subtract(times1[i], times[i])));
+ }
+ verifyNoMoreInteractions(mCallback);
+
+ // Verify that there won't be a callback if the proc file values didn't change.
+ Mockito.reset(mCallback, mBufferedReader);
+ when(mBufferedReader.readLine()).thenReturn(info, formatTime(uids, times1));
+ mReader.readDeltaInternal(mBufferedReader, mCallback);
+ verifyNoMoreInteractions(mCallback);
+
+ // Verify that calling with a null callback doesn't result in any crashes
+ Mockito.reset(mCallback, mBufferedReader);
+ final long[][] times2 = increaseTime(times1);
+ when(mBufferedReader.readLine()).thenReturn(info, formatTime(uids, times2));
+ mReader.readDeltaInternal(mBufferedReader, null);
+
+ // Verify that the readDelta call will only return deltas when
+ // the previous call had null callback.
+ Mockito.reset(mCallback, mBufferedReader);
+ final long[][] times3 = increaseTime(times2);
+ when(mBufferedReader.readLine()).thenReturn(info, formatTime(uids, times3));
+ mReader.readDeltaInternal(mBufferedReader, mCallback);
+ for (int i = 0; i < uids.length; ++i) {
+ verify(mCallback).onUidCpuActiveTime(uids[i], getTotal(subtract(times3[i], times2[i])));
+ }
+ verifyNoMoreInteractions(mCallback);
+ }
+
+ @Test
+ public void testReadDelta_malformedData() throws Exception {
+ final int cores = 8;
+ final String info = "active: 8";
+ final int[] uids = {1, 22, 333, 4444, 5555};
+ final long[][] times = increaseTime(new long[uids.length][cores]);
+ when(mBufferedReader.readLine()).thenReturn(info, formatTime(uids, times));
+ mReader.readDeltaInternal(mBufferedReader, mCallback);
+ for(int i=0;i<uids.length;i++){
+ verify(mCallback).onUidCpuActiveTime(uids[i], getTotal(times[i]));
+ }
+ verifyNoMoreInteractions(mCallback);
+
+ // Verify that there is no callback if subsequent call provides wrong # of entries.
+ Mockito.reset(mCallback, mBufferedReader);
+ final long[][] temp = increaseTime(times);
+ final long[][] times1 = new long[uids.length][];
+ for(int i=0;i<temp.length;i++){
+ times1[i] = Arrays.copyOfRange(temp[i], 0, 6);
+ }
+ when(mBufferedReader.readLine()).thenReturn(info, formatTime(uids, times1));
+ mReader.readDeltaInternal(mBufferedReader, mCallback);
+ verifyNoMoreInteractions(mCallback);
+
+ // Verify that the internal state was not modified if the given core count does not match
+ // the following # of entries.
+ Mockito.reset(mCallback, mBufferedReader);
+ final long[][] times2 = increaseTime(times);
+ when(mBufferedReader.readLine()).thenReturn(info, formatTime(uids, times2));
+ mReader.readDeltaInternal(mBufferedReader, mCallback);
+ for(int i=0;i<uids.length;i++){
+ verify(mCallback).onUidCpuActiveTime(uids[i], getTotal(subtract(times2[i], times[i])));
+ }
+ verifyNoMoreInteractions(mCallback);
+
+ // Verify that there is no callback if any value in the proc file is -ve.
+ Mockito.reset(mCallback, mBufferedReader);
+ final long[][] times3 = increaseTime(times2);
+ times3[uids.length - 1][cores - 1] *= -1;
+ when(mBufferedReader.readLine()).thenReturn(info, formatTime(uids, times3));
+ mReader.readDeltaInternal(mBufferedReader, mCallback);
+ for (int i = 0; i < uids.length - 1; ++i) {
+ verify(mCallback).onUidCpuActiveTime(uids[i], getTotal(subtract(times3[i], times2[i])));
+ }
+ verifyNoMoreInteractions(mCallback);
+
+ // Verify that the internal state was not modified when the proc file had -ve value.
+ Mockito.reset(mCallback, mBufferedReader);
+ for (int i = 0; i < cores; i++) {
+ times3[uids.length - 1][i] = times2[uids.length - 1][i] + uids[uids.length - 1] * 1000;
+ }
+ when(mBufferedReader.readLine()).thenReturn(info, formatTime(uids, times3));
+ mReader.readDeltaInternal(mBufferedReader, mCallback);
+ verify(mCallback).onUidCpuActiveTime(uids[uids.length - 1], getTotal(subtract(times3[uids.length - 1], times2[uids.length - 1])));
+ verifyNoMoreInteractions(mCallback);
+
+ // Verify that there is no callback if the values in the proc file are decreased.
+ Mockito.reset(mCallback, mBufferedReader);
+ final long[][] times4 = increaseTime(times3);
+ times4[uids.length - 1][cores - 1] = times3[uids.length - 1][cores - 1] - 1;
+ when(mBufferedReader.readLine()).thenReturn(info, formatTime(uids, times4));
+ mReader.readDeltaInternal(mBufferedReader, mCallback);
+ for (int i = 0; i < uids.length - 1; ++i) {
+ verify(mCallback).onUidCpuActiveTime(uids[i], getTotal(subtract(times4[i], times3[i])));
+ }
+ verifyNoMoreInteractions(mCallback);
+
+ // Verify that the internal state was not modified when the proc file had decreased values.
+ Mockito.reset(mCallback, mBufferedReader);
+ for (int i = 0; i < cores; i++) {
+ times4[uids.length - 1][i] = times3[uids.length - 1][i] + uids[uids.length - 1] * 1000;
+ }
+ when(mBufferedReader.readLine()).thenReturn(info, formatTime(uids, times4));
+ mReader.readDeltaInternal(mBufferedReader, mCallback);
+ verify(mCallback).onUidCpuActiveTime(uids[uids.length - 1], getTotal(subtract(times4[uids.length - 1], times3[uids.length - 1])));
+ verifyNoMoreInteractions(mCallback);
+ }
+
+ private long[] subtract(long[] a1, long[] a2) {
+ long[] val = new long[a1.length];
+ for (int i = 0; i < val.length; ++i) {
+ val[i] = a1[i] - a2[i];
+ }
+ return val;
+ }
+
+ private String[] formatTime(int[] uids, long[][] times) {
+ String[] lines = new String[uids.length + 1];
+ for (int i=0;i<uids.length;i++){
+ StringBuilder sb = new StringBuilder();
+ sb.append(uids[i]).append(':');
+ for(int j=0;j<times[i].length;j++){
+ sb.append(' ').append(times[i][j]);
+ }
+ lines[i] = sb.toString();
+ }
+ lines[uids.length] = null;
+ return lines;
+ }
+
+ private long[][] increaseTime(long[][] original) {
+ long[][] newTime = new long[original.length][original[0].length];
+ Random rand = new Random();
+ for(int i = 0;i<original.length;i++){
+ for(int j=0;j<original[0].length;j++){
+ newTime[i][j] = original[i][j] + rand.nextInt(1000_000) + 10000;
+ }
+ }
+ return newTime;
+ }
+
+ private long getTotal(long[] times) {
+ long sum = 0;
+ for(int i=0;i<times.length;i++){
+ sum+=times[i] * 10 / (i+1);
+ }
+ return sum;
+ }
+}
diff --git a/core/tests/coretests/src/com/android/internal/os/KernelUidCpuClusterTimeReaderTest.java b/core/tests/coretests/src/com/android/internal/os/KernelUidCpuClusterTimeReaderTest.java
new file mode 100644
index 000000000000..0d1f85277ebb
--- /dev/null
+++ b/core/tests/coretests/src/com/android/internal/os/KernelUidCpuClusterTimeReaderTest.java
@@ -0,0 +1,245 @@
+/*
+ * 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.os;
+
+import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.verifyNoMoreInteractions;
+import static org.mockito.Mockito.when;
+
+import android.support.test.filters.SmallTest;
+import android.support.test.runner.AndroidJUnit4;
+
+import static org.junit.Assert.*;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.ArgumentCaptor;
+import org.mockito.Mock;
+import org.mockito.Mockito;
+import org.mockito.MockitoAnnotations;
+
+import java.io.BufferedReader;
+import java.util.Arrays;
+import java.util.List;
+import java.util.Random;
+
+/**
+ * Test class for {@link KernelUidCpuClusterTimeReader}.
+ *
+ * To run it:
+ * bit FrameworksCoreTests:com.android.internal.os.KernelUidCpuClusterTimeReaderTest
+ *
+ */
+@SmallTest
+@RunWith(AndroidJUnit4.class)
+public class KernelUidCpuClusterTimeReaderTest {
+ @Mock private BufferedReader mBufferedReader;
+ @Mock private KernelUidCpuClusterTimeReader.Callback mCallback;
+
+ private KernelUidCpuClusterTimeReader mReader;
+
+ @Before
+ public void setUp() {
+ MockitoAnnotations.initMocks(this);
+ mReader = new KernelUidCpuClusterTimeReader();
+ }
+
+ @Test
+ public void testReadDelta() throws Exception {
+ final String info = "policy0: 2 policy4: 4";
+ final int cores = 6;
+ final int[] cluster = {2, 4};
+ final int[] uids = {1, 22, 333, 4444, 5555};
+
+ // Verify initial call
+ final long[][] times = increaseTime(new long[uids.length][cores]);
+ when(mBufferedReader.readLine()).thenReturn(info, formatTime(uids, times));
+ mReader.readDeltaInternal(mBufferedReader, mCallback);
+ for (int i=0;i<uids.length;i++){
+ verify(mCallback).onUidCpuPolicyTime(uids[i], getTotal(cluster, times[i]));
+ }
+
+ // Verify that a second call will only return deltas.
+ Mockito.reset(mCallback, mBufferedReader);
+ final long[][] times1 = increaseTime(times);
+ when(mBufferedReader.readLine()).thenReturn(info, formatTime(uids, times1));
+ mReader.readDeltaInternal(mBufferedReader, mCallback);
+ for (int i=0;i<uids.length;i++){
+ verify(mCallback).onUidCpuPolicyTime(uids[i], getTotal(cluster, subtract(times1[i], times[i])));
+ }
+
+ // Verify that there won't be a callback if the proc file values didn't change.
+ Mockito.reset(mCallback, mBufferedReader);
+ when(mBufferedReader.readLine()).thenReturn(info, formatTime(uids, times1));
+ mReader.readDeltaInternal(mBufferedReader, mCallback);
+ verifyNoMoreInteractions(mCallback);
+
+ // Verify that calling with a null callback doesn't result in any crashes
+ Mockito.reset(mCallback, mBufferedReader);
+ final long[][] times2 = increaseTime(times1);
+ when(mBufferedReader.readLine()).thenReturn(info, formatTime(uids, times2));
+ mReader.readDeltaInternal(mBufferedReader, null);
+
+ // Verify that the readDelta call will only return deltas when
+ // the previous call had null callback.
+ Mockito.reset(mCallback, mBufferedReader);
+ final long[][] times3 = increaseTime(times2);
+ when(mBufferedReader.readLine()).thenReturn(info, formatTime(uids, times3));
+ mReader.readDeltaInternal(mBufferedReader, mCallback);
+ for (int i=0;i<uids.length;i++){
+ verify(mCallback).onUidCpuPolicyTime(uids[i], getTotal(cluster, subtract(times3[i], times2[i])));
+ }
+
+ }
+
+ @Test
+ public void testReadDelta_malformedData() throws Exception {
+ final String info = "policy0: 2 policy4: 4";
+ final int cores = 6;
+ final int[] cluster = {2, 4};
+ final int[] uids = {1, 22, 333, 4444, 5555};
+
+ // Verify initial call
+ final long[][] times = increaseTime(new long[uids.length][cores]);
+ when(mBufferedReader.readLine()).thenReturn(info, formatTime(uids, times));
+ mReader.readDeltaInternal(mBufferedReader, mCallback);
+ for (int i=0;i<uids.length;i++){
+ verify(mCallback).onUidCpuPolicyTime(uids[i], getTotal(cluster, times[i]));
+ }
+
+ // Verify that there is no callback if subsequent call provides wrong # of entries.
+ Mockito.reset(mCallback, mBufferedReader);
+ final long[][] temp = increaseTime(times);
+ final long[][] times1 = new long[uids.length][];
+ for(int i=0;i<temp.length;i++){
+ times1[i] = Arrays.copyOfRange(temp[i], 0, 4);
+ }
+ when(mBufferedReader.readLine()).thenReturn(info, formatTime(uids, times1));
+ mReader.readDeltaInternal(mBufferedReader, mCallback);
+ verifyNoMoreInteractions(mCallback);
+
+ // Verify that the internal state was not modified if the given core count does not match
+ // the following # of entries.
+ Mockito.reset(mCallback, mBufferedReader);
+ final long[][] times2 = increaseTime(times);
+ when(mBufferedReader.readLine()).thenReturn(info, formatTime(uids, times2));
+ mReader.readDeltaInternal(mBufferedReader, mCallback);
+ for (int i=0;i<uids.length;i++){
+ verify(mCallback).onUidCpuPolicyTime(uids[i], getTotal(cluster, subtract(times2[i], times[i])));
+ }
+
+ // Verify that there is no callback if any value in the proc file is -ve.
+ Mockito.reset(mCallback, mBufferedReader);
+ final long[][] times3 = increaseTime(times2);
+ times3[uids.length - 1][cores - 1] *= -1;
+ when(mBufferedReader.readLine()).thenReturn(info, formatTime(uids, times3));
+ mReader.readDeltaInternal(mBufferedReader, mCallback);
+ for (int i=0;i<uids.length-1;i++){
+ verify(mCallback).onUidCpuPolicyTime(uids[i], getTotal(cluster, subtract(times3[i], times2[i])));
+ }
+ verifyNoMoreInteractions(mCallback);
+
+ // Verify that the internal state was not modified when the proc file had -ve value.
+ Mockito.reset(mCallback, mBufferedReader);
+ for(int i=0;i<cores;i++){
+ times3[uids.length -1][i] = times2[uids.length -1][i] + uids[uids.length -1]*1000;
+ }
+ when(mBufferedReader.readLine()).thenReturn(info, formatTime(uids, times3));
+ mReader.readDeltaInternal(mBufferedReader, mCallback);
+ verify(mCallback, times(1)).onUidCpuPolicyTime(uids[uids.length-1], getTotal(cluster, subtract(times3[uids.length -1], times2[uids.length -1])));
+
+ // // Verify that there is no callback if the values in the proc file are decreased.
+ Mockito.reset(mCallback, mBufferedReader);
+ final long[][] times4 = increaseTime(times3);
+ times4[uids.length - 1][cores - 1] = times3[uids.length - 1][cores - 1] - 1;
+ when(mBufferedReader.readLine()).thenReturn(info, formatTime(uids, times4));
+ mReader.readDeltaInternal(mBufferedReader, mCallback);
+ for (int i=0;i<uids.length-1;i++){
+ verify(mCallback).onUidCpuPolicyTime(uids[i], getTotal(cluster, subtract(times4[i], times3[i])));
+ }
+ verifyNoMoreInteractions(mCallback);
+
+ // Verify that the internal state was not modified when the proc file had decreased values.
+ Mockito.reset(mCallback, mBufferedReader);
+ for(int i=0;i<cores;i++){
+ times4[uids.length -1][i] = times3[uids.length -1][i] + uids[uids.length -1]*1000;
+ }
+ when(mBufferedReader.readLine()).thenReturn(info, formatTime(uids, times4));
+ mReader.readDeltaInternal(mBufferedReader, mCallback);
+ verify(mCallback, times(1))
+ .onUidCpuPolicyTime(uids[uids.length-1], getTotal(cluster, subtract(times3[uids.length -1], times2[uids.length -1])));
+
+ }
+
+
+ private long[] subtract(long[] a1, long[] a2) {
+ long[] val = new long[a1.length];
+ for (int i = 0; i < val.length; ++i) {
+ val[i] = a1[i] - a2[i];
+ }
+ return val;
+ }
+
+ private String[] formatTime(int[] uids, long[][] times) {
+ String[] lines = new String[uids.length + 1];
+ for (int i=0;i<uids.length;i++){
+ StringBuilder sb = new StringBuilder();
+ sb.append(uids[i]).append(':');
+ for(int j=0;j<times[i].length;j++){
+ sb.append(' ').append(times[i][j]);
+ }
+ lines[i] = sb.toString();
+ }
+ lines[uids.length] = null;
+ return lines;
+ }
+
+ private long[][] increaseTime(long[][] original) {
+ long[][] newTime = new long[original.length][original[0].length];
+ Random rand = new Random();
+ for(int i = 0;i<original.length;i++){
+ for(int j=0;j<original[0].length;j++){
+ newTime[i][j] = original[i][j] + rand.nextInt(1000_000) + 10000;
+ }
+ }
+ return newTime;
+ }
+
+ // Format an array of cluster times according to the algorithm in KernelUidCpuClusterTimeReader
+ private long[] getTotal(int[] cluster, long[] times) {
+ int core = 0;
+ long[] sum = new long[cluster.length];
+ for(int i=0;i<cluster.length;i++){
+ for(int j=0;j<cluster[i];j++){
+ sum[i] += times[core++] * 10 / (j+1);
+ }
+ }
+ return sum;
+ }
+
+ // Compare array1 against flattened 2d array array2 element by element
+ private boolean testEqual(long[] array1, long[][] array2) {
+ int k=0;
+ for(int i=0;i<array2.length;i++){
+ for(int j=0;j<array2[i].length;j++){
+ if (k >= array1.length || array1[k++]!=array2[i][j])return false;
+ }
+ }
+ return k == array1.length;
+ }
+}
diff --git a/core/tests/coretests/src/com/android/internal/os/MockBatteryStatsImpl.java b/core/tests/coretests/src/com/android/internal/os/MockBatteryStatsImpl.java
index 6c5a2aac159b..660c744f050d 100644
--- a/core/tests/coretests/src/com/android/internal/os/MockBatteryStatsImpl.java
+++ b/core/tests/coretests/src/com/android/internal/os/MockBatteryStatsImpl.java
@@ -88,6 +88,16 @@ public class MockBatteryStatsImpl extends BatteryStatsImpl {
return this;
}
+ public MockBatteryStatsImpl setKernelUidCpuActiveTimeReader(KernelUidCpuActiveTimeReader reader) {
+ mKernelUidCpuActiveTimeReader = reader;
+ return this;
+ }
+
+ public MockBatteryStatsImpl setKernelUidCpuClusterTimeReader(KernelUidCpuClusterTimeReader reader) {
+ mKernelUidCpuClusterTimeReader = reader;
+ return this;
+ }
+
public MockBatteryStatsImpl setKernelUidCpuTimeReader(KernelUidCpuTimeReader reader) {
mKernelUidCpuTimeReader = reader;
return this;
diff --git a/core/tests/coretests/src/com/android/internal/os/PowerProfileTest.java b/core/tests/coretests/src/com/android/internal/os/PowerProfileTest.java
new file mode 100644
index 000000000000..eb7da9ca4ffc
--- /dev/null
+++ b/core/tests/coretests/src/com/android/internal/os/PowerProfileTest.java
@@ -0,0 +1,58 @@
+/*
+ * 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.os;
+
+import android.support.test.InstrumentationRegistry;
+import android.support.test.filters.SmallTest;
+
+import junit.framework.TestCase;
+
+import org.junit.Before;
+import org.junit.Test;
+
+/*
+ * Keep this file in sync with frameworks/base/core/res/res/xml/power_profile_test.xml
+ */
+@SmallTest
+public class PowerProfileTest extends TestCase {
+
+ private PowerProfile mProfile;
+
+ @Before
+ public void setUp() {
+ mProfile = new PowerProfile(InstrumentationRegistry.getContext(), true);
+ }
+
+ @Test
+ public void testPowerProfile() {
+ assertEquals(2, mProfile.getNumCpuClusters());
+ assertEquals(4, mProfile.getNumCoresInCpuCluster(0));
+ assertEquals(4, mProfile.getNumCoresInCpuCluster(1));
+ assertEquals(5.0, mProfile.getAveragePower(PowerProfile.POWER_CPU_SUSPEND));
+ assertEquals(1.11, mProfile.getAveragePower(PowerProfile.POWER_CPU_IDLE));
+ assertEquals(2.55, mProfile.getAveragePower(PowerProfile.POWER_CPU_ACTIVE));
+ assertEquals(2.11, mProfile.getAveragePowerForCpuCluster(0));
+ assertEquals(2.22, mProfile.getAveragePowerForCpuCluster(1));
+ assertEquals(3, mProfile.getNumSpeedStepsInCpuCluster(0));
+ assertEquals(30.0, mProfile.getAveragePowerForCpuCore(0, 2));
+ assertEquals(4, mProfile.getNumSpeedStepsInCpuCluster(1));
+ assertEquals(60.0, mProfile.getAveragePowerForCpuCore(1, 3));
+ assertEquals(3000.0, mProfile.getBatteryCapacity());
+ }
+
+}
diff --git a/data/etc/platform.xml b/data/etc/platform.xml
index 993bae1eea00..c0633cb44e02 100644
--- a/data/etc/platform.xml
+++ b/data/etc/platform.xml
@@ -165,6 +165,9 @@
<assign-permission name="android.permission.ACCESS_SURFACE_FLINGER" uid="graphics" />
+ <assign-permission name="android.permission.DUMP" uid="incidentd" />
+ <assign-permission name="android.permission.PACKAGE_USAGE_STATS" uid="incidentd" />
+
<assign-permission name="android.permission.ACCESS_LOWPAN_STATE" uid="lowpan" />
<assign-permission name="android.permission.MANAGE_LOWPAN_INTERFACES" uid="lowpan" />
diff --git a/docs/html/reference/images/text/style/backgroundcolorspan.png b/docs/html/reference/images/text/style/backgroundcolorspan.png
new file mode 100644
index 000000000000..e7e72714c5bb
--- /dev/null
+++ b/docs/html/reference/images/text/style/backgroundcolorspan.png
Binary files differ
diff --git a/docs/html/reference/images/text/style/foregroundcolorspan.png b/docs/html/reference/images/text/style/foregroundcolorspan.png
new file mode 100644
index 000000000000..f60db6c55254
--- /dev/null
+++ b/docs/html/reference/images/text/style/foregroundcolorspan.png
Binary files differ
diff --git a/graphics/java/android/graphics/ImageDecoder.java b/graphics/java/android/graphics/ImageDecoder.java
index 05dadc97a5ba..4d715d1cb9ea 100644
--- a/graphics/java/android/graphics/ImageDecoder.java
+++ b/graphics/java/android/graphics/ImageDecoder.java
@@ -33,6 +33,8 @@ import android.graphics.drawable.NinePatchDrawable;
import android.net.Uri;
import android.system.ErrnoException;
import android.system.Os;
+import android.util.DisplayMetrics;
+import android.util.TypedValue;
import libcore.io.IoUtils;
import dalvik.system.CloseGuard;
@@ -64,6 +66,19 @@ public final class ImageDecoder implements AutoCloseable {
Resources getResources() { return null; }
/* @hide */
+ int getDensity() { return Bitmap.DENSITY_NONE; }
+
+ /* @hide */
+ int computeDstDensity() {
+ Resources res = getResources();
+ if (res == null) {
+ return Bitmap.getDefaultDensity();
+ }
+
+ return res.getDisplayMetrics().densityDpi;
+ }
+
+ /* @hide */
abstract ImageDecoder createImageDecoder() throws IOException;
};
@@ -170,26 +185,73 @@ public final class ImageDecoder implements AutoCloseable {
return decoder;
}
+ private static class InputStreamSource extends Source {
+ InputStreamSource(Resources res, InputStream is, int inputDensity) {
+ if (is == null) {
+ throw new IllegalArgumentException("The InputStream cannot be null");
+ }
+ mResources = res;
+ mInputStream = is;
+ mInputDensity = res != null ? inputDensity : Bitmap.DENSITY_NONE;
+ }
+
+ final Resources mResources;
+ InputStream mInputStream;
+ final int mInputDensity;
+
+ @Override
+ public Resources getResources() { return mResources; }
+
+ @Override
+ public int getDensity() { return mInputDensity; }
+
+ @Override
+ public ImageDecoder createImageDecoder() throws IOException {
+
+ synchronized (this) {
+ if (mInputStream == null) {
+ throw new IOException("Cannot reuse InputStreamSource");
+ }
+ InputStream is = mInputStream;
+ mInputStream = null;
+ return createFromStream(is);
+ }
+ }
+ }
+
private static class ResourceSource extends Source {
ResourceSource(Resources res, int resId) {
mResources = res;
mResId = resId;
+ mResDensity = Bitmap.DENSITY_NONE;
}
final Resources mResources;
final int mResId;
+ int mResDensity;
@Override
public Resources getResources() { return mResources; }
@Override
+ public int getDensity() { return mResDensity; }
+
+ @Override
public ImageDecoder createImageDecoder() throws IOException {
// This is just used in order to access the underlying Asset and
// keep it alive. FIXME: Can we skip creating this object?
InputStream is = null;
ImageDecoder decoder = null;
+ TypedValue value = new TypedValue();
try {
- is = mResources.openRawResource(mResId);
+ is = mResources.openRawResource(mResId, value);
+
+ if (value.density == TypedValue.DENSITY_DEFAULT) {
+ mResDensity = DisplayMetrics.DENSITY_DEFAULT;
+ } else if (value.density != TypedValue.DENSITY_NONE) {
+ mResDensity = value.density;
+ }
+
if (!(is instanceof AssetManager.AssetInputStream)) {
// This should never happen.
throw new RuntimeException("Resource is not an asset?");
@@ -421,6 +483,22 @@ public final class ImageDecoder implements AutoCloseable {
}
/**
+ * Internal API used to generate bitmaps for use by Drawables (i.e. BitmapDrawable)
+ * @hide
+ */
+ public static Source createSource(Resources res, InputStream is) {
+ return new InputStreamSource(res, is, Bitmap.getDefaultDensity());
+ }
+
+ /**
+ * Internal API used to generate bitmaps for use by Drawables (i.e. BitmapDrawable)
+ * @hide
+ */
+ public static Source createSource(Resources res, InputStream is, int density) {
+ return new InputStreamSource(res, is, density);
+ }
+
+ /**
* Return the width and height of a given sample size.
*
* This takes an input that functions like
@@ -476,6 +554,10 @@ public final class ImageDecoder implements AutoCloseable {
this.resize(dimensions.x, dimensions.y);
}
+ private boolean requestedResize() {
+ return mWidth != mDesiredWidth || mHeight != mDesiredHeight;
+ }
+
// These need to stay in sync with ImageDecoder.cpp's Allocator enum.
/**
* Use the default allocation for the pixel memory.
@@ -730,6 +812,9 @@ public final class ImageDecoder implements AutoCloseable {
"Drawable!");
}
+ // this call potentially manipulates the decoder so it must be performed prior to
+ // decoding the bitmap and after decode set the density on the resulting bitmap
+ final int srcDensity = computeDensity(src, decoder);
if (decoder.mAnimated) {
// AnimatedImageDrawable calls postProcessAndRelease only if
// mPostProcess exists.
@@ -737,7 +822,8 @@ public final class ImageDecoder implements AutoCloseable {
null : decoder;
Drawable d = new AnimatedImageDrawable(decoder.mNativePtr,
postProcessPtr, decoder.mDesiredWidth,
- decoder.mDesiredHeight, decoder.mCropRect,
+ decoder.mDesiredHeight, srcDensity,
+ src.computeDstDensity(), decoder.mCropRect,
decoder.mInputStream, decoder.mAssetFd);
// d has taken ownership of these objects.
decoder.mInputStream = null;
@@ -746,13 +832,15 @@ public final class ImageDecoder implements AutoCloseable {
}
Bitmap bm = decoder.decodeBitmap();
- Resources res = src.getResources();
- if (res == null) {
- bm.setDensity(Bitmap.DENSITY_NONE);
- }
+ bm.setDensity(srcDensity);
+ Resources res = src.getResources();
byte[] np = bm.getNinePatchChunk();
if (np != null && NinePatch.isNinePatchChunk(np)) {
+ if (res != null) {
+ bm.setDensity(res.getDisplayMetrics().densityDpi);
+ }
+
Rect opticalInsets = new Rect();
bm.getOpticalInsets(opticalInsets);
Rect padding = new Rect();
@@ -799,8 +887,46 @@ public final class ImageDecoder implements AutoCloseable {
}
}
- return decoder.decodeBitmap();
+ // this call potentially manipulates the decoder so it must be performed prior to
+ // decoding the bitmap
+ final int srcDensity = computeDensity(src, decoder);
+ Bitmap bm = decoder.decodeBitmap();
+ bm.setDensity(srcDensity);
+ return bm;
+ }
+ }
+
+ // This method may modify the decoder so it must be called prior to performing the decode
+ private static int computeDensity(@NonNull Source src, @NonNull ImageDecoder decoder) {
+ // if the caller changed the size then we treat the density as unknown
+ if (decoder.requestedResize()) {
+ return Bitmap.DENSITY_NONE;
+ }
+
+ // Special stuff for compatibility mode: if the target density is not
+ // the same as the display density, but the resource -is- the same as
+ // the display density, then don't scale it down to the target density.
+ // This allows us to load the system's density-correct resources into
+ // an application in compatibility mode, without scaling those down
+ // to the compatibility density only to have them scaled back up when
+ // drawn to the screen.
+ Resources res = src.getResources();
+ final int srcDensity = src.getDensity();
+ if (res != null && res.getDisplayMetrics().noncompatDensityDpi == srcDensity) {
+ return srcDensity;
}
+
+ // downscale the bitmap if the asset has a higher density than the default
+ final int dstDensity = src.computeDstDensity();
+ if (srcDensity != Bitmap.DENSITY_NONE && srcDensity > dstDensity) {
+ float scale = (float) dstDensity / srcDensity;
+ int scaledWidth = (int) (decoder.mWidth * scale + 0.5f);
+ int scaledHeight = (int) (decoder.mHeight * scale + 0.5f);
+ decoder.resize(scaledWidth, scaledHeight);
+ return dstDensity;
+ }
+
+ return srcDensity;
}
private String getMimeType() {
diff --git a/graphics/java/android/graphics/Typeface.java b/graphics/java/android/graphics/Typeface.java
index 68b7ac287e98..ef4150763139 100644
--- a/graphics/java/android/graphics/Typeface.java
+++ b/graphics/java/android/graphics/Typeface.java
@@ -1025,6 +1025,10 @@ public class Typeface {
xmlFamily.getName(), fallback, languageTags, variant, cache, fontDir);
if (family != null) {
fallbackMap.valueAt(i).add(family);
+ } else if (defaultFamily != null) {
+ fallbackMap.valueAt(i).add(defaultFamily);
+ } else {
+ // There is no valid for for default fallback. Ignore.
}
}
}
diff --git a/graphics/java/android/graphics/drawable/AnimatedImageDrawable.java b/graphics/java/android/graphics/drawable/AnimatedImageDrawable.java
index ce3bd9af73b6..da170c0fae24 100644
--- a/graphics/java/android/graphics/drawable/AnimatedImageDrawable.java
+++ b/graphics/java/android/graphics/drawable/AnimatedImageDrawable.java
@@ -20,12 +20,14 @@ import android.annotation.IntRange;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.content.res.AssetFileDescriptor;
+import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.ColorFilter;
import android.graphics.ImageDecoder;
import android.graphics.PixelFormat;
import android.graphics.Rect;
import android.os.SystemClock;
+import android.util.DisplayMetrics;
import libcore.io.IoUtils;
import libcore.util.NativeAllocationRegistry;
@@ -59,22 +61,31 @@ public class AnimatedImageDrawable extends Drawable implements Animatable {
* decoder is only non-null if it has a PostProcess
*/
public AnimatedImageDrawable(long nativeImageDecoder,
- @Nullable ImageDecoder decoder, int width, int height, Rect cropRect,
+ @Nullable ImageDecoder decoder, int width, int height,
+ int srcDensity, int dstDensity, Rect cropRect,
InputStream inputStream, AssetFileDescriptor afd)
throws IOException {
- mNativePtr = nCreate(nativeImageDecoder, decoder, width, height, cropRect);
- mInputStream = inputStream;
- mAssetFd = afd;
+ width = Bitmap.scaleFromDensity(width, srcDensity, dstDensity);
+ height = Bitmap.scaleFromDensity(height, srcDensity, dstDensity);
if (cropRect == null) {
mIntrinsicWidth = width;
mIntrinsicHeight = height;
} else {
+ cropRect.set(Bitmap.scaleFromDensity(cropRect.left, srcDensity, dstDensity),
+ Bitmap.scaleFromDensity(cropRect.top, srcDensity, dstDensity),
+ Bitmap.scaleFromDensity(cropRect.right, srcDensity, dstDensity),
+ Bitmap.scaleFromDensity(cropRect.bottom, srcDensity, dstDensity));
mIntrinsicWidth = cropRect.width();
mIntrinsicHeight = cropRect.height();
}
- long nativeSize = nNativeByteSize(mNativePtr);
+ mNativePtr = nCreate(nativeImageDecoder, decoder, width, height, cropRect);
+ mInputStream = inputStream;
+ mAssetFd = afd;
+
+ // FIXME: Use the right size for the native allocation.
+ long nativeSize = 200;
NativeAllocationRegistry registry = new NativeAllocationRegistry(
AnimatedImageDrawable.class.getClassLoader(), nGetNativeFinalizer(), nativeSize);
registry.registerNativeAllocation(this, mNativePtr);
diff --git a/graphics/java/android/graphics/drawable/BitmapDrawable.java b/graphics/java/android/graphics/drawable/BitmapDrawable.java
index e3740e3cf284..f74c39d84bce 100644
--- a/graphics/java/android/graphics/drawable/BitmapDrawable.java
+++ b/graphics/java/android/graphics/drawable/BitmapDrawable.java
@@ -27,6 +27,7 @@ import android.graphics.BitmapFactory;
import android.graphics.BitmapShader;
import android.graphics.Canvas;
import android.graphics.ColorFilter;
+import android.graphics.ImageDecoder;
import android.graphics.Insets;
import android.graphics.Matrix;
import android.graphics.Outline;
@@ -49,6 +50,7 @@ import com.android.internal.R;
import org.xmlpull.v1.XmlPullParser;
import org.xmlpull.v1.XmlPullParserException;
+import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
@@ -111,7 +113,7 @@ public class BitmapDrawable extends Drawable {
*/
@Deprecated
public BitmapDrawable() {
- mBitmapState = new BitmapState((Bitmap) null);
+ init(new BitmapState((Bitmap) null), null);
}
/**
@@ -124,8 +126,7 @@ public class BitmapDrawable extends Drawable {
@SuppressWarnings("unused")
@Deprecated
public BitmapDrawable(Resources res) {
- mBitmapState = new BitmapState((Bitmap) null);
- mBitmapState.mTargetDensity = mTargetDensity;
+ init(new BitmapState((Bitmap) null), res);
}
/**
@@ -135,7 +136,7 @@ public class BitmapDrawable extends Drawable {
*/
@Deprecated
public BitmapDrawable(Bitmap bitmap) {
- this(new BitmapState(bitmap), null);
+ init(new BitmapState(bitmap), null);
}
/**
@@ -143,8 +144,7 @@ public class BitmapDrawable extends Drawable {
* the display metrics of the resources.
*/
public BitmapDrawable(Resources res, Bitmap bitmap) {
- this(new BitmapState(bitmap), res);
- mBitmapState.mTargetDensity = mTargetDensity;
+ init(new BitmapState(bitmap), res);
}
/**
@@ -154,10 +154,7 @@ public class BitmapDrawable extends Drawable {
*/
@Deprecated
public BitmapDrawable(String filepath) {
- this(new BitmapState(BitmapFactory.decodeFile(filepath)), null);
- if (mBitmapState.mBitmap == null) {
- android.util.Log.w("BitmapDrawable", "BitmapDrawable cannot decode " + filepath);
- }
+ this(null, filepath);
}
/**
@@ -165,10 +162,21 @@ public class BitmapDrawable extends Drawable {
*/
@SuppressWarnings("unused")
public BitmapDrawable(Resources res, String filepath) {
- this(new BitmapState(BitmapFactory.decodeFile(filepath)), null);
- mBitmapState.mTargetDensity = mTargetDensity;
- if (mBitmapState.mBitmap == null) {
- android.util.Log.w("BitmapDrawable", "BitmapDrawable cannot decode " + filepath);
+ Bitmap bitmap = null;
+ try (FileInputStream stream = new FileInputStream(filepath)) {
+ bitmap = ImageDecoder.decodeBitmap(ImageDecoder.createSource(res, stream),
+ (info, decoder) -> {
+ decoder.setAllocator(ImageDecoder.SOFTWARE_ALLOCATOR);
+ });
+ } catch (Exception e) {
+ /* do nothing. This matches the behavior of BitmapFactory.decodeFile()
+ If the exception happened on decode, mBitmapState.mBitmap will be null.
+ */
+ } finally {
+ init(new BitmapState(bitmap), res);
+ if (mBitmapState.mBitmap == null) {
+ android.util.Log.w("BitmapDrawable", "BitmapDrawable cannot decode " + filepath);
+ }
}
}
@@ -179,10 +187,7 @@ public class BitmapDrawable extends Drawable {
*/
@Deprecated
public BitmapDrawable(java.io.InputStream is) {
- this(new BitmapState(BitmapFactory.decodeStream(is)), null);
- if (mBitmapState.mBitmap == null) {
- android.util.Log.w("BitmapDrawable", "BitmapDrawable cannot decode " + is);
- }
+ this(null, is);
}
/**
@@ -190,10 +195,21 @@ public class BitmapDrawable extends Drawable {
*/
@SuppressWarnings("unused")
public BitmapDrawable(Resources res, java.io.InputStream is) {
- this(new BitmapState(BitmapFactory.decodeStream(is)), null);
- mBitmapState.mTargetDensity = mTargetDensity;
- if (mBitmapState.mBitmap == null) {
- android.util.Log.w("BitmapDrawable", "BitmapDrawable cannot decode " + is);
+ Bitmap bitmap = null;
+ try {
+ bitmap = ImageDecoder.decodeBitmap(ImageDecoder.createSource(res, is),
+ (info, decoder) -> {
+ decoder.setAllocator(ImageDecoder.SOFTWARE_ALLOCATOR);
+ });
+ } catch (Exception e) {
+ /* do nothing. This matches the behavior of BitmapFactory.decodeStream()
+ If the exception happened on decode, mBitmapState.mBitmap will be null.
+ */
+ } finally {
+ init(new BitmapState(bitmap), res);
+ if (mBitmapState.mBitmap == null) {
+ android.util.Log.w("BitmapDrawable", "BitmapDrawable cannot decode " + is);
+ }
}
}
@@ -812,9 +828,19 @@ public class BitmapDrawable extends Drawable {
}
}
+ int density = Bitmap.DENSITY_NONE;
+ if (value.density == TypedValue.DENSITY_DEFAULT) {
+ density = DisplayMetrics.DENSITY_DEFAULT;
+ } else if (value.density != TypedValue.DENSITY_NONE) {
+ density = value.density;
+ }
+
Bitmap bitmap = null;
try (InputStream is = r.openRawResource(srcResId, value)) {
- bitmap = BitmapFactory.decodeResourceStream(r, value, is, null, null);
+ ImageDecoder.Source source = ImageDecoder.createSource(r, is, density);
+ bitmap = ImageDecoder.decodeBitmap(source, (info, decoder) -> {
+ decoder.setAllocator(ImageDecoder.SOFTWARE_ALLOCATOR);
+ });
} catch (Exception e) {
// Do nothing and pick up the error below.
}
@@ -1013,14 +1039,21 @@ public class BitmapDrawable extends Drawable {
}
}
+ private BitmapDrawable(BitmapState state, Resources res) {
+ init(state, res);
+ }
+
/**
- * The one constructor to rule them all. This is called by all public
+ * The one helper to rule them all. This is called by all public & private
* constructors to set the state and initialize local properties.
*/
- private BitmapDrawable(BitmapState state, Resources res) {
+ private void init(BitmapState state, Resources res) {
mBitmapState = state;
-
updateLocalState(res);
+
+ if (mBitmapState != null && res != null) {
+ mBitmapState.mTargetDensity = mTargetDensity;
+ }
}
/**
diff --git a/graphics/java/android/graphics/drawable/Drawable.java b/graphics/java/android/graphics/drawable/Drawable.java
index f17cd768c386..291b0a0be4f4 100644
--- a/graphics/java/android/graphics/drawable/Drawable.java
+++ b/graphics/java/android/graphics/drawable/Drawable.java
@@ -37,6 +37,7 @@ import android.graphics.BitmapFactory;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.ColorFilter;
+import android.graphics.ImageDecoder;
import android.graphics.Insets;
import android.graphics.NinePatch;
import android.graphics.Outline;
@@ -50,11 +51,13 @@ import android.graphics.Xfermode;
import android.os.Trace;
import android.util.AttributeSet;
import android.util.DisplayMetrics;
+import android.util.Log;
import android.util.StateSet;
import android.util.TypedValue;
import android.util.Xml;
import android.view.View;
+import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.lang.ref.WeakReference;
@@ -1175,6 +1178,10 @@ public abstract class Drawable {
return null;
}
+ if (opts == null) {
+ return getBitmapDrawable(res, value, is);
+ }
+
/* ugh. The decodeStream contract is that we have already allocated
the pad rect, but if the bitmap does not had a ninepatch chunk,
then the pad will be ignored. If we could change this to lazily
@@ -1207,6 +1214,33 @@ public abstract class Drawable {
return null;
}
+ private static Drawable getBitmapDrawable(Resources res, TypedValue value, InputStream is) {
+ try {
+ ImageDecoder.Source source = null;
+ if (value != null) {
+ int density = Bitmap.DENSITY_NONE;
+ if (value.density == TypedValue.DENSITY_DEFAULT) {
+ density = DisplayMetrics.DENSITY_DEFAULT;
+ } else if (value.density != TypedValue.DENSITY_NONE) {
+ density = value.density;
+ }
+ source = ImageDecoder.createSource(res, is, density);
+ } else {
+ source = ImageDecoder.createSource(res, is);
+ }
+
+ return ImageDecoder.decodeDrawable(source, (info, decoder) -> {
+ decoder.setAllocator(ImageDecoder.SOFTWARE_ALLOCATOR);
+ });
+ } catch (IOException e) {
+ /* do nothing.
+ If the exception happened on decode, the drawable will be null.
+ */
+ Log.e("Drawable", "Unable to decode stream: " + e);
+ }
+ return null;
+ }
+
/**
* Create a drawable from an XML document. For more information on how to
* create resources in XML, see
@@ -1306,11 +1340,10 @@ public abstract class Drawable {
}
Trace.traceBegin(Trace.TRACE_TAG_RESOURCES, pathName);
- try {
- Bitmap bm = BitmapFactory.decodeFile(pathName);
- if (bm != null) {
- return drawableFromBitmap(null, bm, null, null, null, pathName);
- }
+ try (FileInputStream stream = new FileInputStream(pathName)) {
+ return getBitmapDrawable(null, null, stream);
+ } catch(IOException e) {
+ // Do nothing; we will just return null if the FileInputStream had an error
} finally {
Trace.traceEnd(Trace.TRACE_TAG_RESOURCES);
}
diff --git a/location/java/com/android/internal/location/gnssmetrics/GnssMetrics.java b/location/java/com/android/internal/location/gnssmetrics/GnssMetrics.java
index 833376cfa057..603926f4fe4d 100644
--- a/location/java/com/android/internal/location/gnssmetrics/GnssMetrics.java
+++ b/location/java/com/android/internal/location/gnssmetrics/GnssMetrics.java
@@ -19,10 +19,12 @@ package com.android.internal.location.gnssmetrics;
import android.os.SystemClock;
import android.util.Base64;
+import android.util.Log;
import android.util.TimeUtils;
import java.util.Arrays;
+import com.android.internal.app.IBatteryStats;
import com.android.internal.location.nano.GnssLogsProto.GnssLog;
/**
@@ -31,14 +33,29 @@ import com.android.internal.location.nano.GnssLogsProto.GnssLog;
*/
public class GnssMetrics {
+ private static final String TAG = GnssMetrics.class.getSimpleName();
+
+ /* Constant which indicates GPS signal quality is poor */
+ public static final int GPS_SIGNAL_QUALITY_POOR = 0;
+
+ /* Constant which indicates GPS signal quality is good */
+ public static final int GPS_SIGNAL_QUALITY_GOOD = 1;
+
+ /* Number of GPS signal quality levels */
+ public static final int NUM_GPS_SIGNAL_QUALITY_LEVELS = GPS_SIGNAL_QUALITY_GOOD + 1;
+
/** Default time between location fixes (in millisecs) */
private static final int DEFAULT_TIME_BETWEEN_FIXES_MILLISECS = 1000;
/* The time since boot when logging started */
private String logStartInElapsedRealTime;
+ /* GNSS power metrics */
+ private GnssPowerMetrics mGnssPowerMetrics;
+
/** Constructor */
- public GnssMetrics() {
+ public GnssMetrics(IBatteryStats stats) {
+ mGnssPowerMetrics = new GnssPowerMetrics(stats);
locationFailureStatistics = new Statistics();
timeToFirstFixSecStatistics = new Statistics();
positionAccuracyMeterStatistics = new Statistics();
@@ -103,11 +120,18 @@ public class GnssMetrics {
*
*/
public void logCn0(float[] cn0s, int numSv) {
- if (numSv < 4) {
+ if (numSv == 0 || cn0s == null || cn0s.length == 0 || cn0s.length < numSv) {
+ if (numSv == 0) {
+ mGnssPowerMetrics.reportSignalQuality(null, 0);
+ }
return;
}
float[] cn0Array = Arrays.copyOf(cn0s, numSv);
Arrays.sort(cn0Array);
+ mGnssPowerMetrics.reportSignalQuality(cn0Array, numSv);
+ if (numSv < 4) {
+ return;
+ }
if (cn0Array[numSv - 4] > 0.0) {
double top4AvgCn0 = 0.0;
for (int i = numSv - 4; i < numSv; i++) {
@@ -265,4 +289,62 @@ public class GnssMetrics {
topFourAverageCn0Statistics.reset();
return;
}
+
+ /* Class for handling GNSS power related metrics */
+ private class GnssPowerMetrics {
+
+ /* Threshold for Top Four Average CN0 below which GNSS signal quality is declared poor */
+ private static final double POOR_TOP_FOUR_AVG_CN0_THRESHOLD_DB_HZ = 20.0;
+
+ /* Minimum change in Top Four Average CN0 needed to trigger a report */
+ private static final double REPORTING_THRESHOLD_DB_HZ = 1.0;
+
+ /* BatteryStats API */
+ private final IBatteryStats mBatteryStats;
+
+ /* Last reported Top Four Average CN0 */
+ private double mLastAverageCn0;
+
+ public GnssPowerMetrics(IBatteryStats stats) {
+ mBatteryStats = stats;
+ // Used to initialize the variable to a very small value (unachievable in practice) so that
+ // the first CNO report will trigger an update to BatteryStats
+ mLastAverageCn0 = -100.0;
+ }
+
+ /**
+ * Reports signal quality to BatteryStats. Signal quality is based on Top four average CN0. If
+ * the number of SVs seen is less than 4, then signal quality is the average CN0.
+ * Changes are reported only if the average CN0 changes by more than REPORTING_THRESHOLD_DB_HZ.
+ */
+ public void reportSignalQuality(float[] ascendingCN0Array, int numSv) {
+ double avgCn0 = 0.0;
+ if (numSv > 0) {
+ for (int i = Math.max(0, numSv - 4); i < numSv; i++) {
+ avgCn0 += (double) ascendingCN0Array[i];
+ }
+ avgCn0 /= Math.min(numSv, 4);
+ }
+ if (Math.abs(avgCn0 - mLastAverageCn0) < REPORTING_THRESHOLD_DB_HZ) {
+ return;
+ }
+ try {
+ mBatteryStats.noteGpsSignalQuality(getSignalLevel(avgCn0));
+ mLastAverageCn0 = avgCn0;
+ } catch (Exception e) {
+ Log.w(TAG, "Exception", e);
+ }
+ return;
+ }
+
+ /**
+ * Obtains signal level based on CN0
+ */
+ private int getSignalLevel(double cn0) {
+ if (cn0 > POOR_TOP_FOUR_AVG_CN0_THRESHOLD_DB_HZ) {
+ return GnssMetrics.GPS_SIGNAL_QUALITY_GOOD;
+ }
+ return GnssMetrics.GPS_SIGNAL_QUALITY_POOR;
+ }
+ }
} \ No newline at end of file
diff --git a/media/java/android/media/AudioFormat.java b/media/java/android/media/AudioFormat.java
index 93fc3da54550..46fe89a74ce5 100644
--- a/media/java/android/media/AudioFormat.java
+++ b/media/java/android/media/AudioFormat.java
@@ -240,20 +240,25 @@ public final class AudioFormat implements Parcelable {
public static final int ENCODING_DTS_HD = 8;
/** Audio data format: MP3 compressed
* @hide
+ * TODO unhide and add to @Encoding (intentional white space
* */
public static final int ENCODING_MP3 = 9;
/** Audio data format: AAC LC compressed
* @hide
+ * TODO unhide and add to @Encoding (intentional white space
* */
public static final int ENCODING_AAC_LC = 10;
/** Audio data format: AAC HE V1 compressed
* @hide
+ * TODO unhide and add to @Encoding (intentional white space
* */
public static final int ENCODING_AAC_HE_V1 = 11;
/** Audio data format: AAC HE V2 compressed
* @hide
+ * TODO unhide and add to @Encoding (intentional white space
* */
public static final int ENCODING_AAC_HE_V2 = 12;
+
/** Audio data format: compressed audio wrapped in PCM for HDMI
* or S/PDIF passthrough.
* IEC61937 uses a stereo stream of 16-bit samples as the wrapper.
@@ -266,6 +271,16 @@ public final class AudioFormat implements Parcelable {
/** Audio data format: DOLBY TRUEHD compressed
**/
public static final int ENCODING_DOLBY_TRUEHD = 14;
+ /** Audio data format: AAC ELD compressed
+ * @hide
+ * TODO unhide and add to @Encoding (intentional white space
+ * */
+ public static final int ENCODING_AAC_ELD = 15;
+ /** Audio data format: AAC xHE compressed
+ * @hide
+ * TODO unhide and add to @Encoding (intentional white space
+ * */
+ public static final int ENCODING_AAC_XHE = 16;
/** @hide */
public static String toLogFriendlyEncoding(int enc) {
@@ -298,6 +313,10 @@ public final class AudioFormat implements Parcelable {
return "ENCODING_IEC61937";
case ENCODING_DOLBY_TRUEHD:
return "ENCODING_DOLBY_TRUEHD";
+ case ENCODING_AAC_ELD:
+ return "ENCODING_AAC_ELD";
+ case ENCODING_AAC_XHE:
+ return "ENCODING_AAC_XHE";
default :
return "invalid encoding " + enc;
}
@@ -514,6 +533,8 @@ public final class AudioFormat implements Parcelable {
case ENCODING_AAC_HE_V1:
case ENCODING_AAC_HE_V2:
case ENCODING_IEC61937:
+ case ENCODING_AAC_ELD:
+ case ENCODING_AAC_XHE:
return true;
default:
return false;
@@ -532,6 +553,13 @@ public final class AudioFormat implements Parcelable {
case ENCODING_DTS:
case ENCODING_DTS_HD:
case ENCODING_IEC61937:
+ //TODO not true yet (intended white space
+ case ENCODING_MP3:
+ case ENCODING_AAC_LC:
+ case ENCODING_AAC_HE_V1:
+ case ENCODING_AAC_HE_V2:
+ case ENCODING_AAC_ELD:
+ case ENCODING_AAC_XHE:
return true;
default:
return false;
@@ -556,6 +584,8 @@ public final class AudioFormat implements Parcelable {
case ENCODING_AAC_HE_V1:
case ENCODING_AAC_HE_V2:
case ENCODING_IEC61937: // wrapped in PCM but compressed
+ case ENCODING_AAC_ELD:
+ case ENCODING_AAC_XHE:
return false;
case ENCODING_INVALID:
default:
@@ -581,6 +611,8 @@ public final class AudioFormat implements Parcelable {
case ENCODING_AAC_LC:
case ENCODING_AAC_HE_V1:
case ENCODING_AAC_HE_V2:
+ case ENCODING_AAC_ELD:
+ case ENCODING_AAC_XHE:
return false;
case ENCODING_INVALID:
default:
@@ -794,14 +826,7 @@ public final class AudioFormat implements Parcelable {
/**
* Sets the data encoding format.
- * @param encoding one of {@link AudioFormat#ENCODING_DEFAULT},
- * {@link AudioFormat#ENCODING_PCM_8BIT},
- * {@link AudioFormat#ENCODING_PCM_16BIT},
- * {@link AudioFormat#ENCODING_PCM_FLOAT},
- * {@link AudioFormat#ENCODING_AC3},
- * {@link AudioFormat#ENCODING_E_AC3}.
- * {@link AudioFormat#ENCODING_DTS},
- * {@link AudioFormat#ENCODING_DTS_HD}.
+ * @param encoding the specified encoding or default.
* @return the same Builder instance.
* @throws java.lang.IllegalArgumentException
*/
@@ -818,6 +843,12 @@ public final class AudioFormat implements Parcelable {
case ENCODING_DTS:
case ENCODING_DTS_HD:
case ENCODING_IEC61937:
+ case ENCODING_MP3:
+ case ENCODING_AAC_LC:
+ case ENCODING_AAC_HE_V1:
+ case ENCODING_AAC_HE_V2:
+ case ENCODING_AAC_ELD:
+ case ENCODING_AAC_XHE:
mEncoding = encoding;
break;
case ENCODING_INVALID:
@@ -1016,7 +1047,7 @@ public final class AudioFormat implements Parcelable {
}
/** @hide */
- @IntDef({
+ @IntDef(flag = false, prefix = "ENCODING", value = {
ENCODING_DEFAULT,
ENCODING_PCM_8BIT,
ENCODING_PCM_16BIT,
@@ -1025,8 +1056,8 @@ public final class AudioFormat implements Parcelable {
ENCODING_E_AC3,
ENCODING_DTS,
ENCODING_DTS_HD,
- ENCODING_IEC61937
- })
+ ENCODING_IEC61937 }
+ )
@Retention(RetentionPolicy.SOURCE)
public @interface Encoding {}
diff --git a/media/java/android/media/AudioManager.java b/media/java/android/media/AudioManager.java
index 913b5e841112..4d5343c97b05 100644
--- a/media/java/android/media/AudioManager.java
+++ b/media/java/android/media/AudioManager.java
@@ -1329,6 +1329,21 @@ public class AudioManager {
}
//====================================================================
+ // Offload query
+ /**
+ * @hide
+ * TODO unhide (intentional white space to attract attention:
+ * Returns whether offloaded playback of an audio format is supported on the device.
+ * Offloaded playback is where the decoding of an audio stream is not competing with other
+ * software resources. In general, it is supported by dedicated hardware, such as audio DSPs.
+ * @param format the audio format (codec, sample rate, channels) being checked.
+ * @return true if the given audio format can be offloaded.
+ */
+ public static boolean isOffloadedPlaybackSupported(@NonNull AudioFormat format) {
+ return AudioSystem.isOffloadSupported(format);
+ }
+
+ //====================================================================
// Bluetooth SCO control
/**
* Sticky broadcast intent action indicating that the Bluetooth SCO audio
@@ -3746,6 +3761,33 @@ public class AudioManager {
}
/**
+ * Indicate A2DP source or sink connection state change and eventually suppress
+ * the {@link AudioManager.ACTION_AUDIO_BECOMING_NOISY} intent.
+ * @param device Bluetooth device connected/disconnected
+ * @param state new connection state (BluetoothProfile.STATE_xxx)
+ * @param profile profile for the A2DP device
+ * (either {@link android.bluetooth.BluetoothProfile.A2DP} or
+ * {@link android.bluetooth.BluetoothProfile.A2DP_SINK})
+ * @param suppressNoisyIntent if true the
+ * {@link AudioManager.ACTION_AUDIO_BECOMING_NOISY} intent will not be sent.
+ * @return a delay in ms that the caller should wait before broadcasting
+ * BluetoothA2dp.ACTION_CONNECTION_STATE_CHANGED intent.
+ * {@hide}
+ */
+ public int setBluetoothA2dpDeviceConnectionStateSuppressNoisyIntent(
+ BluetoothDevice device, int state, int profile, boolean suppressNoisyIntent) {
+ final IAudioService service = getService();
+ int delay = 0;
+ try {
+ delay = service.setBluetoothA2dpDeviceConnectionStateSuppressNoisyIntent(device,
+ state, profile, suppressNoisyIntent);
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ return delay;
+ }
+
+ /**
* Indicate A2DP device configuration has changed.
* @param device Bluetooth device whose configuration has changed.
* {@hide}
diff --git a/media/java/android/media/AudioSystem.java b/media/java/android/media/AudioSystem.java
index e56944dff782..b4316ba9b1df 100644
--- a/media/java/android/media/AudioSystem.java
+++ b/media/java/android/media/AudioSystem.java
@@ -16,6 +16,7 @@
package android.media;
+import android.annotation.NonNull;
import android.content.Context;
import android.content.pm.PackageManager;
import android.media.audiopolicy.AudioMix;
@@ -818,6 +819,14 @@ public class AudioSystem
public static native float getStreamVolumeDB(int stream, int index, int device);
+ static boolean isOffloadSupported(@NonNull AudioFormat format) {
+ return native_is_offload_supported(format.getEncoding(), format.getSampleRate(),
+ format.getChannelMask(), format.getChannelIndexMask());
+ }
+
+ private static native boolean native_is_offload_supported(int encoding, int sampleRate,
+ int channelMask, int channelIndexMask);
+
// Items shared with audio service
/**
@@ -914,7 +923,8 @@ public class AudioSystem
(1 << STREAM_MUSIC) |
(1 << STREAM_RING) |
(1 << STREAM_NOTIFICATION) |
- (1 << STREAM_SYSTEM);
+ (1 << STREAM_SYSTEM) |
+ (1 << STREAM_VOICE_CALL);
/**
* Event posted by AudioTrack and AudioRecord JNI (JNIDeviceCallback) when routing changes.
diff --git a/media/java/android/media/AudioTrack.java b/media/java/android/media/AudioTrack.java
index e535fdf53d01..6add381fc885 100644
--- a/media/java/android/media/AudioTrack.java
+++ b/media/java/android/media/AudioTrack.java
@@ -24,7 +24,9 @@ import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.nio.NioUtils;
import java.util.Collection;
+import java.util.concurrent.Executor;
+import android.annotation.CallbackExecutor;
import android.annotation.IntDef;
import android.annotation.NonNull;
import android.annotation.Nullable;
@@ -185,6 +187,22 @@ public class AudioTrack extends PlayerBase
* Event id denotes when previously set update period has elapsed during playback.
*/
private static final int NATIVE_EVENT_NEW_POS = 4;
+ /**
+ * Callback for more data
+ * TODO only for offload
+ */
+ private static final int NATIVE_EVENT_MORE_DATA = 0;
+ /**
+ * IAudioTrack tear down for offloaded tracks
+ * TODO: when received, java AudioTrack must be released
+ */
+ private static final int NATIVE_EVENT_NEW_IAUDIOTRACK = 6;
+ /**
+ * Event id denotes when all the buffers queued in AF and HW are played
+ * back (after stop is called) for an offloaded track.
+ * TODO: not just for offload
+ */
+ private static final int NATIVE_EVENT_STREAM_END = 7;
private final static String TAG = "android.media.AudioTrack";
@@ -540,6 +558,12 @@ public class AudioTrack extends PlayerBase
public AudioTrack(AudioAttributes attributes, AudioFormat format, int bufferSizeInBytes,
int mode, int sessionId)
throws IllegalArgumentException {
+ this(attributes, format, bufferSizeInBytes, mode, sessionId, false /*offload*/);
+ }
+
+ private AudioTrack(AudioAttributes attributes, AudioFormat format, int bufferSizeInBytes,
+ int mode, int sessionId, boolean offload)
+ throws IllegalArgumentException {
super(attributes, AudioPlaybackConfiguration.PLAYER_TYPE_JAM_AUDIOTRACK);
// mState already == STATE_UNINITIALIZED
@@ -601,7 +625,8 @@ public class AudioTrack extends PlayerBase
// native initialization
int initResult = native_setup(new WeakReference<AudioTrack>(this), mAttributes,
sampleRate, mChannelMask, mChannelIndexMask, mAudioFormat,
- mNativeBufferSizeInBytes, mDataLoadMode, session, 0 /*nativeTrackInJavaObj*/);
+ mNativeBufferSizeInBytes, mDataLoadMode, session, 0 /*nativeTrackInJavaObj*/,
+ offload);
if (initResult != SUCCESS) {
loge("Error code "+initResult+" when initializing AudioTrack.");
return; // with mState == STATE_UNINITIALIZED
@@ -681,7 +706,8 @@ public class AudioTrack extends PlayerBase
0 /*mNativeBufferSizeInBytes - NA*/,
0 /*mDataLoadMode - NA*/,
session,
- nativeTrackInJavaObj);
+ nativeTrackInJavaObj,
+ false /*offload*/);
if (initResult != SUCCESS) {
loge("Error code "+initResult+" when initializing AudioTrack.");
return; // with mState == STATE_UNINITIALIZED
@@ -730,6 +756,7 @@ public class AudioTrack extends PlayerBase
* <br>If the session ID is not specified with {@link #setSessionId(int)}, a new one will
* be generated.
*/
+ // TODO add that offload is false by default (intended white space
public static class Builder {
private AudioAttributes mAttributes;
private AudioFormat mFormat;
@@ -737,6 +764,7 @@ public class AudioTrack extends PlayerBase
private int mSessionId = AudioManager.AUDIO_SESSION_ID_GENERATE;
private int mMode = MODE_STREAM;
private int mPerformanceMode = PERFORMANCE_MODE_NONE;
+ private boolean mOffload = false;
/**
* Constructs a new Builder with the default values as described above.
@@ -867,6 +895,24 @@ public class AudioTrack extends PlayerBase
}
/**
+ * @hide
+ * TODO unhide (intentional whitespace
+ * TODO should offload require POWER_SAVING?
+ * Sets whether this track will play through the offloaded audio path.
+ * When set to true, at build time, the audio format will be checked against
+ * {@link AudioManager#isOffloadedPlaybackSupported(AudioFormat)} to verify the audio format
+ * used by this track is supported on the device's offload path (if any).
+ * <br>Offload is only supported for media audio data, and therefore require that
+ * the usage be {@link AudioAttributes#USAGE_MEDIA}.
+ * @param offload true to require the offload path for playback.
+ * @return the same Builder instance.
+ */
+ public @NonNull Builder setOffloadedPlayback(boolean offload) {
+ mOffload = offload;
+ return this;
+ }
+
+ /**
* Builds an {@link AudioTrack} instance initialized with all the parameters set
* on this <code>Builder</code>.
* @return a new successfully initialized {@link AudioTrack} instance.
@@ -909,6 +955,19 @@ public class AudioTrack extends PlayerBase
.setEncoding(AudioFormat.ENCODING_DEFAULT)
.build();
}
+
+ //TODO tie offload to PERFORMANCE_MODE_POWER_SAVING?
+ if (mOffload) {
+ if (mAttributes.getUsage() != AudioAttributes.USAGE_MEDIA) {
+ throw new UnsupportedOperationException(
+ "Cannot create AudioTrack, offload requires USAGE_MEDIA");
+ }
+ if (!AudioManager.isOffloadedPlaybackSupported(mFormat)) {
+ throw new UnsupportedOperationException(
+ "Cannot create AudioTrack, offload format not supported");
+ }
+ }
+
try {
// If the buffer size is not specified in streaming mode,
// use a single frame for the buffer size and let the
@@ -918,7 +977,7 @@ public class AudioTrack extends PlayerBase
* mFormat.getBytesPerSample(mFormat.getEncoding());
}
final AudioTrack track = new AudioTrack(
- mAttributes, mFormat, mBufferSizeInBytes, mMode, mSessionId);
+ mAttributes, mFormat, mBufferSizeInBytes, mMode, mSessionId, mOffload);
if (track.getState() == STATE_UNINITIALIZED) {
// release is not necessary
throw new UnsupportedOperationException("Cannot create AudioTrack");
@@ -2882,6 +2941,55 @@ public class AudioTrack extends PlayerBase
void onPeriodicNotification(AudioTrack track);
}
+ /**
+ * @hide
+ * TODO unhide (intentional white space to attract attention:
+ * Abstract class to receive event notification about the stream playback.
+ */
+ public abstract static class StreamEventCallback {
+ // TODO rename if supported for non offload tracks
+ public void onTearDown(AudioTrack track) { }
+ public void onStreamPresentationEnd(AudioTrack track) { }
+ public void onStreamDataRequest(AudioTrack track) { }
+ }
+
+ private Executor mStreamEventExec;
+ private StreamEventCallback mStreamEventCb;
+ private final Object mStreamEventCbLock = new Object();
+
+ /**
+ * @hide
+ * TODO unhide (intentional white space to attract attention:
+ * Registers a callback for notification of stream events.
+ * @param executor {@link Executor} to handle the callbacks
+ * @param eventCallback the callback to receive the stream events
+ */
+ public void setStreamEventCallback(@NonNull @CallbackExecutor Executor executor,
+ @NonNull StreamEventCallback eventCallback) {
+ if (eventCallback == null) {
+ throw new IllegalArgumentException("Illegal null StreamEventCallback");
+ }
+ if (executor == null) {
+ throw new IllegalArgumentException("Illegal null Executor for the StreamEventCallback");
+ }
+ synchronized (mStreamEventCbLock) {
+ mStreamEventExec = executor;
+ mStreamEventCb = eventCallback;
+ }
+ }
+
+ /**
+ * @hide
+ * Unregisters the callback for notification of stream events, previously set
+ * by {@link #setStreamEventCallback(StreamEventCallback, Executor)}.
+ */
+ public void removeStreamEventCallback() {
+ synchronized (mStreamEventCbLock) {
+ mStreamEventExec = null;
+ mStreamEventCb = null;
+ }
+ }
+
//---------------------------------------------------------
// Inner classes
//--------------------
@@ -2965,7 +3073,7 @@ public class AudioTrack extends PlayerBase
private static void postEventFromNative(Object audiotrack_ref,
int what, int arg1, int arg2, Object obj) {
//logd("Event posted from the native side: event="+ what + " args="+ arg1+" "+arg2);
- AudioTrack track = (AudioTrack)((WeakReference)audiotrack_ref).get();
+ final AudioTrack track = (AudioTrack)((WeakReference)audiotrack_ref).get();
if (track == null) {
return;
}
@@ -2974,6 +3082,32 @@ public class AudioTrack extends PlayerBase
track.broadcastRoutingChange();
return;
}
+
+ if (what == NATIVE_EVENT_MORE_DATA || what == NATIVE_EVENT_NEW_IAUDIOTRACK
+ || what == NATIVE_EVENT_STREAM_END) {
+ final Executor exec;
+ final StreamEventCallback cb;
+ synchronized (track.mStreamEventCbLock) {
+ exec = track.mStreamEventExec;
+ cb = track.mStreamEventCb;
+ }
+ if ((exec == null) || (cb == null)) {
+ return;
+ }
+ switch (what) {
+ case NATIVE_EVENT_MORE_DATA:
+ exec.execute(() -> cb.onStreamDataRequest(track));
+ return;
+ case NATIVE_EVENT_NEW_IAUDIOTRACK:
+ // TODO also release track as it's not longer usable
+ exec.execute(() -> cb.onTearDown(track));
+ return;
+ case NATIVE_EVENT_STREAM_END:
+ exec.execute(() -> cb.onStreamPresentationEnd(track));
+ return;
+ }
+ }
+
NativePositionEventHandlerDelegate delegate = track.mEventHandlerDelegate;
if (delegate != null) {
Handler handler = delegate.getHandler();
@@ -2995,7 +3129,8 @@ public class AudioTrack extends PlayerBase
private native final int native_setup(Object /*WeakReference<AudioTrack>*/ audiotrack_this,
Object /*AudioAttributes*/ attributes,
int[] sampleRate, int channelMask, int channelIndexMask, int audioFormat,
- int buffSizeInBytes, int mode, int[] sessionId, long nativeAudioTrack);
+ int buffSizeInBytes, int mode, int[] sessionId, long nativeAudioTrack,
+ boolean offload);
private native final void native_finalize();
diff --git a/media/java/android/media/IAudioService.aidl b/media/java/android/media/IAudioService.aidl
index bb6ae9863d31..6c6522328e8d 100644
--- a/media/java/android/media/IAudioService.aidl
+++ b/media/java/android/media/IAudioService.aidl
@@ -203,5 +203,8 @@ interface IAudioService {
oneway void playerHasOpPlayAudio(in int piid, in boolean hasOpPlayAudio);
+ int setBluetoothA2dpDeviceConnectionStateSuppressNoisyIntent(in BluetoothDevice device,
+ int state, int profile, boolean suppressNoisyIntent);
+
// WARNING: read warning at top of file, it is recommended to add new methods at the end
}
diff --git a/media/java/android/media/update/ApiLoader.java b/media/java/android/media/update/ApiLoader.java
index 07483f60c69e..b928e9319b18 100644
--- a/media/java/android/media/update/ApiLoader.java
+++ b/media/java/android/media/update/ApiLoader.java
@@ -16,8 +16,10 @@
package android.media.update;
+import android.content.res.Resources;
import android.content.Context;
-import android.content.pm.PackageManager.NameNotFoundException;
+import android.content.pm.PackageManager;
+import android.os.Build;
/**
* @hide
@@ -34,23 +36,25 @@ public final class ApiLoader {
public static StaticProvider getProvider(Context context) {
try {
return (StaticProvider) getMediaLibraryImpl(context);
- } catch (NameNotFoundException | ReflectiveOperationException e) {
+ } catch (PackageManager.NameNotFoundException | ReflectiveOperationException e) {
throw new RuntimeException(e);
}
}
// TODO This method may do I/O; Ensure it does not violate (emit warnings in) strict mode.
- private static synchronized Object getMediaLibraryImpl(Context appContext)
- throws NameNotFoundException, ReflectiveOperationException {
+ private static synchronized Object getMediaLibraryImpl(Context context)
+ throws PackageManager.NameNotFoundException, ReflectiveOperationException {
if (sMediaLibrary != null) return sMediaLibrary;
- // TODO Dynamically find the package name
- Context libContext = appContext.createPackageContext(UPDATE_PACKAGE,
+ // TODO Figure out when to use which package (query media update service)
+ int flags = Build.IS_DEBUGGABLE ? 0 : PackageManager.MATCH_FACTORY_ONLY;
+ Context libContext = context.createApplicationContext(
+ context.getPackageManager().getPackageInfo(UPDATE_PACKAGE, flags).applicationInfo,
Context.CONTEXT_INCLUDE_CODE | Context.CONTEXT_IGNORE_SECURITY);
sMediaLibrary = libContext.getClassLoader()
.loadClass(UPDATE_CLASS)
- .getMethod(UPDATE_METHOD, Context.class, Context.class)
- .invoke(null, appContext, libContext);
+ .getMethod(UPDATE_METHOD, Resources.class, Resources.Theme.class)
+ .invoke(null, libContext.getResources(), libContext.getTheme());
return sMediaLibrary;
}
}
diff --git a/media/java/android/media/update/MediaController2Provider.java b/media/java/android/media/update/MediaControlView2Provider.java
index 71fbd084e643..83763b41bcaa 100644
--- a/media/java/android/media/update/MediaController2Provider.java
+++ b/media/java/android/media/update/MediaControlView2Provider.java
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2017 The Android Open Source Project
+ * Copyright 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.
@@ -19,7 +19,6 @@ package android.media.update;
import android.annotation.SystemApi;
import android.media.session.MediaController;
import android.view.View;
-import android.view.View.OnClickListener;
/**
* Interface for connecting the public API to an updatable implementation.
@@ -30,19 +29,17 @@ import android.view.View.OnClickListener;
*
* All methods behave as per their namesake in the public API.
*
- * @see android.widget.MediaController2
+ * @see android.widget.MediaControlView2
*
* @hide
*/
// TODO @SystemApi
-public interface MediaController2Provider extends ViewProvider {
+public interface MediaControlView2Provider extends ViewProvider {
void setController_impl(MediaController controller);
- void setAnchorView_impl(View view);
void show_impl();
void show_impl(int timeout);
boolean isShowing_impl();
void hide_impl();
- void setPrevNextListeners_impl(OnClickListener next, OnClickListener prev);
void showCCButton_impl();
boolean isPlaying_impl();
int getCurrentPosition_impl();
diff --git a/media/java/android/media/update/StaticProvider.java b/media/java/android/media/update/StaticProvider.java
index a1e2404ca78a..1a0df52413d2 100644
--- a/media/java/android/media/update/StaticProvider.java
+++ b/media/java/android/media/update/StaticProvider.java
@@ -16,8 +16,10 @@
package android.media.update;
+import android.annotation.Nullable;
import android.annotation.SystemApi;
-import android.widget.MediaController2;
+import android.util.AttributeSet;
+import android.widget.MediaControlView2;
import android.widget.VideoView2;
/**
@@ -30,7 +32,9 @@ import android.widget.VideoView2;
*/
// TODO @SystemApi
public interface StaticProvider {
- MediaController2Provider createMediaController2(
- MediaController2 instance, ViewProvider superProvider);
- VideoView2Provider createVideoView2(VideoView2 instance, ViewProvider superProvider);
+ MediaControlView2Provider createMediaControlView2(
+ MediaControlView2 instance, ViewProvider superProvider);
+ VideoView2Provider createVideoView2(
+ VideoView2 instance, ViewProvider superProvider,
+ @Nullable AttributeSet attrs, int defStyleAttr, int defStyleRes);
}
diff --git a/media/java/android/media/update/VideoView2Provider.java b/media/java/android/media/update/VideoView2Provider.java
index 6fc9bdc64e02..b7a24e59ab3e 100644
--- a/media/java/android/media/update/VideoView2Provider.java
+++ b/media/java/android/media/update/VideoView2Provider.java
@@ -17,9 +17,8 @@
package android.media.update;
import android.media.AudioAttributes;
-import android.media.MediaPlayer;
import android.net.Uri;
-import android.widget.MediaController2;
+import android.widget.MediaControlView2;
import android.widget.VideoView2;
import java.util.Map;
@@ -39,6 +38,8 @@ import java.util.Map;
*/
// TODO @SystemApi
public interface VideoView2Provider extends ViewProvider {
+ void setMediaControlView2_impl(MediaControlView2 mediaControlView);
+ MediaControlView2 getMediaControlView2_impl();
void start_impl();
void pause_impl();
int getDuration_impl();
@@ -49,18 +50,19 @@ public interface VideoView2Provider extends ViewProvider {
int getAudioSessionId_impl();
void showSubtitle_impl();
void hideSubtitle_impl();
+ void setSpeed_impl(float speed);
+ float getSpeed_impl();
void setAudioFocusRequest_impl(int focusGain);
void setAudioAttributes_impl(AudioAttributes attributes);
void setVideoPath_impl(String path);
void setVideoURI_impl(Uri uri);
void setVideoURI_impl(Uri uri, Map<String, String> headers);
- void setMediaController2_impl(MediaController2 controllerView);
void setViewType_impl(int viewType);
int getViewType_impl();
void stopPlayback_impl();
- void setOnPreparedListener_impl(MediaPlayer.OnPreparedListener l);
- void setOnCompletionListener_impl(MediaPlayer.OnCompletionListener l);
- void setOnErrorListener_impl(MediaPlayer.OnErrorListener l);
- void setOnInfoListener_impl(MediaPlayer.OnInfoListener l);
+ void setOnPreparedListener_impl(VideoView2.OnPreparedListener l);
+ void setOnCompletionListener_impl(VideoView2.OnCompletionListener l);
+ void setOnErrorListener_impl(VideoView2.OnErrorListener l);
+ void setOnInfoListener_impl(VideoView2.OnInfoListener l);
void setOnViewTypeChangedListener_impl(VideoView2.OnViewTypeChangedListener l);
}
diff --git a/media/java/android/media/update/ViewProvider.java b/media/java/android/media/update/ViewProvider.java
index bc8f20302d35..e54240433121 100644
--- a/media/java/android/media/update/ViewProvider.java
+++ b/media/java/android/media/update/ViewProvider.java
@@ -37,10 +37,6 @@ import android.view.MotionEvent;
// TODO @SystemApi
public interface ViewProvider {
// TODO Add more (all?) methods from View
- void onAttachedToWindow_impl();
- void onDetachedFromWindow_impl();
- void onLayout_impl(boolean changed, int left, int top, int right, int bottom);
- void draw_impl(Canvas canvas);
CharSequence getAccessibilityClassName_impl();
boolean onTouchEvent_impl(MotionEvent ev);
boolean onTrackballEvent_impl(MotionEvent ev);
diff --git a/native/graphics/jni/Android.bp b/native/graphics/jni/Android.bp
index 61164e068da6..0704e3545b62 100644
--- a/native/graphics/jni/Android.bp
+++ b/native/graphics/jni/Android.bp
@@ -29,6 +29,13 @@ cc_library_shared {
shared_libs: [
"libandroid_runtime",
],
+
+ arch: {
+ arm: {
+ // TODO: This is to work around b/24465209. Remove after root cause is fixed
+ ldflags: ["-Wl,--hash-style=both"],
+ },
+ },
}
// The headers module is in frameworks/native/Android.bp.
diff --git a/packages/ExtServices/AndroidManifest.xml b/packages/ExtServices/AndroidManifest.xml
index 63d3623c468a..45e557c00333 100644
--- a/packages/ExtServices/AndroidManifest.xml
+++ b/packages/ExtServices/AndroidManifest.xml
@@ -56,6 +56,12 @@
<intent-filter>
<action android:name="android.service.autofill.AutofillFieldClassificationService" />
</intent-filter>
+ <meta-data
+ android:name="android.autofill.field_classification.default_algorithm"
+ android:resource="@string/autofill_field_classification_default_algorithm" />
+ <meta-data
+ android:name="android.autofill.field_classification.available_algorithms"
+ android:resource="@array/autofill_field_classification_available_algorithms" />
</service>
<library android:name="android.ext.services"/>
diff --git a/packages/ExtServices/res/values/strings.xml b/packages/ExtServices/res/values/strings.xml
index a2e65bc8f9fd..72647ab8ae3f 100644
--- a/packages/ExtServices/res/values/strings.xml
+++ b/packages/ExtServices/res/values/strings.xml
@@ -19,4 +19,9 @@
<string name="notification_assistant">Notification Assistant</string>
<string name="prompt_block_reason">Too many dismissals:views</string>
+
+ <string name="autofill_field_classification_default_algorithm">EDIT_DISTANCE</string>
+ <string-array name="autofill_field_classification_available_algorithms">
+ <item>EDIT_DISTANCE</item>
+ </string-array>
</resources>
diff --git a/packages/ExtServices/src/android/ext/services/autofill/AutofillFieldClassificationServiceImpl.java b/packages/ExtServices/src/android/ext/services/autofill/AutofillFieldClassificationServiceImpl.java
index ea516a1db8b8..4709d35018c2 100644
--- a/packages/ExtServices/src/android/ext/services/autofill/AutofillFieldClassificationServiceImpl.java
+++ b/packages/ExtServices/src/android/ext/services/autofill/AutofillFieldClassificationServiceImpl.java
@@ -24,28 +24,17 @@ import android.view.autofill.AutofillValue;
import com.android.internal.util.ArrayUtils;
-import java.util.Arrays;
import java.util.List;
public class AutofillFieldClassificationServiceImpl extends AutofillFieldClassificationService {
private static final String TAG = "AutofillFieldClassificationServiceImpl";
- private static final boolean DEBUG = false;
- private static final List<String> sAvailableAlgorithms = Arrays.asList(EditDistanceScorer.NAME);
-
- @Override
- public List<String> onGetAvailableAlgorithms() {
- return sAvailableAlgorithms;
- }
-
- @Override
- public String onGetDefaultAlgorithm() {
- return EditDistanceScorer.NAME;
- }
+ // TODO(b/70291841): set to false before launching
+ private static final boolean DEBUG = true;
@Nullable
@Override
- public Scores onGetScores(@Nullable String algorithmName,
+ public float[][] onGetScores(@Nullable String algorithmName,
@Nullable Bundle algorithmArgs, @NonNull List<AutofillValue> actualValues,
@NonNull List<String> userDataValues) {
if (ArrayUtils.isEmpty(actualValues) || ArrayUtils.isEmpty(userDataValues)) {
@@ -66,14 +55,13 @@ public class AutofillFieldClassificationServiceImpl extends AutofillFieldClassif
Log.d(TAG, "getScores() will return a " + actualValuesSize + "x"
+ userDataValuesSize + " matrix for " + actualAlgorithmName);
}
- final Scores scores = new Scores(actualAlgorithmName, actualValuesSize, userDataValuesSize);
- final float[][] scoresMatrix = scores.getScores();
+ final float[][] scores = new float[actualValuesSize][userDataValuesSize];
final EditDistanceScorer algorithm = EditDistanceScorer.getInstance();
for (int i = 0; i < actualValuesSize; i++) {
for (int j = 0; j < userDataValuesSize; j++) {
final float score = algorithm.getScore(actualValues.get(i), userDataValues.get(j));
- scoresMatrix[i][j] = score;
+ scores[i][j] = score;
}
}
return scores;
diff --git a/packages/SettingsLib/src/com/android/settingslib/core/instrumentation/EventLogWriter.java b/packages/SettingsLib/src/com/android/settingslib/core/instrumentation/EventLogWriter.java
new file mode 100644
index 000000000000..72273046ef29
--- /dev/null
+++ b/packages/SettingsLib/src/com/android/settingslib/core/instrumentation/EventLogWriter.java
@@ -0,0 +1,110 @@
+/*
+ * 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 com.android.settingslib.core.instrumentation;
+
+import android.content.Context;
+import android.metrics.LogMaker;
+import android.util.Log;
+import android.util.Pair;
+
+import com.android.internal.logging.MetricsLogger;
+import com.android.internal.logging.nano.MetricsProto;
+
+/**
+ * {@link LogWriter} that writes data to eventlog.
+ */
+public class EventLogWriter implements LogWriter {
+
+ private final MetricsLogger mMetricsLogger = new MetricsLogger();
+
+ public void visible(Context context, int source, int category) {
+ final LogMaker logMaker = new LogMaker(category)
+ .setType(MetricsProto.MetricsEvent.TYPE_OPEN)
+ .addTaggedData(MetricsProto.MetricsEvent.FIELD_CONTEXT, source);
+ MetricsLogger.action(logMaker);
+ }
+
+ public void hidden(Context context, int category) {
+ MetricsLogger.hidden(context, category);
+ }
+
+ public void action(int category, int value, Pair<Integer, Object>... taggedData) {
+ if (taggedData == null || taggedData.length == 0) {
+ mMetricsLogger.action(category, value);
+ } else {
+ final LogMaker logMaker = new LogMaker(category)
+ .setType(MetricsProto.MetricsEvent.TYPE_ACTION)
+ .setSubtype(value);
+ for (Pair<Integer, Object> pair : taggedData) {
+ logMaker.addTaggedData(pair.first, pair.second);
+ }
+ mMetricsLogger.write(logMaker);
+ }
+ }
+
+ public void action(int category, boolean value, Pair<Integer, Object>... taggedData) {
+ action(category, value ? 1 : 0, taggedData);
+ }
+
+ public void action(Context context, int category, Pair<Integer, Object>... taggedData) {
+ action(context, category, "", taggedData);
+ }
+
+ public void actionWithSource(Context context, int source, int category) {
+ final LogMaker logMaker = new LogMaker(category)
+ .setType(MetricsProto.MetricsEvent.TYPE_ACTION);
+ if (source != MetricsProto.MetricsEvent.VIEW_UNKNOWN) {
+ logMaker.addTaggedData(MetricsProto.MetricsEvent.FIELD_CONTEXT, source);
+ }
+ MetricsLogger.action(logMaker);
+ }
+
+ /** @deprecated use {@link #action(int, int, Pair[])} */
+ @Deprecated
+ public void action(Context context, int category, int value) {
+ MetricsLogger.action(context, category, value);
+ }
+
+ /** @deprecated use {@link #action(int, boolean, Pair[])} */
+ @Deprecated
+ public void action(Context context, int category, boolean value) {
+ MetricsLogger.action(context, category, value);
+ }
+
+ public void action(Context context, int category, String pkg,
+ Pair<Integer, Object>... taggedData) {
+ if (taggedData == null || taggedData.length == 0) {
+ MetricsLogger.action(context, category, pkg);
+ } else {
+ final LogMaker logMaker = new LogMaker(category)
+ .setType(MetricsProto.MetricsEvent.TYPE_ACTION)
+ .setPackageName(pkg);
+ for (Pair<Integer, Object> pair : taggedData) {
+ logMaker.addTaggedData(pair.first, pair.second);
+ }
+ MetricsLogger.action(logMaker);
+ }
+ }
+
+ public void count(Context context, String name, int value) {
+ MetricsLogger.count(context, name, value);
+ }
+
+ public void histogram(Context context, String name, int bucket) {
+ MetricsLogger.histogram(context, name, bucket);
+ }
+}
diff --git a/packages/SettingsLib/src/com/android/settingslib/core/instrumentation/Instrumentable.java b/packages/SettingsLib/src/com/android/settingslib/core/instrumentation/Instrumentable.java
new file mode 100644
index 000000000000..dbc61c26e82e
--- /dev/null
+++ b/packages/SettingsLib/src/com/android/settingslib/core/instrumentation/Instrumentable.java
@@ -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 com.android.settingslib.core.instrumentation;
+
+public interface Instrumentable {
+
+ int METRICS_CATEGORY_UNKNOWN = 0;
+
+ /**
+ * Instrumented name for a view as defined in
+ * {@link com.android.internal.logging.nano.MetricsProto.MetricsEvent}.
+ */
+ int getMetricsCategory();
+}
diff --git a/packages/SettingsLib/src/com/android/settingslib/core/instrumentation/LogWriter.java b/packages/SettingsLib/src/com/android/settingslib/core/instrumentation/LogWriter.java
new file mode 100644
index 000000000000..4b9f5727208d
--- /dev/null
+++ b/packages/SettingsLib/src/com/android/settingslib/core/instrumentation/LogWriter.java
@@ -0,0 +1,84 @@
+/*
+ * 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 com.android.settingslib.core.instrumentation;
+
+import android.content.Context;
+import android.util.Pair;
+
+/**
+ * Generic log writer interface.
+ */
+public interface LogWriter {
+
+ /**
+ * Logs a visibility event when view becomes visible.
+ */
+ void visible(Context context, int source, int category);
+
+ /**
+ * Logs a visibility event when view becomes hidden.
+ */
+ void hidden(Context context, int category);
+
+ /**
+ * Logs a user action.
+ */
+ void action(int category, int value, Pair<Integer, Object>... taggedData);
+
+ /**
+ * Logs a user action.
+ */
+ void action(int category, boolean value, Pair<Integer, Object>... taggedData);
+
+ /**
+ * Logs an user action.
+ */
+ void action(Context context, int category, Pair<Integer, Object>... taggedData);
+
+ /**
+ * Logs an user action.
+ */
+ void actionWithSource(Context context, int source, int category);
+
+ /**
+ * Logs an user action.
+ * @deprecated use {@link #action(int, int, Pair[])}
+ */
+ @Deprecated
+ void action(Context context, int category, int value);
+
+ /**
+ * Logs an user action.
+ * @deprecated use {@link #action(int, boolean, Pair[])}
+ */
+ @Deprecated
+ void action(Context context, int category, boolean value);
+
+ /**
+ * Logs an user action.
+ */
+ void action(Context context, int category, String pkg, Pair<Integer, Object>... taggedData);
+
+ /**
+ * Logs a count.
+ */
+ void count(Context context, String name, int value);
+
+ /**
+ * Logs a histogram event.
+ */
+ void histogram(Context context, String name, int bucket);
+}
diff --git a/packages/SettingsLib/src/com/android/settingslib/core/instrumentation/MetricsFeatureProvider.java b/packages/SettingsLib/src/com/android/settingslib/core/instrumentation/MetricsFeatureProvider.java
new file mode 100644
index 000000000000..1e5b378e931c
--- /dev/null
+++ b/packages/SettingsLib/src/com/android/settingslib/core/instrumentation/MetricsFeatureProvider.java
@@ -0,0 +1,159 @@
+/*
+ * 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 com.android.settingslib.core.instrumentation;
+
+import android.content.ComponentName;
+import android.content.Context;
+import android.content.Intent;
+import android.text.TextUtils;
+import android.util.Pair;
+
+import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * FeatureProvider for metrics.
+ */
+public class MetricsFeatureProvider {
+ private List<LogWriter> mLoggerWriters;
+
+ public MetricsFeatureProvider() {
+ mLoggerWriters = new ArrayList<>();
+ installLogWriters();
+ }
+
+ protected void installLogWriters() {
+ mLoggerWriters.add(new EventLogWriter());
+ }
+
+ public void visible(Context context, int source, int category) {
+ for (LogWriter writer : mLoggerWriters) {
+ writer.visible(context, source, category);
+ }
+ }
+
+ public void hidden(Context context, int category) {
+ for (LogWriter writer : mLoggerWriters) {
+ writer.hidden(context, category);
+ }
+ }
+
+ public void actionWithSource(Context context, int source, int category) {
+ for (LogWriter writer : mLoggerWriters) {
+ writer.actionWithSource(context, source, category);
+ }
+ }
+
+ /**
+ * Logs a user action. Includes the elapsed time since the containing
+ * fragment has been visible.
+ */
+ public void action(VisibilityLoggerMixin visibilityLogger, int category, int value) {
+ for (LogWriter writer : mLoggerWriters) {
+ writer.action(category, value,
+ sinceVisibleTaggedData(visibilityLogger.elapsedTimeSinceVisible()));
+ }
+ }
+
+ /**
+ * Logs a user action. Includes the elapsed time since the containing
+ * fragment has been visible.
+ */
+ public void action(VisibilityLoggerMixin visibilityLogger, int category, boolean value) {
+ for (LogWriter writer : mLoggerWriters) {
+ writer.action(category, value,
+ sinceVisibleTaggedData(visibilityLogger.elapsedTimeSinceVisible()));
+ }
+ }
+
+ public void action(Context context, int category, Pair<Integer, Object>... taggedData) {
+ for (LogWriter writer : mLoggerWriters) {
+ writer.action(context, category, taggedData);
+ }
+ }
+
+ /** @deprecated use {@link #action(VisibilityLoggerMixin, int, int)} */
+ @Deprecated
+ public void action(Context context, int category, int value) {
+ for (LogWriter writer : mLoggerWriters) {
+ writer.action(context, category, value);
+ }
+ }
+
+ /** @deprecated use {@link #action(VisibilityLoggerMixin, int, boolean)} */
+ @Deprecated
+ public void action(Context context, int category, boolean value) {
+ for (LogWriter writer : mLoggerWriters) {
+ writer.action(context, category, value);
+ }
+ }
+
+ public void action(Context context, int category, String pkg,
+ Pair<Integer, Object>... taggedData) {
+ for (LogWriter writer : mLoggerWriters) {
+ writer.action(context, category, pkg, taggedData);
+ }
+ }
+
+ public void count(Context context, String name, int value) {
+ for (LogWriter writer : mLoggerWriters) {
+ writer.count(context, name, value);
+ }
+ }
+
+ public void histogram(Context context, String name, int bucket) {
+ for (LogWriter writer : mLoggerWriters) {
+ writer.histogram(context, name, bucket);
+ }
+ }
+
+ public int getMetricsCategory(Object object) {
+ if (object == null || !(object instanceof Instrumentable)) {
+ return MetricsEvent.VIEW_UNKNOWN;
+ }
+ return ((Instrumentable) object).getMetricsCategory();
+ }
+
+ public void logDashboardStartIntent(Context context, Intent intent,
+ int sourceMetricsCategory) {
+ if (intent == null) {
+ return;
+ }
+ final ComponentName cn = intent.getComponent();
+ if (cn == null) {
+ final String action = intent.getAction();
+ if (TextUtils.isEmpty(action)) {
+ // Not loggable
+ return;
+ }
+ action(context, MetricsEvent.ACTION_SETTINGS_TILE_CLICK, action,
+ Pair.create(MetricsEvent.FIELD_CONTEXT, sourceMetricsCategory));
+ return;
+ } else if (TextUtils.equals(cn.getPackageName(), context.getPackageName())) {
+ // Going to a Setting internal page, skip click logging in favor of page's own
+ // visibility logging.
+ return;
+ }
+ action(context, MetricsEvent.ACTION_SETTINGS_TILE_CLICK, cn.flattenToString(),
+ Pair.create(MetricsEvent.FIELD_CONTEXT, sourceMetricsCategory));
+ }
+
+ private Pair<Integer, Object> sinceVisibleTaggedData(long timestamp) {
+ return Pair.create(MetricsEvent.NOTIFICATION_SINCE_VISIBLE_MILLIS, timestamp);
+ }
+}
diff --git a/packages/SettingsLib/src/com/android/settingslib/core/instrumentation/SharedPreferencesLogger.java b/packages/SettingsLib/src/com/android/settingslib/core/instrumentation/SharedPreferencesLogger.java
new file mode 100644
index 000000000000..facce4e0bcbb
--- /dev/null
+++ b/packages/SettingsLib/src/com/android/settingslib/core/instrumentation/SharedPreferencesLogger.java
@@ -0,0 +1,259 @@
+/*
+ * 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 com.android.settingslib.core.instrumentation;
+
+import android.annotation.Nullable;
+import android.content.ComponentName;
+import android.content.Context;
+import android.content.SharedPreferences;
+import android.content.pm.PackageManager;
+import android.os.AsyncTask;
+import android.support.annotation.VisibleForTesting;
+import android.text.TextUtils;
+import android.util.Log;
+import android.util.Pair;
+
+import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
+
+import java.util.Map;
+import java.util.Set;
+import java.util.concurrent.ConcurrentSkipListSet;
+
+public class SharedPreferencesLogger implements SharedPreferences {
+
+ private static final String LOG_TAG = "SharedPreferencesLogger";
+
+ private final String mTag;
+ private final Context mContext;
+ private final MetricsFeatureProvider mMetricsFeature;
+ private final Set<String> mPreferenceKeySet;
+
+ public SharedPreferencesLogger(Context context, String tag,
+ MetricsFeatureProvider metricsFeature) {
+ mContext = context;
+ mTag = tag;
+ mMetricsFeature = metricsFeature;
+ mPreferenceKeySet = new ConcurrentSkipListSet<>();
+ }
+
+ @Override
+ public Map<String, ?> getAll() {
+ return null;
+ }
+
+ @Override
+ public String getString(String key, @Nullable String defValue) {
+ return defValue;
+ }
+
+ @Override
+ public Set<String> getStringSet(String key, @Nullable Set<String> defValues) {
+ return defValues;
+ }
+
+ @Override
+ public int getInt(String key, int defValue) {
+ return defValue;
+ }
+
+ @Override
+ public long getLong(String key, long defValue) {
+ return defValue;
+ }
+
+ @Override
+ public float getFloat(String key, float defValue) {
+ return defValue;
+ }
+
+ @Override
+ public boolean getBoolean(String key, boolean defValue) {
+ return defValue;
+ }
+
+ @Override
+ public boolean contains(String key) {
+ return false;
+ }
+
+ @Override
+ public Editor edit() {
+ return new EditorLogger();
+ }
+
+ @Override
+ public void registerOnSharedPreferenceChangeListener(
+ OnSharedPreferenceChangeListener listener) {
+ }
+
+ @Override
+ public void unregisterOnSharedPreferenceChangeListener(
+ OnSharedPreferenceChangeListener listener) {
+ }
+
+ private void logValue(String key, Object value) {
+ logValue(key, value, false /* forceLog */);
+ }
+
+ private void logValue(String key, Object value, boolean forceLog) {
+ final String prefKey = buildPrefKey(mTag, key);
+ if (!forceLog && !mPreferenceKeySet.contains(prefKey)) {
+ // Pref key doesn't exist in set, this is initial display so we skip metrics but
+ // keeps track of this key.
+ mPreferenceKeySet.add(prefKey);
+ return;
+ }
+ // TODO: Remove count logging to save some resource.
+ mMetricsFeature.count(mContext, buildCountName(prefKey, value), 1);
+
+ final Pair<Integer, Object> valueData;
+ if (value instanceof Long) {
+ final Long longVal = (Long) value;
+ final int intVal;
+ if (longVal > Integer.MAX_VALUE) {
+ intVal = Integer.MAX_VALUE;
+ } else if (longVal < Integer.MIN_VALUE) {
+ intVal = Integer.MIN_VALUE;
+ } else {
+ intVal = longVal.intValue();
+ }
+ valueData = Pair.create(MetricsEvent.FIELD_SETTINGS_PREFERENCE_CHANGE_INT_VALUE,
+ intVal);
+ } else if (value instanceof Integer) {
+ valueData = Pair.create(MetricsEvent.FIELD_SETTINGS_PREFERENCE_CHANGE_INT_VALUE,
+ value);
+ } else if (value instanceof Boolean) {
+ valueData = Pair.create(MetricsEvent.FIELD_SETTINGS_PREFERENCE_CHANGE_INT_VALUE,
+ (Boolean) value ? 1 : 0);
+ } else if (value instanceof Float) {
+ valueData = Pair.create(MetricsEvent.FIELD_SETTINGS_PREFERENCE_CHANGE_FLOAT_VALUE,
+ value);
+ } else if (value instanceof String) {
+ Log.d(LOG_TAG, "Tried to log string preference " + prefKey + " = " + value);
+ valueData = null;
+ } else {
+ Log.w(LOG_TAG, "Tried to log unloggable object" + value);
+ valueData = null;
+ }
+ if (valueData != null) {
+ // Pref key exists in set, log it's change in metrics.
+ mMetricsFeature.action(mContext, MetricsEvent.ACTION_SETTINGS_PREFERENCE_CHANGE,
+ Pair.create(MetricsEvent.FIELD_SETTINGS_PREFERENCE_CHANGE_NAME, prefKey),
+ valueData);
+ }
+ }
+
+ @VisibleForTesting
+ void logPackageName(String key, String value) {
+ final String prefKey = mTag + "/" + key;
+ mMetricsFeature.action(mContext, MetricsEvent.ACTION_SETTINGS_PREFERENCE_CHANGE, value,
+ Pair.create(MetricsEvent.FIELD_SETTINGS_PREFERENCE_CHANGE_NAME, prefKey));
+ }
+
+ private void safeLogValue(String key, String value) {
+ new AsyncPackageCheck().executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR, key, value);
+ }
+
+ public static String buildCountName(String prefKey, Object value) {
+ return prefKey + "|" + value;
+ }
+
+ public static String buildPrefKey(String tag, String key) {
+ return tag + "/" + key;
+ }
+
+ private class AsyncPackageCheck extends AsyncTask<String, Void, Void> {
+ @Override
+ protected Void doInBackground(String... params) {
+ String key = params[0];
+ String value = params[1];
+ PackageManager pm = mContext.getPackageManager();
+ try {
+ // Check if this might be a component.
+ ComponentName name = ComponentName.unflattenFromString(value);
+ if (value != null) {
+ value = name.getPackageName();
+ }
+ } catch (Exception e) {
+ }
+ try {
+ pm.getPackageInfo(value, PackageManager.MATCH_ANY_USER);
+ logPackageName(key, value);
+ } catch (PackageManager.NameNotFoundException e) {
+ // Clearly not a package, and it's unlikely this preference is in prefSet, so
+ // lets force log it.
+ logValue(key, value, true /* forceLog */);
+ }
+ return null;
+ }
+ }
+
+ public class EditorLogger implements Editor {
+ @Override
+ public Editor putString(String key, @Nullable String value) {
+ safeLogValue(key, value);
+ return this;
+ }
+
+ @Override
+ public Editor putStringSet(String key, @Nullable Set<String> values) {
+ safeLogValue(key, TextUtils.join(",", values));
+ return this;
+ }
+
+ @Override
+ public Editor putInt(String key, int value) {
+ logValue(key, value);
+ return this;
+ }
+
+ @Override
+ public Editor putLong(String key, long value) {
+ logValue(key, value);
+ return this;
+ }
+
+ @Override
+ public Editor putFloat(String key, float value) {
+ logValue(key, value);
+ return this;
+ }
+
+ @Override
+ public Editor putBoolean(String key, boolean value) {
+ logValue(key, value);
+ return this;
+ }
+
+ @Override
+ public Editor remove(String key) {
+ return this;
+ }
+
+ @Override
+ public Editor clear() {
+ return this;
+ }
+
+ @Override
+ public boolean commit() {
+ return true;
+ }
+
+ @Override
+ public void apply() {
+ }
+ }
+}
diff --git a/packages/SettingsLib/src/com/android/settingslib/core/instrumentation/VisibilityLoggerMixin.java b/packages/SettingsLib/src/com/android/settingslib/core/instrumentation/VisibilityLoggerMixin.java
new file mode 100644
index 000000000000..79838962ef1e
--- /dev/null
+++ b/packages/SettingsLib/src/com/android/settingslib/core/instrumentation/VisibilityLoggerMixin.java
@@ -0,0 +1,96 @@
+/*
+ * 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 com.android.settingslib.core.instrumentation;
+
+import android.app.Activity;
+import android.content.Context;
+import android.content.Intent;
+
+import android.os.SystemClock;
+import com.android.internal.logging.nano.MetricsProto;
+import com.android.settingslib.core.lifecycle.LifecycleObserver;
+import com.android.settingslib.core.lifecycle.events.OnPause;
+import com.android.settingslib.core.lifecycle.events.OnResume;
+
+import static com.android.settingslib.core.instrumentation.Instrumentable.METRICS_CATEGORY_UNKNOWN;
+
+/**
+ * Logs visibility change of a fragment.
+ */
+public class VisibilityLoggerMixin implements LifecycleObserver, OnResume, OnPause {
+
+ private static final String TAG = "VisibilityLoggerMixin";
+
+ private final int mMetricsCategory;
+
+ private MetricsFeatureProvider mMetricsFeature;
+ private int mSourceMetricsCategory = MetricsProto.MetricsEvent.VIEW_UNKNOWN;
+ private long mVisibleTimestamp;
+
+ /**
+ * The metrics category constant for logging source when a setting fragment is opened.
+ */
+ public static final String EXTRA_SOURCE_METRICS_CATEGORY = ":settings:source_metrics";
+
+ private VisibilityLoggerMixin() {
+ mMetricsCategory = METRICS_CATEGORY_UNKNOWN;
+ }
+
+ public VisibilityLoggerMixin(int metricsCategory, MetricsFeatureProvider metricsFeature) {
+ mMetricsCategory = metricsCategory;
+ mMetricsFeature = metricsFeature;
+ }
+
+ @Override
+ public void onResume() {
+ mVisibleTimestamp = SystemClock.elapsedRealtime();
+ if (mMetricsFeature != null && mMetricsCategory != METRICS_CATEGORY_UNKNOWN) {
+ mMetricsFeature.visible(null /* context */, mSourceMetricsCategory, mMetricsCategory);
+ }
+ }
+
+ @Override
+ public void onPause() {
+ mVisibleTimestamp = 0;
+ if (mMetricsFeature != null && mMetricsCategory != METRICS_CATEGORY_UNKNOWN) {
+ mMetricsFeature.hidden(null /* context */, mMetricsCategory);
+ }
+ }
+
+ /**
+ * Sets source metrics category for this logger. Source is the caller that opened this UI.
+ */
+ public void setSourceMetricsCategory(Activity activity) {
+ if (mSourceMetricsCategory != MetricsProto.MetricsEvent.VIEW_UNKNOWN || activity == null) {
+ return;
+ }
+ final Intent intent = activity.getIntent();
+ if (intent == null) {
+ return;
+ }
+ mSourceMetricsCategory = intent.getIntExtra(EXTRA_SOURCE_METRICS_CATEGORY,
+ MetricsProto.MetricsEvent.VIEW_UNKNOWN);
+ }
+
+ /** Returns elapsed time since onResume() */
+ public long elapsedTimeSinceVisible() {
+ if (mVisibleTimestamp == 0) {
+ return 0;
+ }
+ return SystemClock.elapsedRealtime() - mVisibleTimestamp;
+ }
+}
diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/core/instrumentation/MetricsFeatureProviderTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/core/instrumentation/MetricsFeatureProviderTest.java
new file mode 100644
index 000000000000..8bea51d1696d
--- /dev/null
+++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/core/instrumentation/MetricsFeatureProviderTest.java
@@ -0,0 +1,132 @@
+/*
+ * 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 com.android.settingslib.core.instrumentation;
+
+import static com.google.common.truth.Truth.assertThat;
+import static org.mockito.Matchers.anyString;
+import static org.mockito.Matchers.eq;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.verifyNoMoreInteractions;
+import static org.mockito.Mockito.when;
+
+import android.content.ComponentName;
+import android.content.Context;
+import android.content.Intent;
+import android.util.Pair;
+
+import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
+import com.android.settingslib.TestConfig;
+import com.android.settingslib.SettingsLibRobolectricTestRunner;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.ArgumentCaptor;
+import org.mockito.Captor;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+import org.robolectric.RuntimeEnvironment;
+import org.robolectric.annotation.Config;
+import org.robolectric.util.ReflectionHelpers;
+
+import java.util.ArrayList;
+import java.util.List;
+
+@RunWith(SettingsLibRobolectricTestRunner.class)
+@Config(manifest = TestConfig.MANIFEST_PATH, sdk = TestConfig.SDK_VERSION)
+public class MetricsFeatureProviderTest {
+ private static int CATEGORY = 10;
+ private static boolean SUBTYPE_BOOLEAN = true;
+ private static int SUBTYPE_INTEGER = 1;
+ private static long ELAPSED_TIME = 1000;
+
+ @Mock private LogWriter mockLogWriter;
+ @Mock private VisibilityLoggerMixin mockVisibilityLogger;
+
+ private Context mContext;
+ private MetricsFeatureProvider mProvider;
+
+ @Captor
+ private ArgumentCaptor<Pair> mPairCaptor;
+
+ @Before
+ public void setUp() {
+ MockitoAnnotations.initMocks(this);
+ mContext = RuntimeEnvironment.application;
+ mProvider = new MetricsFeatureProvider();
+ List<LogWriter> writers = new ArrayList<>();
+ writers.add(mockLogWriter);
+ ReflectionHelpers.setField(mProvider, "mLoggerWriters", writers);
+
+ when(mockVisibilityLogger.elapsedTimeSinceVisible()).thenReturn(ELAPSED_TIME);
+ }
+
+ @Test
+ public void logDashboardStartIntent_intentEmpty_shouldNotLog() {
+ mProvider.logDashboardStartIntent(mContext, null /* intent */,
+ MetricsEvent.SETTINGS_GESTURES);
+
+ verifyNoMoreInteractions(mockLogWriter);
+ }
+
+ @Test
+ public void logDashboardStartIntent_intentHasNoComponent_shouldLog() {
+ final Intent intent = new Intent(Intent.ACTION_ASSIST);
+
+ mProvider.logDashboardStartIntent(mContext, intent, MetricsEvent.SETTINGS_GESTURES);
+
+ verify(mockLogWriter).action(
+ eq(mContext),
+ eq(MetricsEvent.ACTION_SETTINGS_TILE_CLICK),
+ anyString(),
+ eq(Pair.create(MetricsEvent.FIELD_CONTEXT, MetricsEvent.SETTINGS_GESTURES)));
+ }
+
+ @Test
+ public void logDashboardStartIntent_intentIsExternal_shouldLog() {
+ final Intent intent = new Intent().setComponent(new ComponentName("pkg", "cls"));
+
+ mProvider.logDashboardStartIntent(mContext, intent, MetricsEvent.SETTINGS_GESTURES);
+
+ verify(mockLogWriter).action(
+ eq(mContext),
+ eq(MetricsEvent.ACTION_SETTINGS_TILE_CLICK),
+ anyString(),
+ eq(Pair.create(MetricsEvent.FIELD_CONTEXT, MetricsEvent.SETTINGS_GESTURES)));
+ }
+
+ @Test
+ public void action_BooleanLogsElapsedTime() {
+ mProvider.action(mockVisibilityLogger, CATEGORY, SUBTYPE_BOOLEAN);
+ verify(mockLogWriter).action(eq(CATEGORY), eq(SUBTYPE_BOOLEAN), mPairCaptor.capture());
+
+ Pair value = mPairCaptor.getValue();
+ assertThat(value.first instanceof Integer).isTrue();
+ assertThat((int) value.first).isEqualTo(MetricsEvent.NOTIFICATION_SINCE_VISIBLE_MILLIS);
+ assertThat(value.second).isEqualTo(ELAPSED_TIME);
+ }
+
+ @Test
+ public void action_IntegerLogsElapsedTime() {
+ mProvider.action(mockVisibilityLogger, CATEGORY, SUBTYPE_INTEGER);
+ verify(mockLogWriter).action(eq(CATEGORY), eq(SUBTYPE_INTEGER), mPairCaptor.capture());
+
+ Pair value = mPairCaptor.getValue();
+ assertThat(value.first instanceof Integer).isTrue();
+ assertThat((int) value.first).isEqualTo(MetricsEvent.NOTIFICATION_SINCE_VISIBLE_MILLIS);
+ assertThat(value.second).isEqualTo(ELAPSED_TIME);
+ }
+}
diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/core/instrumentation/SharedPreferenceLoggerTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/core/instrumentation/SharedPreferenceLoggerTest.java
new file mode 100644
index 000000000000..d558a645aeb7
--- /dev/null
+++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/core/instrumentation/SharedPreferenceLoggerTest.java
@@ -0,0 +1,181 @@
+/*
+ * 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 com.android.settingslib.core.instrumentation;
+
+import static com.android.internal.logging.nano.MetricsProto.MetricsEvent.ACTION_SETTINGS_PREFERENCE_CHANGE;
+import static com.android.internal.logging.nano.MetricsProto.MetricsEvent.FIELD_SETTINGS_PREFERENCE_CHANGE_FLOAT_VALUE;
+import static com.android.internal.logging.nano.MetricsProto.MetricsEvent.FIELD_SETTINGS_PREFERENCE_CHANGE_INT_VALUE;
+import static com.android.internal.logging.nano.MetricsProto.MetricsEvent.FIELD_SETTINGS_PREFERENCE_CHANGE_NAME;
+import static org.mockito.Matchers.any;
+import static org.mockito.Matchers.anyInt;
+import static org.mockito.Matchers.argThat;
+import static org.mockito.Matchers.eq;
+import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.verify;
+
+import android.content.Context;
+import android.content.SharedPreferences;
+import android.util.Pair;
+
+import com.android.settingslib.TestConfig;
+import com.android.settingslib.SettingsLibRobolectricTestRunner;
+
+import com.google.common.truth.Platform;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Answers;
+import org.mockito.ArgumentMatcher;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+import org.robolectric.annotation.Config;
+
+@RunWith(SettingsLibRobolectricTestRunner.class)
+@Config(manifest = TestConfig.MANIFEST_PATH, sdk = TestConfig.SDK_VERSION)
+public class SharedPreferenceLoggerTest {
+
+ private static final String TEST_TAG = "tag";
+ private static final String TEST_KEY = "key";
+
+ @Mock(answer = Answers.RETURNS_DEEP_STUBS)
+ private Context mContext;
+
+ private ArgumentMatcher<Pair<Integer, Object>> mNamePairMatcher;
+ @Mock
+ private MetricsFeatureProvider mMetricsFeature;
+ private SharedPreferencesLogger mSharedPrefLogger;
+
+ @Before
+ public void init() {
+ MockitoAnnotations.initMocks(this);
+ mSharedPrefLogger = new SharedPreferencesLogger(mContext, TEST_TAG, mMetricsFeature);
+ mNamePairMatcher = pairMatches(FIELD_SETTINGS_PREFERENCE_CHANGE_NAME, String.class);
+ }
+
+ @Test
+ public void putInt_shouldNotLogInitialPut() {
+ final SharedPreferences.Editor editor = mSharedPrefLogger.edit();
+ editor.putInt(TEST_KEY, 1);
+ editor.putInt(TEST_KEY, 1);
+ editor.putInt(TEST_KEY, 1);
+ editor.putInt(TEST_KEY, 2);
+ editor.putInt(TEST_KEY, 2);
+ editor.putInt(TEST_KEY, 2);
+ editor.putInt(TEST_KEY, 2);
+
+ verify(mMetricsFeature, times(6)).action(any(Context.class), anyInt(),
+ argThat(mNamePairMatcher),
+ argThat(pairMatches(FIELD_SETTINGS_PREFERENCE_CHANGE_INT_VALUE, Integer.class)));
+ }
+
+ @Test
+ public void putBoolean_shouldNotLogInitialPut() {
+ final SharedPreferences.Editor editor = mSharedPrefLogger.edit();
+ editor.putBoolean(TEST_KEY, true);
+ editor.putBoolean(TEST_KEY, true);
+ editor.putBoolean(TEST_KEY, false);
+ editor.putBoolean(TEST_KEY, false);
+ editor.putBoolean(TEST_KEY, false);
+
+
+ verify(mMetricsFeature).action(any(Context.class), anyInt(),
+ argThat(mNamePairMatcher),
+ argThat(pairMatches(FIELD_SETTINGS_PREFERENCE_CHANGE_INT_VALUE, true)));
+ verify(mMetricsFeature, times(3)).action(any(Context.class), anyInt(),
+ argThat(mNamePairMatcher),
+ argThat(pairMatches(FIELD_SETTINGS_PREFERENCE_CHANGE_INT_VALUE, false)));
+ }
+
+ @Test
+ public void putLong_shouldNotLogInitialPut() {
+ final SharedPreferences.Editor editor = mSharedPrefLogger.edit();
+ editor.putLong(TEST_KEY, 1);
+ editor.putLong(TEST_KEY, 1);
+ editor.putLong(TEST_KEY, 1);
+ editor.putLong(TEST_KEY, 1);
+ editor.putLong(TEST_KEY, 2);
+
+ verify(mMetricsFeature, times(4)).action(any(Context.class), anyInt(),
+ argThat(mNamePairMatcher),
+ argThat(pairMatches(FIELD_SETTINGS_PREFERENCE_CHANGE_INT_VALUE, Integer.class)));
+ }
+
+ @Test
+ public void putLong_biggerThanIntMax_shouldLogIntMax() {
+ final SharedPreferences.Editor editor = mSharedPrefLogger.edit();
+ final long veryBigNumber = 500L + Integer.MAX_VALUE;
+ editor.putLong(TEST_KEY, 1);
+ editor.putLong(TEST_KEY, veryBigNumber);
+
+ verify(mMetricsFeature).action(any(Context.class), anyInt(),
+ argThat(mNamePairMatcher),
+ argThat(pairMatches(
+ FIELD_SETTINGS_PREFERENCE_CHANGE_INT_VALUE, Integer.MAX_VALUE)));
+ }
+
+ @Test
+ public void putLong_smallerThanIntMin_shouldLogIntMin() {
+ final SharedPreferences.Editor editor = mSharedPrefLogger.edit();
+ final long veryNegativeNumber = -500L + Integer.MIN_VALUE;
+ editor.putLong(TEST_KEY, 1);
+ editor.putLong(TEST_KEY, veryNegativeNumber);
+
+ verify(mMetricsFeature).action(any(Context.class), anyInt(),
+ argThat(mNamePairMatcher),
+ argThat(pairMatches(
+ FIELD_SETTINGS_PREFERENCE_CHANGE_INT_VALUE, Integer.MIN_VALUE)));
+ }
+
+ @Test
+ public void putFloat_shouldNotLogInitialPut() {
+ final SharedPreferences.Editor editor = mSharedPrefLogger.edit();
+ editor.putFloat(TEST_KEY, 1);
+ editor.putFloat(TEST_KEY, 1);
+ editor.putFloat(TEST_KEY, 1);
+ editor.putFloat(TEST_KEY, 1);
+ editor.putFloat(TEST_KEY, 2);
+
+ verify(mMetricsFeature, times(4)).action(any(Context.class), anyInt(),
+ argThat(mNamePairMatcher),
+ argThat(pairMatches(FIELD_SETTINGS_PREFERENCE_CHANGE_FLOAT_VALUE, Float.class)));
+ }
+
+ @Test
+ public void logPackage_shouldUseLogPackageApi() {
+ mSharedPrefLogger.logPackageName("key", "com.android.settings");
+ verify(mMetricsFeature).action(any(Context.class),
+ eq(ACTION_SETTINGS_PREFERENCE_CHANGE),
+ eq("com.android.settings"),
+ any(Pair.class));
+ }
+
+ private ArgumentMatcher<Pair<Integer, Object>> pairMatches(int tag, Class clazz) {
+ return pair -> pair.first == tag && Platform.isInstanceOfType(pair.second, clazz);
+ }
+
+ private ArgumentMatcher<Pair<Integer, Object>> pairMatches(int tag, boolean bool) {
+ return pair -> pair.first == tag
+ && Platform.isInstanceOfType(pair.second, Integer.class)
+ && pair.second.equals((bool ? 1 : 0));
+ }
+
+ private ArgumentMatcher<Pair<Integer, Object>> pairMatches(int tag, int val) {
+ return pair -> pair.first == tag
+ && Platform.isInstanceOfType(pair.second, Integer.class)
+ && pair.second.equals(val);
+ }
+}
diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/core/instrumentation/VisibilityLoggerMixinTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/core/instrumentation/VisibilityLoggerMixinTest.java
new file mode 100644
index 000000000000..a2648861d1d8
--- /dev/null
+++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/core/instrumentation/VisibilityLoggerMixinTest.java
@@ -0,0 +1,122 @@
+/*
+ * 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 com.android.settingslib.core.instrumentation;
+
+import static com.android.settingslib.core.instrumentation.Instrumentable.METRICS_CATEGORY_UNKNOWN;
+
+import static org.mockito.ArgumentMatchers.nullable;
+import static org.mockito.Matchers.anyInt;
+import static org.mockito.Matchers.eq;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+import android.app.Activity;
+import android.content.Context;
+import android.content.Intent;
+
+import com.android.internal.logging.nano.MetricsProto;
+import com.android.settingslib.SettingsLibRobolectricTestRunner;
+import com.android.settingslib.TestConfig;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+import org.robolectric.annotation.Config;
+
+
+@RunWith(SettingsLibRobolectricTestRunner.class)
+@Config(manifest = TestConfig.MANIFEST_PATH, sdk = TestConfig.SDK_VERSION)
+public class VisibilityLoggerMixinTest {
+
+ @Mock
+ private MetricsFeatureProvider mMetricsFeature;
+
+ private VisibilityLoggerMixin mMixin;
+
+ @Before
+ public void init() {
+ MockitoAnnotations.initMocks(this);
+ mMixin = new VisibilityLoggerMixin(TestInstrumentable.TEST_METRIC, mMetricsFeature);
+ }
+
+ @Test
+ public void shouldLogVisibleOnResume() {
+ mMixin.onResume();
+
+ verify(mMetricsFeature, times(1))
+ .visible(nullable(Context.class), eq(MetricsProto.MetricsEvent.VIEW_UNKNOWN),
+ eq(TestInstrumentable.TEST_METRIC));
+ }
+
+ @Test
+ public void shouldLogVisibleWithSource() {
+ final Intent sourceIntent = new Intent()
+ .putExtra(VisibilityLoggerMixin.EXTRA_SOURCE_METRICS_CATEGORY,
+ MetricsProto.MetricsEvent.SETTINGS_GESTURES);
+ final Activity activity = mock(Activity.class);
+ when(activity.getIntent()).thenReturn(sourceIntent);
+ mMixin.setSourceMetricsCategory(activity);
+ mMixin.onResume();
+
+ verify(mMetricsFeature, times(1))
+ .visible(nullable(Context.class), eq(MetricsProto.MetricsEvent.SETTINGS_GESTURES),
+ eq(TestInstrumentable.TEST_METRIC));
+ }
+
+ @Test
+ public void shouldLogHideOnPause() {
+ mMixin.onPause();
+
+ verify(mMetricsFeature, times(1))
+ .hidden(nullable(Context.class), eq(TestInstrumentable.TEST_METRIC));
+ }
+
+ @Test
+ public void shouldNotLogIfMetricsFeatureIsNull() {
+ mMixin = new VisibilityLoggerMixin(TestInstrumentable.TEST_METRIC, null);
+ mMixin.onResume();
+ mMixin.onPause();
+
+ verify(mMetricsFeature, never())
+ .hidden(nullable(Context.class), anyInt());
+ }
+
+ @Test
+ public void shouldNotLogIfMetricsCategoryIsUnknown() {
+ mMixin = new VisibilityLoggerMixin(METRICS_CATEGORY_UNKNOWN, mMetricsFeature);
+
+ mMixin.onResume();
+ mMixin.onPause();
+
+ verify(mMetricsFeature, never())
+ .hidden(nullable(Context.class), anyInt());
+ }
+
+ private final class TestInstrumentable implements Instrumentable {
+
+ public static final int TEST_METRIC = 12345;
+
+ @Override
+ public int getMetricsCategory() {
+ return TEST_METRIC;
+ }
+ }
+}
diff --git a/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java
index 175cff6b61b2..2a697b8d5034 100644
--- a/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java
+++ b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java
@@ -60,6 +60,7 @@ import android.os.UserHandle;
import android.os.UserManager;
import android.os.UserManagerInternal;
import android.provider.Settings;
+import android.provider.SettingsValidators;
import android.provider.Settings.Global;
import android.provider.Settings.Secure;
import android.text.TextUtils;
@@ -297,6 +298,12 @@ public class SettingsProvider extends ContentProvider {
@Override
public boolean onCreate() {
Settings.setInSystemServer();
+
+ // fail to boot if there're any backed up settings that don't have a non-null validator
+ ensureAllBackedUpSystemSettingsHaveValidators();
+ ensureAllBackedUpGlobalSettingsHaveValidators();
+ ensureAllBackedUpSecureSettingsHaveValidators();
+
synchronized (mLock) {
mUserManager = UserManager.get(getContext());
mPackageManager = AppGlobals.getPackageManager();
@@ -314,6 +321,57 @@ public class SettingsProvider extends ContentProvider {
return true;
}
+ private void ensureAllBackedUpSystemSettingsHaveValidators() {
+ String offenders = getOffenders(concat(Settings.System.SETTINGS_TO_BACKUP,
+ Settings.System.LEGACY_RESTORE_SETTINGS), Settings.System.VALIDATORS);
+
+ failToBootIfOffendersPresent(offenders, "Settings.System");
+ }
+
+ private void ensureAllBackedUpGlobalSettingsHaveValidators() {
+ String offenders = getOffenders(concat(Settings.Global.SETTINGS_TO_BACKUP,
+ Settings.Global.LEGACY_RESTORE_SETTINGS), Settings.Global.VALIDATORS);
+
+ failToBootIfOffendersPresent(offenders, "Settings.Global");
+ }
+
+ private void ensureAllBackedUpSecureSettingsHaveValidators() {
+ String offenders = getOffenders(concat(Settings.Secure.SETTINGS_TO_BACKUP,
+ Settings.Secure.LEGACY_RESTORE_SETTINGS), Settings.Secure.VALIDATORS);
+
+ failToBootIfOffendersPresent(offenders, "Settings.Secure");
+ }
+
+ private void failToBootIfOffendersPresent(String offenders, String settingsType) {
+ if (offenders.length() > 0) {
+ throw new RuntimeException("All " + settingsType + " settings that are backed up"
+ + " have to have a non-null validator, but those don't: " + offenders);
+ }
+ }
+
+ private String getOffenders(String[] settingsToBackup, Map<String,
+ SettingsValidators.Validator> validators) {
+ StringBuilder offenders = new StringBuilder();
+ for (String setting : settingsToBackup) {
+ if (validators.get(setting) == null) {
+ offenders.append(setting).append(" ");
+ }
+ }
+ return offenders.toString();
+ }
+
+ private final String[] concat(String[] first, String[] second) {
+ if (second == null || second.length == 0) {
+ return first;
+ }
+ final int firstLen = first.length;
+ final int secondLen = second.length;
+ String[] both = new String[firstLen + secondLen];
+ System.arraycopy(first, 0, both, 0, firstLen);
+ System.arraycopy(second, 0, both, firstLen, secondLen);
+ return both;
+ }
+
@Override
public Bundle call(String method, String name, Bundle args) {
final int requestingUserId = getRequestingUserId(args);
@@ -1472,7 +1530,7 @@ public class SettingsProvider extends ContentProvider {
}
private void validateSystemSettingValue(String name, String value) {
- Settings.System.Validator validator = Settings.System.VALIDATORS.get(name);
+ SettingsValidators.Validator validator = Settings.System.VALIDATORS.get(name);
if (validator != null && !validator.validate(value)) {
throw new IllegalArgumentException("Invalid value: " + value
+ " for setting: " + name);
diff --git a/packages/Shell/AndroidManifest.xml b/packages/Shell/AndroidManifest.xml
index 0f43db052622..2a6d55c28ec4 100644
--- a/packages/Shell/AndroidManifest.xml
+++ b/packages/Shell/AndroidManifest.xml
@@ -135,6 +135,9 @@
<uses-permission android:name="android.permission.RESTRICTED_VR_ACCESS" />
<uses-permission android:name="android.permission.MANAGE_BIND_INSTANT_SERVICE" />
<uses-permission android:name="android.permission.SET_HARMFUL_APP_WARNINGS" />
+ <uses-permission android:name="android.permission.MANAGE_SENSORS" />
+
+ <uses-permission android:name="android.permission.MANAGE_AUDIO_POLICY" />
<application android:label="@string/app_label"
android:defaultToDeviceProtectedStorage="true"
diff --git a/packages/SystemUI/res-keyguard/layout/keyguard_pin_view.xml b/packages/SystemUI/res-keyguard/layout/keyguard_pin_view.xml
index 631cc0d3df30..41dd0b36d160 100644
--- a/packages/SystemUI/res-keyguard/layout/keyguard_pin_view.xml
+++ b/packages/SystemUI/res-keyguard/layout/keyguard_pin_view.xml
@@ -67,7 +67,7 @@
android:paddingTop="8dip"
android:paddingBottom="8dip"
android:paddingRight="0dp"
- android:paddingLeft="24dp"
+ android:paddingLeft="0dp"
android:background="@drawable/ripple_drawable"
android:contentDescription="@string/keyboardview_keycode_delete"
android:layout_alignEnd="@+id/pinEntry"
diff --git a/packages/SystemUI/res-keyguard/layout/keyguard_sim_pin_view.xml b/packages/SystemUI/res-keyguard/layout/keyguard_sim_pin_view.xml
index 947f27deb84e..33f7e750c390 100644
--- a/packages/SystemUI/res-keyguard/layout/keyguard_sim_pin_view.xml
+++ b/packages/SystemUI/res-keyguard/layout/keyguard_sim_pin_view.xml
@@ -81,7 +81,7 @@
android:paddingTop="8dip"
android:paddingBottom="8dip"
android:paddingRight="0dp"
- android:paddingLeft="24dp"
+ android:paddingLeft="0dp"
android:background="@drawable/ripple_drawable"
android:contentDescription="@string/keyboardview_keycode_delete"
android:layout_alignEnd="@+id/pinEntry"
diff --git a/packages/SystemUI/res-keyguard/layout/keyguard_sim_puk_view.xml b/packages/SystemUI/res-keyguard/layout/keyguard_sim_puk_view.xml
index 6f270b405c11..4b385fc3d6e1 100644
--- a/packages/SystemUI/res-keyguard/layout/keyguard_sim_puk_view.xml
+++ b/packages/SystemUI/res-keyguard/layout/keyguard_sim_puk_view.xml
@@ -82,7 +82,7 @@
android:paddingTop="8dip"
android:paddingBottom="8dip"
android:paddingRight="0dp"
- android:paddingLeft="24dp"
+ android:paddingLeft="0dp"
android:background="@drawable/ripple_drawable"
android:contentDescription="@string/keyboardview_keycode_delete"
android:layout_alignEnd="@+id/pinEntry"
diff --git a/packages/SystemUI/res/layout/volume_dialog.xml b/packages/SystemUI/res/layout/volume_dialog.xml
index 748c9a5ec7ed..5108f58dc832 100644
--- a/packages/SystemUI/res/layout/volume_dialog.xml
+++ b/packages/SystemUI/res/layout/volume_dialog.xml
@@ -34,7 +34,7 @@
<LinearLayout
android:id="@+id/volume_dialog_rows"
- android:layout_width="@dimen/volume_dialog_panel_width"
+ android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:clipChildren="false"
android:clipToPadding="false"
@@ -56,6 +56,7 @@
android:layout_below="@id/volume_dialog_rows"
android:background="@drawable/rounded_bg_full"
android:gravity="center"
+ android:layout_gravity="end"
android:orientation="vertical" >
<TextView
diff --git a/packages/SystemUI/res/values-af/strings.xml b/packages/SystemUI/res/values-af/strings.xml
index fb756e308e19..8b2ab81c7fe8 100644
--- a/packages/SystemUI/res/values-af/strings.xml
+++ b/packages/SystemUI/res/values-af/strings.xml
@@ -33,7 +33,10 @@
<string name="status_bar_ongoing_events_title" msgid="1682504513316879202">"Voortdurend"</string>
<string name="status_bar_latest_events_title" msgid="6594767438577593172">"Kennisgewings"</string>
<string name="battery_low_title" msgid="6456385927409742437">"Battery is amper pap"</string>
+ <string name="battery_low_title_hybrid" msgid="6268991275887381595">"Battery is amper pap. Skakel Batterybespaarder aan"</string>
<string name="battery_low_percent_format" msgid="2900940511201380775">"<xliff:g id="PERCENTAGE">%s</xliff:g> oor"</string>
+ <string name="battery_low_percent_format_hybrid" msgid="6838677459286775617">"<xliff:g id="PERCENTAGE">%s</xliff:g> oor; ongeveer <xliff:g id="TIME">%s</xliff:g> oor op grond van jou gebruik"</string>
+ <string name="battery_low_percent_format_hybrid_short" msgid="9025795469949145586">"<xliff:g id="PERCENTAGE">%s</xliff:g> oor; ongeveer <xliff:g id="TIME">%s</xliff:g> oor"</string>
<string name="battery_low_percent_format_saver_started" msgid="7879389868952879166">"<xliff:g id="PERCENTAGE">%s</xliff:g> oor. Batterybespaarder is aan."</string>
<string name="invalid_charger" msgid="4549105996740522523">"USB-laaiery nie ondersteun nie.\nGebruik net die laaier wat verskaf is."</string>
<string name="invalid_charger_title" msgid="3515740382572798460">"Laai met USB word nie gesteun nie."</string>
@@ -67,14 +70,15 @@
<string name="usb_debugging_secondary_user_message" msgid="6067122453571699801">"Die gebruiker wat tans by hierdie toestel aangemeld is, kan nie USB-ontfouting aanskakel nie. Skakel na die primêre gebruiker toe oor om hierdie kenmerk te gebruik."</string>
<string name="compat_mode_on" msgid="6623839244840638213">"Zoem om skerm te vul"</string>
<string name="compat_mode_off" msgid="4434467572461327898">"Strek om skerm te vul"</string>
+ <string name="global_action_screenshot" msgid="8329831278085426283">"Skermkiekie"</string>
<string name="screenshot_saving_ticker" msgid="7403652894056693515">"Stoor tans skermkiekie..."</string>
<string name="screenshot_saving_title" msgid="8242282144535555697">"Stoor tans skermkiekie..."</string>
- <string name="screenshot_saving_text" msgid="2419718443411738818">"Skermkiekie word tans gestoor."</string>
- <string name="screenshot_saved_title" msgid="6461865960961414961">"Skermkiekie geneem."</string>
- <string name="screenshot_saved_text" msgid="2685605830386712477">"Tik om jou skermkiekie te sien."</string>
- <string name="screenshot_failed_title" msgid="705781116746922771">"Kon nie skermkiekie neem nie."</string>
- <string name="screenshot_failed_to_save_unknown_text" msgid="7887826345701753830">"Kon nie skermkiekie stoor nie."</string>
- <string name="screenshot_failed_to_save_text" msgid="2592658083866306296">"Kan weens beperkte bergingspasie nie skermkiekie stoor nie."</string>
+ <string name="screenshot_saving_text" msgid="2545047868936087248">"Skermkiekie word tans gestoor"</string>
+ <string name="screenshot_saved_title" msgid="5637073968117370753">"Skermkiekie is gestoor"</string>
+ <string name="screenshot_saved_text" msgid="7574667448002050363">"Tik om jou skermkiekie te bekyk"</string>
+ <string name="screenshot_failed_title" msgid="9096484883063264803">"Kon nie skermkiekie neem nie"</string>
+ <string name="screenshot_failed_to_save_unknown_text" msgid="8844781948876286488">"Kon nie skermkiekie stoor nie"</string>
+ <string name="screenshot_failed_to_save_text" msgid="3041612585107107310">"Kan weens beperkte bergingspasie nie skermkiekie stoor nie"</string>
<string name="screenshot_failed_to_capture_text" msgid="173674476457581486">"Die program of jou organisasie laat nie toe dat skermkiekies geneem word nie"</string>
<string name="usb_preference_title" msgid="6551050377388882787">"USB-lêeroordrag-opsies"</string>
<string name="use_mtp_button_title" msgid="4333504413563023626">"Heg as \'n mediaspeler (MTP)"</string>
@@ -557,26 +561,19 @@
<string name="tuner_full_importance_settings_off" msgid="8208165412614935229">"Af"</string>
<string name="power_notification_controls_description" msgid="4372459941671353358">"Met kragkennisgewingkontroles kan jy \'n belangrikheidvlak van 0 tot 5 vir \'n program se kennisgewings stel. \n\n"<b>"Vlak 5"</b>" \n- Wys aan die bokant van die kennisgewinglys \n- Laat volskermonderbreking toe \n- Wys altyd opspringkennisgewings \n\n"<b>"Vlak 4"</b>" \n- Verhoed volskermonderbreking \n- Wys altyd opspringkennisgewings \n\n"<b>"Vlak 3"</b>" \n- Verhoed volskermonderbreking \n- Verhoed opspringkennisgewings \n\n"<b>"Vlak 2"</b>" \n- Verhoed volskermonderbreking \n- Verhoed opspringkennisgewings \n- Moet nooit \'n klank maak of vibreer nie \n\n"<b>"Vlak 1"</b>" \n- Verhoed volskermonderbreking \n- Verhoed opspringkennisgewings \n- Moet nooit \'n klank maak of vibreer nie \n- Versteek van sluitskerm en statusbalk \n- Wys aan die onderkant van die kennisgewinglys \n\n"<b>"Vlak 0"</b>" \n- Blokkeer alle kennisgewings van die program af"</string>
<string name="notification_header_default_channel" msgid="7506845022070889909">"Kennisgewings"</string>
- <string name="notification_channel_disabled" msgid="2139193533791840539">"Jy sal nie meer hierdie kennisgewings kry nie"</string>
- <string name="notification_num_channels" msgid="2048144408999179471">"<xliff:g id="NUMBER">%d</xliff:g> kennisgewingkategorieë"</string>
- <string name="notification_default_channel_desc" msgid="2506053815870808359">"Hierdie program het nie kennisgewingkategorieë nie"</string>
- <string name="notification_unblockable_desc" msgid="3561016061737896906">"Kennisgewings van hierdie program af kan nie afgeskakel word nie"</string>
- <plurals name="notification_num_channels_desc" formatted="false" msgid="5492793452274077663">
- <item quantity="other">1 uit <xliff:g id="NUMBER_1">%s</xliff:g> kennisgewingkategorieë van hierdie program</item>
- <item quantity="one">1 uit <xliff:g id="NUMBER_0">%s</xliff:g> kennisgewingkategorie van hierdie program</item>
- </plurals>
- <string name="notification_channels_list_desc_2" msgid="6214732715833946441">"<xliff:g id="CHANNEL_NAME_1">%1$s</xliff:g>, <xliff:g id="CHANNEL_NAME_2">%2$s</xliff:g>"</string>
- <plurals name="notification_channels_list_desc_2_and_others" formatted="false" msgid="2747813553355336157">
- <item quantity="other"><xliff:g id="CHANNEL_NAME_1_3">%1$s</xliff:g>, <xliff:g id="CHANNEL_NAME_2_4">%2$s</xliff:g> en <xliff:g id="NUMBER_5">%3$d</xliff:g> ander kanale</item>
- <item quantity="one"><xliff:g id="CHANNEL_NAME_1_0">%1$s</xliff:g>, <xliff:g id="CHANNEL_NAME_2_1">%2$s</xliff:g> en <xliff:g id="NUMBER_2">%3$d</xliff:g> ander kanaal</item>
- </plurals>
+ <string name="notification_channel_disabled" msgid="344536703863700565">"Jy sal nie meer hierdie kennisgewings sien nie"</string>
+ <string name="inline_keep_showing" msgid="8945102997083836858">"Hou aan om hierdie kennisgewings te wys?"</string>
+ <string name="inline_stop_button" msgid="4172980096860941033">"Stop kennisgewings"</string>
+ <string name="inline_keep_button" msgid="6665940297019018232">"Hou aan wys"</string>
+ <string name="inline_keep_showing_app" msgid="1723113469580031041">"Hou aan om kennisgewings van hierdie program af te wys?"</string>
+ <string name="notification_unblockable_desc" msgid="1037434112919403708">"Hierdie kennisgewings kan nie afgeskakel word nie"</string>
<string name="notification_channel_controls_opened_accessibility" msgid="6553950422055908113">"Kennisgewingkontroles vir <xliff:g id="APP_NAME">%1$s</xliff:g> is oopgemaak"</string>
<string name="notification_channel_controls_closed_accessibility" msgid="7521619812603693144">"Kennisgewingkontroles vir <xliff:g id="APP_NAME">%1$s</xliff:g> is toegemaak"</string>
<string name="notification_channel_switch_accessibility" msgid="3420796005601900717">"Laat kennisgewings van hierdie kanaal af toe"</string>
- <string name="notification_all_categories" msgid="5407190218055113282">"Alle kategorieë"</string>
<string name="notification_more_settings" msgid="816306283396553571">"Meer instellings"</string>
- <string name="notification_app_settings" msgid="3743278649182392015">"Pasmaak: <xliff:g id="SUB_CATEGORY">%1$s</xliff:g>"</string>
+ <string name="notification_app_settings" msgid="420348114670768449">"Pasmaak"</string>
<string name="notification_done" msgid="5279426047273930175">"Klaar"</string>
+ <string name="inline_undo" msgid="558916737624706010">"Ontdoen"</string>
<string name="notification_menu_accessibility" msgid="2046162834248888553">"<xliff:g id="APP_NAME">%1$s</xliff:g> <xliff:g id="MENU_DESCRIPTION">%2$s</xliff:g>"</string>
<string name="notification_menu_gear_description" msgid="2204480013726775108">"kennisgewingkontroles"</string>
<string name="notification_menu_snooze_description" msgid="3653669438131034525">"kennisgewing-sluimeropsies"</string>
@@ -731,8 +728,7 @@
<string name="pip_phone_expand" msgid="5889780005575693909">"Vou uit"</string>
<string name="pip_phone_minimize" msgid="1079119422589131792">"Minimeer"</string>
<string name="pip_phone_close" msgid="8416647892889710330">"Maak toe"</string>
- <!-- no translation found for pip_phone_settings (8080777499521528521) -->
- <skip />
+ <string name="pip_phone_settings" msgid="8080777499521528521">"Instellings"</string>
<string name="pip_phone_dismiss_hint" msgid="6351678169095923899">"Sleep af om toe te maak"</string>
<string name="pip_menu_title" msgid="4707292089961887657">"Kieslys"</string>
<string name="pip_notification_title" msgid="3204024940158161322">"<xliff:g id="NAME">%s</xliff:g> is in beeld-in-beeld"</string>
diff --git a/packages/SystemUI/res/values-ar/strings.xml b/packages/SystemUI/res/values-ar/strings.xml
index e5db8deeb095..a2a0f06f6411 100644
--- a/packages/SystemUI/res/values-ar/strings.xml
+++ b/packages/SystemUI/res/values-ar/strings.xml
@@ -37,7 +37,10 @@
<string name="status_bar_ongoing_events_title" msgid="1682504513316879202">"مستمر"</string>
<string name="status_bar_latest_events_title" msgid="6594767438577593172">"الإشعارات"</string>
<string name="battery_low_title" msgid="6456385927409742437">"البطارية منخفضة"</string>
+ <string name="battery_low_title_hybrid" msgid="6268991275887381595">"طاقة البطارية منخفضة، لذا يُرجى تفعيل الوضع \"توفير شحن البطارية\"."</string>
<string name="battery_low_percent_format" msgid="2900940511201380775">"متبقي <xliff:g id="PERCENTAGE">%s</xliff:g>"</string>
+ <string name="battery_low_percent_format_hybrid" msgid="6838677459286775617">"طاقة البطارية المتبقية <xliff:g id="PERCENTAGE">%s</xliff:g> ويتبقى على نفادها <xliff:g id="TIME">%s</xliff:g> تقريبًا بناءً على استخدامك."</string>
+ <string name="battery_low_percent_format_hybrid_short" msgid="9025795469949145586">"طاقة البطارية المتبقية <xliff:g id="PERCENTAGE">%s</xliff:g> ويتبقى على نفادها <xliff:g id="TIME">%s</xliff:g> تقريبًا."</string>
<string name="battery_low_percent_format_saver_started" msgid="7879389868952879166">"يتبقى <xliff:g id="PERCENTAGE">%s</xliff:g>. تم تفعيل ميزة توفير شحن البطارية."</string>
<string name="invalid_charger" msgid="4549105996740522523">"‏شحن USB غير معتمد.\nاستخدم الشاحن الموفر فقط."</string>
<string name="invalid_charger_title" msgid="3515740382572798460">"‏لا يمكن إجراء الشحن عبر USB."</string>
@@ -71,14 +74,15 @@
<string name="usb_debugging_secondary_user_message" msgid="6067122453571699801">"‏لا يمكن للمستخدم الذي يسجّل دخوله حاليًا إلى هذا الجهاز تشغيل تصحيح أخطاء USB. لاستخدام هذه الميزة، يمكنك التبديل إلى المستخدم الأساسي."</string>
<string name="compat_mode_on" msgid="6623839244840638213">"تكبير/تصغير لملء الشاشة"</string>
<string name="compat_mode_off" msgid="4434467572461327898">"توسيع بملء الشاشة"</string>
+ <string name="global_action_screenshot" msgid="8329831278085426283">"لقطة شاشة"</string>
<string name="screenshot_saving_ticker" msgid="7403652894056693515">"جارٍ حفظ لقطة الشاشة..."</string>
<string name="screenshot_saving_title" msgid="8242282144535555697">"جارٍ حفظ لقطة الشاشة..."</string>
- <string name="screenshot_saving_text" msgid="2419718443411738818">"يتم حفظ لقطة."</string>
- <string name="screenshot_saved_title" msgid="6461865960961414961">"تم التقاط لقطة الشاشة"</string>
- <string name="screenshot_saved_text" msgid="2685605830386712477">"انقر لعرض لقطة الشاشة"</string>
- <string name="screenshot_failed_title" msgid="705781116746922771">"تعذر التقاط لقطة الشاشة."</string>
- <string name="screenshot_failed_to_save_unknown_text" msgid="7887826345701753830">"حدثت مشكلة أثناء حفظ لقطة الشاشة."</string>
- <string name="screenshot_failed_to_save_text" msgid="2592658083866306296">"يتعذر حفظ لقطة الشاشة نظرًا لأن مساحة التخزين المتاحة محدودة."</string>
+ <string name="screenshot_saving_text" msgid="2545047868936087248">"جارٍ حفظ لقطة الشاشة."</string>
+ <string name="screenshot_saved_title" msgid="5637073968117370753">"تم حفظ لقطة الشاشة."</string>
+ <string name="screenshot_saved_text" msgid="7574667448002050363">"انقر لعرض لقطة الشاشة."</string>
+ <string name="screenshot_failed_title" msgid="9096484883063264803">"تعذَّر الحصول على لقطة شاشة"</string>
+ <string name="screenshot_failed_to_save_unknown_text" msgid="8844781948876286488">"حدثت مشكلة أثناء حفظ لقطة الشاشة."</string>
+ <string name="screenshot_failed_to_save_text" msgid="3041612585107107310">"يتعذر حفظ لقطة الشاشة لأن مساحة التخزين المتاحة محدودة."</string>
<string name="screenshot_failed_to_capture_text" msgid="173674476457581486">"يحظر التطبيق أو تحظر مؤسستك التقاط لقطات شاشة"</string>
<string name="usb_preference_title" msgid="6551050377388882787">"‏خيارات نقل الملفات عبر USB"</string>
<string name="use_mtp_button_title" msgid="4333504413563023626">"‏تحميل كمشغل وسائط (MTP)"</string>
@@ -565,34 +569,19 @@
<string name="tuner_full_importance_settings_off" msgid="8208165412614935229">"إيقاف"</string>
<string name="power_notification_controls_description" msgid="4372459941671353358">"باستخدام عناصر التحكم في إشعار التشغيل، يمكنك تعيين مستوى الأهمية من 0 إلى 5 لإشعارات التطبيق. \n\n"<b>"المستوى 5"</b>" \n- العرض أعلى قائمة الإشعارات \n- يسمح بمقاطعة ملء الشاشة \n- الظهور الخاطف دائمًا \n\n"<b>"المستوى 4"</b>" \n- منع مقاطعة ملء الشاشة \n- الظهور الخاطف دائمًا \n\n"<b>"المستوى 3"</b>" \n- منع مقاطعة ملء الشاشة \n- عدم الظهور الخاطف أبدًا \n\n"<b>"المستوى 2"</b>" \n- منع مقاطعة ملء الشاشة \n- عدم الظهور الخاطف أبدًا \n- عدم إصدار أصوات واهتزاز \n\n"<b>"المستوى 1"</b>" \n- منع مقاطعة ملء الشاشة \n- عدم الظهور الخاطف أبدًا \n- عدم إصدار أصوات أو اهتزاز أبدًا \n- الإخفاء من شاشة التأمين وشريط الحالة \n- العرض أسفل قائمة الإشعارات \n\n"<b>"المستوى 0"</b>" \n- حظر جميع الإشعارات من التطبيق"</string>
<string name="notification_header_default_channel" msgid="7506845022070889909">"الإشعارات"</string>
- <string name="notification_channel_disabled" msgid="2139193533791840539">"لن تتلقى هذه الإشعارات بعد الآن."</string>
- <string name="notification_num_channels" msgid="2048144408999179471">"<xliff:g id="NUMBER">%d</xliff:g> فئة إشعار"</string>
- <string name="notification_default_channel_desc" msgid="2506053815870808359">"لا يحتوي هذا التطبيق على فئات إشعار"</string>
- <string name="notification_unblockable_desc" msgid="3561016061737896906">"لا يمكن إيقاف الإشعارات من هذا التطبيق"</string>
- <plurals name="notification_num_channels_desc" formatted="false" msgid="5492793452274077663">
- <item quantity="zero">1 من إجمالي <xliff:g id="NUMBER_1">%s</xliff:g> فئة إشعار من هذا التطبيق</item>
- <item quantity="two">1 من إجمالي فئتي إشعار (<xliff:g id="NUMBER_1">%s</xliff:g>) من هذا التطبيق</item>
- <item quantity="few">1 من إجمالي <xliff:g id="NUMBER_1">%s</xliff:g> فئات إشعار من هذا التطبيق</item>
- <item quantity="many">1 من إجمالي <xliff:g id="NUMBER_1">%s</xliff:g> فئة إشعار من هذا التطبيق</item>
- <item quantity="other">1 من إجمالي <xliff:g id="NUMBER_1">%s</xliff:g> فئة إشعار من هذا التطبيق</item>
- <item quantity="one">1 من إجمالي <xliff:g id="NUMBER_0">%s</xliff:g> فئة إشعار من هذا التطبيق</item>
- </plurals>
- <string name="notification_channels_list_desc_2" msgid="6214732715833946441">"<xliff:g id="CHANNEL_NAME_1">%1$s</xliff:g>، <xliff:g id="CHANNEL_NAME_2">%2$s</xliff:g>"</string>
- <plurals name="notification_channels_list_desc_2_and_others" formatted="false" msgid="2747813553355336157">
- <item quantity="zero"><xliff:g id="CHANNEL_NAME_1_3">%1$s</xliff:g> و<xliff:g id="CHANNEL_NAME_2_4">%2$s</xliff:g> و<xliff:g id="NUMBER_5">%3$d</xliff:g> أيضًا</item>
- <item quantity="two"><xliff:g id="CHANNEL_NAME_1_3">%1$s</xliff:g> و<xliff:g id="CHANNEL_NAME_2_4">%2$s</xliff:g> و<xliff:g id="NUMBER_5">%3$d</xliff:g> أيضًا</item>
- <item quantity="few"><xliff:g id="CHANNEL_NAME_1_3">%1$s</xliff:g> و<xliff:g id="CHANNEL_NAME_2_4">%2$s</xliff:g> و<xliff:g id="NUMBER_5">%3$d</xliff:g> أيضًا</item>
- <item quantity="many"><xliff:g id="CHANNEL_NAME_1_3">%1$s</xliff:g> و<xliff:g id="CHANNEL_NAME_2_4">%2$s</xliff:g> و<xliff:g id="NUMBER_5">%3$d</xliff:g> أيضًا</item>
- <item quantity="other"><xliff:g id="CHANNEL_NAME_1_3">%1$s</xliff:g> و<xliff:g id="CHANNEL_NAME_2_4">%2$s</xliff:g> و<xliff:g id="NUMBER_5">%3$d</xliff:g> أيضًا</item>
- <item quantity="one"><xliff:g id="CHANNEL_NAME_1_0">%1$s</xliff:g> و<xliff:g id="CHANNEL_NAME_2_1">%2$s</xliff:g> و<xliff:g id="NUMBER_2">%3$d</xliff:g> أيضًا</item>
- </plurals>
+ <string name="notification_channel_disabled" msgid="344536703863700565">"لن تتلقى هذه الإشعارات بعد الآن."</string>
+ <string name="inline_keep_showing" msgid="8945102997083836858">"هل تريد الاستمرار في تلقي هذه الإشعارات؟"</string>
+ <string name="inline_stop_button" msgid="4172980096860941033">"إيقاف الإشعارات"</string>
+ <string name="inline_keep_button" msgid="6665940297019018232">"الاستمرار في تلقّي الإشعارات"</string>
+ <string name="inline_keep_showing_app" msgid="1723113469580031041">"هل تريد الاستمرار في تلقي إشعارات من هذا التطبيق؟"</string>
+ <string name="notification_unblockable_desc" msgid="1037434112919403708">"يتعذَّر إيقاف هذه الإشعارات."</string>
<string name="notification_channel_controls_opened_accessibility" msgid="6553950422055908113">"تم فتح عناصر التحكم في الإشعارات لتطبيق <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
<string name="notification_channel_controls_closed_accessibility" msgid="7521619812603693144">"تم إغلاق عناصر التحكم في الإشعارات لتطبيق <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
<string name="notification_channel_switch_accessibility" msgid="3420796005601900717">"السماح بالإشعارات من هذه القناة"</string>
- <string name="notification_all_categories" msgid="5407190218055113282">"كل الفئات"</string>
<string name="notification_more_settings" msgid="816306283396553571">"المزيد من الإعدادات"</string>
- <string name="notification_app_settings" msgid="3743278649182392015">"تخصيص: <xliff:g id="SUB_CATEGORY">%1$s</xliff:g>"</string>
+ <string name="notification_app_settings" msgid="420348114670768449">"تخصيص"</string>
<string name="notification_done" msgid="5279426047273930175">"تم"</string>
+ <string name="inline_undo" msgid="558916737624706010">"تراجع"</string>
<string name="notification_menu_accessibility" msgid="2046162834248888553">"<xliff:g id="APP_NAME">%1$s</xliff:g> <xliff:g id="MENU_DESCRIPTION">%2$s</xliff:g>"</string>
<string name="notification_menu_gear_description" msgid="2204480013726775108">"عناصر التحكم في الإشعارات"</string>
<string name="notification_menu_snooze_description" msgid="3653669438131034525">"خيارات تأجيل الإشعارات"</string>
@@ -755,8 +744,7 @@
<string name="pip_phone_expand" msgid="5889780005575693909">"توسيع"</string>
<string name="pip_phone_minimize" msgid="1079119422589131792">"تصغير"</string>
<string name="pip_phone_close" msgid="8416647892889710330">"إغلاق"</string>
- <!-- no translation found for pip_phone_settings (8080777499521528521) -->
- <skip />
+ <string name="pip_phone_settings" msgid="8080777499521528521">"الإعدادات"</string>
<string name="pip_phone_dismiss_hint" msgid="6351678169095923899">"اسحب لأسفل للإلغاء"</string>
<string name="pip_menu_title" msgid="4707292089961887657">"القائمة"</string>
<string name="pip_notification_title" msgid="3204024940158161322">"<xliff:g id="NAME">%s</xliff:g> يظهر في صورة داخل صورة"</string>
diff --git a/packages/SystemUI/res/values-az/strings.xml b/packages/SystemUI/res/values-az/strings.xml
index 1b2972bb22ca..e73cc86210eb 100644
--- a/packages/SystemUI/res/values-az/strings.xml
+++ b/packages/SystemUI/res/values-az/strings.xml
@@ -33,7 +33,10 @@
<string name="status_bar_ongoing_events_title" msgid="1682504513316879202">"Davam edir"</string>
<string name="status_bar_latest_events_title" msgid="6594767438577593172">"Bildirişlər"</string>
<string name="battery_low_title" msgid="6456385927409742437">"Enerji azdır"</string>
+ <string name="battery_low_title_hybrid" msgid="6268991275887381595">"Batareya azdır. Batareya Qənaətini aktiv edin"</string>
<string name="battery_low_percent_format" msgid="2900940511201380775">"<xliff:g id="PERCENTAGE">%s</xliff:g> qalır"</string>
+ <string name="battery_low_percent_format_hybrid" msgid="6838677459286775617">"Qalan <xliff:g id="PERCENTAGE">%s</xliff:g>, istifadəyə əsasən təxminən <xliff:g id="TIME">%s</xliff:g> qalıb"</string>
+ <string name="battery_low_percent_format_hybrid_short" msgid="9025795469949145586">"Qalan <xliff:g id="PERCENTAGE">%s</xliff:g>, təxminən <xliff:g id="TIME">%s</xliff:g> qalır"</string>
<string name="battery_low_percent_format_saver_started" msgid="7879389868952879166">"<xliff:g id="PERCENTAGE">%s</xliff:g> qalır. Batareya Qənaəti aktivdir."</string>
<string name="invalid_charger" msgid="4549105996740522523">"USB ilə elektrik doldurma dəstəklənmir.\nYalnız adapter istifadə edin."</string>
<string name="invalid_charger_title" msgid="3515740382572798460">"USB qidalandırıcı dəstəklənmir."</string>
@@ -67,14 +70,15 @@
<string name="usb_debugging_secondary_user_message" msgid="6067122453571699801">"Hazırda bu cihaza daxil olmuş istifadəçi USB sazlama prosesini aktiv edə bilməz. Bu funksiyadan istifadə etmək üçün əsas istifadəçi hesaba daxil olmalıdır."</string>
<string name="compat_mode_on" msgid="6623839244840638213">"Ekranı doldurmaq üçün yaxınlaşdır"</string>
<string name="compat_mode_off" msgid="4434467572461327898">"Ekranı doldurmaq üçün uzat"</string>
+ <string name="global_action_screenshot" msgid="8329831278085426283">"Skrinşot"</string>
<string name="screenshot_saving_ticker" msgid="7403652894056693515">"Skrinşot yadda saxlanılır..."</string>
<string name="screenshot_saving_title" msgid="8242282144535555697">"Skrinşot yadda saxlanır..."</string>
- <string name="screenshot_saving_text" msgid="2419718443411738818">"Skrinşot yadda saxlanır."</string>
- <string name="screenshot_saved_title" msgid="6461865960961414961">"Skrinşot çəkildi."</string>
- <string name="screenshot_saved_text" msgid="2685605830386712477">"Skrinşotunuza baxmaq üçün tıklayın."</string>
- <string name="screenshot_failed_title" msgid="705781116746922771">"Skrinşot götürülə bilinmədi."</string>
- <string name="screenshot_failed_to_save_unknown_text" msgid="7887826345701753830">"Skrinşot yadda saxlanarkən problem baş verdi."</string>
- <string name="screenshot_failed_to_save_text" msgid="2592658083866306296">"Yaddaş ehtiyatının az olması səbəbindən skrinşotu yadda saxlamaq olmur."</string>
+ <string name="screenshot_saving_text" msgid="2545047868936087248">"Skrinşot yadda saxlanır"</string>
+ <string name="screenshot_saved_title" msgid="5637073968117370753">"Skrinşot yadda saxlandı"</string>
+ <string name="screenshot_saved_text" msgid="7574667448002050363">"Skrinşotunuza baxmaq üçün klikləyin"</string>
+ <string name="screenshot_failed_title" msgid="9096484883063264803">"Skrinşot çəkmək alınmadı"</string>
+ <string name="screenshot_failed_to_save_unknown_text" msgid="8844781948876286488">"Skrinşot yadda saxlanarkən problem baş verdi"</string>
+ <string name="screenshot_failed_to_save_text" msgid="3041612585107107310">"Yaddaş ehtiyatının az olması səbəbindən skrinşotu yadda saxlamaq olmur"</string>
<string name="screenshot_failed_to_capture_text" msgid="173674476457581486">"Skrinşot çəkməyə tətbiq və ya təşkilat tərəfindən icazə verilmir"</string>
<string name="usb_preference_title" msgid="6551050377388882787">"USB fayl transferi seçimləri"</string>
<string name="use_mtp_button_title" msgid="4333504413563023626">"Media pleyer (MTP) kimi montaj edin"</string>
@@ -557,26 +561,19 @@
<string name="tuner_full_importance_settings_off" msgid="8208165412614935229">"Deaktiv"</string>
<string name="power_notification_controls_description" msgid="4372459941671353358">"Enerji bildiriş nəzarəti ilə, tətbiq bildirişləri üçün əhəmiyyət səviyyəsini 0-dan 5-ə kimi ayarlaya bilərsiniz. \n\n"<b>"Səviyyə 5"</b>" \n- Bildiriş siyahısının yuxarı hissəsində göstərin \n- Tam ekran kəsintisinə icazə verin \n- Hər zaman izləyin \n\n"<b>"Səviyyə 4"</b>" \n- Tam ekran kəsintisinin qarşısını alın \n- Hər zaman izləyin \n\n"<b>"Level 3"</b>" \n- Tam ekran kəsintisinin qarşısını alın \n- Heç vaxt izləməyin \n\n"<b>"Level 2"</b>" \n- Tam ekran kəsintisinin qarşısını alın \n- Heç vaxt izləməyin \n- Heç vaxt səsliyə və ya vibrasiyaya qoymayın \n\n"<b>"Səviyyə 1"</b>" \n- Prevent full screen interruption \n- Heç vaxt izləməyin \n- Heç vaxt səsliyə və ya vibrasiyaya qoymayın \n- Ekran kilidi və ya status panelindən gizlədin \n- Bildiriş siyahısının yuxarı hissəsində göstərin \n\n"<b>"Səviyyə 0"</b>" \n- Bütün bildirişləri tətbiqdən blok edin"</string>
<string name="notification_header_default_channel" msgid="7506845022070889909">"Bildirişlər"</string>
- <string name="notification_channel_disabled" msgid="2139193533791840539">"Bu bildirişlər daha sizə göndərilməyəcək"</string>
- <string name="notification_num_channels" msgid="2048144408999179471">"<xliff:g id="NUMBER">%d</xliff:g> bildiriş kateqoriyaları"</string>
- <string name="notification_default_channel_desc" msgid="2506053815870808359">"Bu tətbiqin bildiriş kateqoriyası yoxdur"</string>
- <string name="notification_unblockable_desc" msgid="3561016061737896906">"Bu tətbiqin bildirişləri deaktiv edilə bilməz"</string>
- <plurals name="notification_num_channels_desc" formatted="false" msgid="5492793452274077663">
- <item quantity="other">Bu tətbiqin <xliff:g id="NUMBER_1">%s</xliff:g> bildiriş kateqoriyasından 1 kanal</item>
- <item quantity="one">Bu tətbiqin <xliff:g id="NUMBER_0">%s</xliff:g> bildiriş kateqoriyasından 1 kanal</item>
- </plurals>
- <string name="notification_channels_list_desc_2" msgid="6214732715833946441">"<xliff:g id="CHANNEL_NAME_1">%1$s</xliff:g>, <xliff:g id="CHANNEL_NAME_2">%2$s</xliff:g>"</string>
- <plurals name="notification_channels_list_desc_2_and_others" formatted="false" msgid="2747813553355336157">
- <item quantity="other"><xliff:g id="CHANNEL_NAME_1_3">%1$s</xliff:g>, <xliff:g id="CHANNEL_NAME_2_4">%2$s</xliff:g>, və <xliff:g id="NUMBER_5">%3$d</xliff:g> digər</item>
- <item quantity="one"><xliff:g id="CHANNEL_NAME_1_0">%1$s</xliff:g>, <xliff:g id="CHANNEL_NAME_2_1">%2$s</xliff:g>, və <xliff:g id="NUMBER_2">%3$d</xliff:g> digər</item>
- </plurals>
+ <string name="notification_channel_disabled" msgid="344536703863700565">"Artıq bu bildirişləri görməyəcəkəsiniz"</string>
+ <string name="inline_keep_showing" msgid="8945102997083836858">"Bu bildirişlər göstərilməyə davam edilsin?"</string>
+ <string name="inline_stop_button" msgid="4172980096860941033">"Bildirişləri dayandırın"</string>
+ <string name="inline_keep_button" msgid="6665940297019018232">"Göstərməyə davam edin"</string>
+ <string name="inline_keep_showing_app" msgid="1723113469580031041">"Bu tətbiqin bildirişləri göstərilməyə davam edilsin?"</string>
+ <string name="notification_unblockable_desc" msgid="1037434112919403708">"Bu bildirişlər deaktiv edilə bilməz"</string>
<string name="notification_channel_controls_opened_accessibility" msgid="6553950422055908113">"<xliff:g id="APP_NAME">%1$s</xliff:g> üçün bildiriş kontrolları açıqdır"</string>
<string name="notification_channel_controls_closed_accessibility" msgid="7521619812603693144">"<xliff:g id="APP_NAME">%1$s</xliff:g> üçün bildiriş kontrolları bağlıdır"</string>
<string name="notification_channel_switch_accessibility" msgid="3420796005601900717">"Bu kanaldan gələn bildirişlərə icazə verin"</string>
- <string name="notification_all_categories" msgid="5407190218055113282">"Bütün Kateqoriyalar"</string>
<string name="notification_more_settings" msgid="816306283396553571">"Daha çox ayar"</string>
- <string name="notification_app_settings" msgid="3743278649182392015">"Fərdiləşdirin: <xliff:g id="SUB_CATEGORY">%1$s</xliff:g>"</string>
+ <string name="notification_app_settings" msgid="420348114670768449">"Fərdiləşdirin"</string>
<string name="notification_done" msgid="5279426047273930175">"Hazırdır"</string>
+ <string name="inline_undo" msgid="558916737624706010">"Ləğv edin"</string>
<string name="notification_menu_accessibility" msgid="2046162834248888553">"<xliff:g id="APP_NAME">%1$s</xliff:g> <xliff:g id="MENU_DESCRIPTION">%2$s</xliff:g>"</string>
<string name="notification_menu_gear_description" msgid="2204480013726775108">"bildiriş nəzarəti"</string>
<string name="notification_menu_snooze_description" msgid="3653669438131034525">"bildiriş təxirə salma seçimləri"</string>
@@ -731,8 +728,7 @@
<string name="pip_phone_expand" msgid="5889780005575693909">"Genişləndirin"</string>
<string name="pip_phone_minimize" msgid="1079119422589131792">"Kiçildin"</string>
<string name="pip_phone_close" msgid="8416647892889710330">"Bağlayın"</string>
- <!-- no translation found for pip_phone_settings (8080777499521528521) -->
- <skip />
+ <string name="pip_phone_settings" msgid="8080777499521528521">"Ayarlar"</string>
<string name="pip_phone_dismiss_hint" msgid="6351678169095923899">"Rədd etmək üçün aşağı çəkin"</string>
<string name="pip_menu_title" msgid="4707292089961887657">"Menyu"</string>
<string name="pip_notification_title" msgid="3204024940158161322">"<xliff:g id="NAME">%s</xliff:g> şəkil içində şəkildədir"</string>
diff --git a/packages/SystemUI/res/values-b+sr+Latn/strings.xml b/packages/SystemUI/res/values-b+sr+Latn/strings.xml
index 2d3635c13fbd..3c203b1fccd1 100644
--- a/packages/SystemUI/res/values-b+sr+Latn/strings.xml
+++ b/packages/SystemUI/res/values-b+sr+Latn/strings.xml
@@ -34,7 +34,10 @@
<string name="status_bar_ongoing_events_title" msgid="1682504513316879202">"Tekuće"</string>
<string name="status_bar_latest_events_title" msgid="6594767438577593172">"Obaveštenja"</string>
<string name="battery_low_title" msgid="6456385927409742437">"Nivo napunjenosti baterije je nizak"</string>
+ <string name="battery_low_title_hybrid" msgid="6268991275887381595">"Baterija je skoro prazna. Uključite Uštedu baterije"</string>
<string name="battery_low_percent_format" msgid="2900940511201380775">"Još <xliff:g id="PERCENTAGE">%s</xliff:g>"</string>
+ <string name="battery_low_percent_format_hybrid" msgid="6838677459286775617">"Još <xliff:g id="PERCENTAGE">%s</xliff:g>, na osnovu korišćenja ostalo je oko <xliff:g id="TIME">%s</xliff:g>"</string>
+ <string name="battery_low_percent_format_hybrid_short" msgid="9025795469949145586">"Još <xliff:g id="PERCENTAGE">%s</xliff:g>, ostalo je oko <xliff:g id="TIME">%s</xliff:g>"</string>
<string name="battery_low_percent_format_saver_started" msgid="7879389868952879166">"Još <xliff:g id="PERCENTAGE">%s</xliff:g>. Ušteda baterije je uključena."</string>
<string name="invalid_charger" msgid="4549105996740522523">"Punjenje preko USB-a nije podržano.\nKoristite samo priloženi punjač."</string>
<string name="invalid_charger_title" msgid="3515740382572798460">"Punjenje preko USB-a nije podržano."</string>
@@ -68,14 +71,15 @@
<string name="usb_debugging_secondary_user_message" msgid="6067122453571699801">"Korisnik koji je trenutno prijavljen na ovaj uređaj ne može da uključi otklanjanje grešaka na USB-u. Da biste koristili ovu funkciju, prebacite na primarnog korisnika."</string>
<string name="compat_mode_on" msgid="6623839244840638213">"Zumiraj na celom ekranu"</string>
<string name="compat_mode_off" msgid="4434467572461327898">"Razvuci na ceo ekran"</string>
+ <string name="global_action_screenshot" msgid="8329831278085426283">"Snimak ekrana"</string>
<string name="screenshot_saving_ticker" msgid="7403652894056693515">"Čuvanje snimka ekrana..."</string>
<string name="screenshot_saving_title" msgid="8242282144535555697">"Čuvanje snimka ekrana..."</string>
- <string name="screenshot_saving_text" msgid="2419718443411738818">"Snimak ekrana se čuva."</string>
- <string name="screenshot_saved_title" msgid="6461865960961414961">"Snimak ekrana je napravljen."</string>
- <string name="screenshot_saved_text" msgid="2685605830386712477">"Dodirnite da biste videli snimak ekrana."</string>
- <string name="screenshot_failed_title" msgid="705781116746922771">"Nije moguće napraviti snimak ekrana."</string>
- <string name="screenshot_failed_to_save_unknown_text" msgid="7887826345701753830">"Došlo je do problema pri čuvanju snimka ekrana."</string>
- <string name="screenshot_failed_to_save_text" msgid="2592658083866306296">"Čuvanje snimka ekrana nije uspelo zbog ograničenog memorijskog prostora."</string>
+ <string name="screenshot_saving_text" msgid="2545047868936087248">"Snimak ekrana se čuva"</string>
+ <string name="screenshot_saved_title" msgid="5637073968117370753">"Snimak ekrana je sačuvan"</string>
+ <string name="screenshot_saved_text" msgid="7574667448002050363">"Dodirnite da biste videli snimak ekrana"</string>
+ <string name="screenshot_failed_title" msgid="9096484883063264803">"Ne možete da napravite snimak ekrana"</string>
+ <string name="screenshot_failed_to_save_unknown_text" msgid="8844781948876286488">"Došlo je do problema pri čuvanju snimka ekrana"</string>
+ <string name="screenshot_failed_to_save_text" msgid="3041612585107107310">"Čuvanje snimka ekrana nije uspelo zbog ograničenog memorijskog prostora"</string>
<string name="screenshot_failed_to_capture_text" msgid="173674476457581486">"Aplikacija ili organizacija ne dozvoljavaju pravljenje snimaka ekrana"</string>
<string name="usb_preference_title" msgid="6551050377388882787">"Opcije USB prenosa datoteka"</string>
<string name="use_mtp_button_title" msgid="4333504413563023626">"Priključi kao medija plejer (MTP)"</string>
@@ -559,28 +563,19 @@
<string name="tuner_full_importance_settings_off" msgid="8208165412614935229">"Isključeno"</string>
<string name="power_notification_controls_description" msgid="4372459941671353358">"Pomoću naprednih kontrola za obaveštenja možete da podesite nivo važnosti od 0. do 5. za obaveštenja aplikacije. \n\n"<b>"5. nivo"</b>" \n– Prikazuju se u vrhu liste obaveštenja \n- Dozvoli prekid režima celog ekrana \n– Uvek zaviruj \n\n"<b>"4. nivo"</b>" \n– Spreči prekid režima celog ekrana \n– Uvek zaviruj \n\n"<b>"3. nivo"</b>" \n– Spreči prekid režima celog ekrana \n– Nikada ne zaviruj \n\n"<b>"2. nivo"</b>" \n– Spreči prekid režima celog ekrana \n– Nikada ne zaviruj \n– Nikada ne proizvodi zvuk ili vibraciju \n\n"<b>"1. nivo"</b>" \n– Spreči prekid režima celog ekrana \n– Nikada ne zaviruj \n– Nikada ne proizvodi zvuk ili vibraciju \n– Sakrij na zaključanom ekranu i statusnoj traci \n– Prikazuju se u dnu liste obaveštenja \n\n"<b>"0. nivo"</b>" \n– Blokiraj sva obaveštenja iz aplikacije"</string>
<string name="notification_header_default_channel" msgid="7506845022070889909">"Obaveštenja"</string>
- <string name="notification_channel_disabled" msgid="2139193533791840539">"Više nećete dobijati ova obaveštenja"</string>
- <string name="notification_num_channels" msgid="2048144408999179471">"Kategorija obaveštenja: <xliff:g id="NUMBER">%d</xliff:g>"</string>
- <string name="notification_default_channel_desc" msgid="2506053815870808359">"Ova aplikacija nema kategorije obaveštenja"</string>
- <string name="notification_unblockable_desc" msgid="3561016061737896906">"Obaveštenja iz ove aplikacije ne mogu da se isključe"</string>
- <plurals name="notification_num_channels_desc" formatted="false" msgid="5492793452274077663">
- <item quantity="one">1 od <xliff:g id="NUMBER_1">%s</xliff:g> kategorije obaveštenja za ovu aplikaciju</item>
- <item quantity="few">1 od <xliff:g id="NUMBER_1">%s</xliff:g> kategorije obaveštenja za ovu aplikaciju</item>
- <item quantity="other">1 od <xliff:g id="NUMBER_1">%s</xliff:g> kategorija obaveštenja za ovu aplikaciju</item>
- </plurals>
- <string name="notification_channels_list_desc_2" msgid="6214732715833946441">"<xliff:g id="CHANNEL_NAME_1">%1$s</xliff:g>, <xliff:g id="CHANNEL_NAME_2">%2$s</xliff:g>"</string>
- <plurals name="notification_channels_list_desc_2_and_others" formatted="false" msgid="2747813553355336157">
- <item quantity="one"><xliff:g id="CHANNEL_NAME_1_3">%1$s</xliff:g>, <xliff:g id="CHANNEL_NAME_2_4">%2$s</xliff:g> i još <xliff:g id="NUMBER_5">%3$d</xliff:g></item>
- <item quantity="few"><xliff:g id="CHANNEL_NAME_1_3">%1$s</xliff:g>, <xliff:g id="CHANNEL_NAME_2_4">%2$s</xliff:g> i još <xliff:g id="NUMBER_5">%3$d</xliff:g></item>
- <item quantity="other"><xliff:g id="CHANNEL_NAME_1_3">%1$s</xliff:g>, <xliff:g id="CHANNEL_NAME_2_4">%2$s</xliff:g> i još <xliff:g id="NUMBER_5">%3$d</xliff:g></item>
- </plurals>
+ <string name="notification_channel_disabled" msgid="344536703863700565">"Više nećete videti ova obaveštenja"</string>
+ <string name="inline_keep_showing" msgid="8945102997083836858">"Želite li da se ova obaveštenja i dalje prikazuju?"</string>
+ <string name="inline_stop_button" msgid="4172980096860941033">"Prestani da prikazuješ obaveštenja"</string>
+ <string name="inline_keep_button" msgid="6665940297019018232">"Nastavi da prikazuješ"</string>
+ <string name="inline_keep_showing_app" msgid="1723113469580031041">"Želite li da se obaveštenja iz ove aplikacije i dalje prikazuju?"</string>
+ <string name="notification_unblockable_desc" msgid="1037434112919403708">"Ne možete da isključite ova obaveštenja"</string>
<string name="notification_channel_controls_opened_accessibility" msgid="6553950422055908113">"Kontrole obaveštenja za otvaranje aplikacije <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
<string name="notification_channel_controls_closed_accessibility" msgid="7521619812603693144">"Kontrole obaveštenja za zatvaranje aplikacije <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
<string name="notification_channel_switch_accessibility" msgid="3420796005601900717">"Dozvoli obaveštenja sa ovog kanala"</string>
- <string name="notification_all_categories" msgid="5407190218055113282">"Sve kategorije"</string>
<string name="notification_more_settings" msgid="816306283396553571">"Još podešavanja"</string>
- <string name="notification_app_settings" msgid="3743278649182392015">"Prilagodite: <xliff:g id="SUB_CATEGORY">%1$s</xliff:g>"</string>
+ <string name="notification_app_settings" msgid="420348114670768449">"Prilagodi"</string>
<string name="notification_done" msgid="5279426047273930175">"Gotovo"</string>
+ <string name="inline_undo" msgid="558916737624706010">"Opozovi"</string>
<string name="notification_menu_accessibility" msgid="2046162834248888553">"<xliff:g id="APP_NAME">%1$s</xliff:g> <xliff:g id="MENU_DESCRIPTION">%2$s</xliff:g>"</string>
<string name="notification_menu_gear_description" msgid="2204480013726775108">"kontrole obaveštenja"</string>
<string name="notification_menu_snooze_description" msgid="3653669438131034525">"opcije za odlaganje obaveštenja"</string>
@@ -737,8 +732,7 @@
<string name="pip_phone_expand" msgid="5889780005575693909">"Proširi"</string>
<string name="pip_phone_minimize" msgid="1079119422589131792">"Umanji"</string>
<string name="pip_phone_close" msgid="8416647892889710330">"Zatvori"</string>
- <!-- no translation found for pip_phone_settings (8080777499521528521) -->
- <skip />
+ <string name="pip_phone_settings" msgid="8080777499521528521">"Podešavanja"</string>
<string name="pip_phone_dismiss_hint" msgid="6351678169095923899">"Prevucite nadole da biste odbili"</string>
<string name="pip_menu_title" msgid="4707292089961887657">"Meni"</string>
<string name="pip_notification_title" msgid="3204024940158161322">"<xliff:g id="NAME">%s</xliff:g> je slika u slici"</string>
diff --git a/packages/SystemUI/res/values-be/strings.xml b/packages/SystemUI/res/values-be/strings.xml
index 27e3a7d5f555..41ce8239e9ed 100644
--- a/packages/SystemUI/res/values-be/strings.xml
+++ b/packages/SystemUI/res/values-be/strings.xml
@@ -35,7 +35,10 @@
<string name="status_bar_ongoing_events_title" msgid="1682504513316879202">"Пастаянныя"</string>
<string name="status_bar_latest_events_title" msgid="6594767438577593172">"Апавяшчэнні"</string>
<string name="battery_low_title" msgid="6456385927409742437">"Нізкі ўзровень зараду акумулятара"</string>
+ <string name="battery_low_title_hybrid" msgid="6268991275887381595">"Нізкі зарад акумулятара. Уключыце функцыю эканоміі зараду"</string>
<string name="battery_low_percent_format" msgid="2900940511201380775">"Засталося <xliff:g id="PERCENTAGE">%s</xliff:g>"</string>
+ <string name="battery_low_percent_format_hybrid" msgid="6838677459286775617">"Засталося <xliff:g id="PERCENTAGE">%s</xliff:g>, у вас ёсць каля <xliff:g id="TIME">%s</xliff:g> на аснове даных аб выкарыстанні вашай прылады"</string>
+ <string name="battery_low_percent_format_hybrid_short" msgid="9025795469949145586">"Засталося <xliff:g id="PERCENTAGE">%s</xliff:g>, у вас ёсць каля <xliff:g id="TIME">%s</xliff:g>"</string>
<string name="battery_low_percent_format_saver_started" msgid="7879389868952879166">"Засталося <xliff:g id="PERCENTAGE">%s</xliff:g>. Уключана эканомія зараду."</string>
<string name="invalid_charger" msgid="4549105996740522523">"USB-зарадка не падтрымліваецца.\nКарыстайцеся толькі зарадкай для прылады."</string>
<string name="invalid_charger_title" msgid="3515740382572798460">"Зарадка па USB не падтрымліваецца."</string>
@@ -69,14 +72,15 @@
<string name="usb_debugging_secondary_user_message" msgid="6067122453571699801">"Карыстальнік, які зараз увайшоў у гэту прыладу, не можа ўключыць адладку USB. Каб выкарыстоўваць гэту функцыю, пераключыцеся на асноўнага карыстальніка."</string>
<string name="compat_mode_on" msgid="6623839244840638213">"Павял. на ўвесь экран"</string>
<string name="compat_mode_off" msgid="4434467572461327898">"Расцягн. на ўвесь экран"</string>
+ <string name="global_action_screenshot" msgid="8329831278085426283">"Здымак экрана"</string>
<string name="screenshot_saving_ticker" msgid="7403652894056693515">"Захаванне скрыншота..."</string>
<string name="screenshot_saving_title" msgid="8242282144535555697">"Захаванне скрыншота..."</string>
- <string name="screenshot_saving_text" msgid="2419718443411738818">"Скрыншот захаваны."</string>
- <string name="screenshot_saved_title" msgid="6461865960961414961">"Скрыншот зроблены"</string>
- <string name="screenshot_saved_text" msgid="2685605830386712477">"Дакраніцеся, каб прагледзець здымак экрана."</string>
- <string name="screenshot_failed_title" msgid="705781116746922771">"Не атрымалася зрабiць скрыншот."</string>
- <string name="screenshot_failed_to_save_unknown_text" msgid="7887826345701753830">"Падчас захавання скрыншота адбылася памылка."</string>
- <string name="screenshot_failed_to_save_text" msgid="2592658083866306296">"Немагчыма захаваць здымак экрана, бо мала месца ў памяці."</string>
+ <string name="screenshot_saving_text" msgid="2545047868936087248">"Захаванне здымка экрана"</string>
+ <string name="screenshot_saved_title" msgid="5637073968117370753">"Здымак экрана захаваны"</string>
+ <string name="screenshot_saved_text" msgid="7574667448002050363">"Дакраніцеся, каб прагледзець здымак экрана"</string>
+ <string name="screenshot_failed_title" msgid="9096484883063264803">"Не атрымалася зрабіць здымак экрана"</string>
+ <string name="screenshot_failed_to_save_unknown_text" msgid="8844781948876286488">"Падчас захавання здымка экрана адбылася памылка"</string>
+ <string name="screenshot_failed_to_save_text" msgid="3041612585107107310">"Немагчыма захаваць здымак экрана, бо мала месца ў сховішчу"</string>
<string name="screenshot_failed_to_capture_text" msgid="173674476457581486">"Рабіць здымкі экрана не дазваляе праграма ці ваша арганізацыя"</string>
<string name="usb_preference_title" msgid="6551050377388882787">"Парам. перадачы файлаў па USB"</string>
<string name="use_mtp_button_title" msgid="4333504413563023626">"Падлучыць як медыяпрайгравальнік (ССП)"</string>
@@ -563,30 +567,19 @@
<string name="tuner_full_importance_settings_off" msgid="8208165412614935229">"Выключана"</string>
<string name="power_notification_controls_description" msgid="4372459941671353358">"З дапамогай пашыранага кіравання апавяшчэннямі вы можаце задаваць узровень важнасці апавяшчэнняў праграмы ад 0 да 5. \n\n"<b>"Узровень 5"</b>" \n- Паказваць уверсе спіса апавяшчэнняў \n- Дазваляць перапыняць рэжым поўнага экрана \n- Заўсёды дазваляць кароткі паказ \n\n"<b>"Узровень 4"</b>" \n- Забараняць перапыняць рэжым поўнага экрана \n- Заўсёды дазваляць кароткі паказ \n\n"<b>"Узровень 3"</b>" \n- Забараняць перапыняць рэжым поўнага экрана \n- Ніколі не дазваляць кароткі паказ \n\n"<b>"Узровень 2"</b>" \n- Забараняць перапыняць рэжым поўнага экрана \n- Ніколі не дазваляць кароткі паказ \n- Ніколі не прайграваць гук і не вібрыраваць \n\n"<b>"Узровень 1"</b>" \n- Забараняць перапыняць рэжым поўнага экрана \n- Ніколі не дазваляць кароткі паказ \n- Ніколі не прайграваць гук і не вібрыраваць \n- Хаваць з экрана блакіроўкі і панэлі стану \n- Паказваць унізе спіса апавяшчэнняў \n\n"<b>"Узровень 0"</b>" \n- Блакіраваць усе апавяшчэнні ад праграмы"</string>
<string name="notification_header_default_channel" msgid="7506845022070889909">"Апавяшчэнні"</string>
- <string name="notification_channel_disabled" msgid="2139193533791840539">"Вы больш не будзеце атрымліваць гэтыя апавяшчэнні"</string>
- <string name="notification_num_channels" msgid="2048144408999179471">"Катэгорый апавяшчэнняў: <xliff:g id="NUMBER">%d</xliff:g>"</string>
- <string name="notification_default_channel_desc" msgid="2506053815870808359">"У гэтай праграме няма катэгорый апавяшчэнняў"</string>
- <string name="notification_unblockable_desc" msgid="3561016061737896906">"Апавяшчэнні ад гэтай праграмы нельга адключыць"</string>
- <plurals name="notification_num_channels_desc" formatted="false" msgid="5492793452274077663">
- <item quantity="one">1 з <xliff:g id="NUMBER_1">%s</xliff:g> катэгорыі апавяшчэнняў у гэтай праграме</item>
- <item quantity="few">1 з <xliff:g id="NUMBER_1">%s</xliff:g> катэгорый апавяшчэнняў у гэтай праграме</item>
- <item quantity="many">1 з <xliff:g id="NUMBER_1">%s</xliff:g> катэгорый апавяшчэнняў у гэтай праграме</item>
- <item quantity="other">1 з <xliff:g id="NUMBER_1">%s</xliff:g> катэгорыі апавяшчэнняў у гэтай праграме</item>
- </plurals>
- <string name="notification_channels_list_desc_2" msgid="6214732715833946441">"<xliff:g id="CHANNEL_NAME_1">%1$s</xliff:g>, <xliff:g id="CHANNEL_NAME_2">%2$s</xliff:g>"</string>
- <plurals name="notification_channels_list_desc_2_and_others" formatted="false" msgid="2747813553355336157">
- <item quantity="one"><xliff:g id="CHANNEL_NAME_1_3">%1$s</xliff:g>, <xliff:g id="CHANNEL_NAME_2_4">%2$s</xliff:g> і яшчэ <xliff:g id="NUMBER_5">%3$d</xliff:g></item>
- <item quantity="few"><xliff:g id="CHANNEL_NAME_1_3">%1$s</xliff:g>, <xliff:g id="CHANNEL_NAME_2_4">%2$s</xliff:g> і яшчэ <xliff:g id="NUMBER_5">%3$d</xliff:g></item>
- <item quantity="many"><xliff:g id="CHANNEL_NAME_1_3">%1$s</xliff:g>, <xliff:g id="CHANNEL_NAME_2_4">%2$s</xliff:g> і яшчэ <xliff:g id="NUMBER_5">%3$d</xliff:g></item>
- <item quantity="other"><xliff:g id="CHANNEL_NAME_1_3">%1$s</xliff:g>, <xliff:g id="CHANNEL_NAME_2_4">%2$s</xliff:g> і яшчэ <xliff:g id="NUMBER_5">%3$d</xliff:g></item>
- </plurals>
+ <string name="notification_channel_disabled" msgid="344536703863700565">"Вы больш не будзеце бачыць гэты апавяшчэнні"</string>
+ <string name="inline_keep_showing" msgid="8945102997083836858">"Працягваць паказваць гэтыя апавяшчэнні?"</string>
+ <string name="inline_stop_button" msgid="4172980096860941033">"Спыніць апавяшчэнні"</string>
+ <string name="inline_keep_button" msgid="6665940297019018232">"Працягваць паказваць"</string>
+ <string name="inline_keep_showing_app" msgid="1723113469580031041">"Працягваць паказваць апавяшчэнні гэтай праграмы?"</string>
+ <string name="notification_unblockable_desc" msgid="1037434112919403708">"Немагчыма адключыць гэты апавяшчэнні"</string>
<string name="notification_channel_controls_opened_accessibility" msgid="6553950422055908113">"Кіраванне апавяшчэннямі для <xliff:g id="APP_NAME">%1$s</xliff:g> адкрыта"</string>
<string name="notification_channel_controls_closed_accessibility" msgid="7521619812603693144">"Кіраванне апавяшчэннямі для <xliff:g id="APP_NAME">%1$s</xliff:g> закрыта"</string>
<string name="notification_channel_switch_accessibility" msgid="3420796005601900717">"Дазволіць апавяшчэнні з гэтага канала"</string>
- <string name="notification_all_categories" msgid="5407190218055113282">"Усе катэгорыі"</string>
<string name="notification_more_settings" msgid="816306283396553571">"Дадатковыя налады"</string>
- <string name="notification_app_settings" msgid="3743278649182392015">"Персаналізаваць: <xliff:g id="SUB_CATEGORY">%1$s</xliff:g>"</string>
+ <string name="notification_app_settings" msgid="420348114670768449">"Наладзіць"</string>
<string name="notification_done" msgid="5279426047273930175">"Гатова"</string>
+ <string name="inline_undo" msgid="558916737624706010">"Адрабіць"</string>
<string name="notification_menu_accessibility" msgid="2046162834248888553">"<xliff:g id="APP_NAME">%1$s</xliff:g> <xliff:g id="MENU_DESCRIPTION">%2$s</xliff:g>"</string>
<string name="notification_menu_gear_description" msgid="2204480013726775108">"кіраванне апавяшчэннямі"</string>
<string name="notification_menu_snooze_description" msgid="3653669438131034525">"параметры адкладвання апавяшчэнняў"</string>
@@ -745,8 +738,7 @@
<string name="pip_phone_expand" msgid="5889780005575693909">"Разгарнуць"</string>
<string name="pip_phone_minimize" msgid="1079119422589131792">"Згарнуць"</string>
<string name="pip_phone_close" msgid="8416647892889710330">"Закрыць"</string>
- <!-- no translation found for pip_phone_settings (8080777499521528521) -->
- <skip />
+ <string name="pip_phone_settings" msgid="8080777499521528521">"Налады"</string>
<string name="pip_phone_dismiss_hint" msgid="6351678169095923899">"Перацягніце ўніз, каб адхіліць"</string>
<string name="pip_menu_title" msgid="4707292089961887657">"Меню"</string>
<string name="pip_notification_title" msgid="3204024940158161322">"<xliff:g id="NAME">%s</xliff:g> з’яўляецца відарысам у відарысе"</string>
diff --git a/packages/SystemUI/res/values-bg/strings.xml b/packages/SystemUI/res/values-bg/strings.xml
index 6a93d9e0a7f2..fbdf93cfc7ff 100644
--- a/packages/SystemUI/res/values-bg/strings.xml
+++ b/packages/SystemUI/res/values-bg/strings.xml
@@ -33,7 +33,10 @@
<string name="status_bar_ongoing_events_title" msgid="1682504513316879202">"В момента"</string>
<string name="status_bar_latest_events_title" msgid="6594767438577593172">"Известия"</string>
<string name="battery_low_title" msgid="6456385927409742437">"Батерията е изтощена"</string>
+ <string name="battery_low_title_hybrid" msgid="6268991275887381595">"Батерията е изтощена – включете режима за запазването й"</string>
<string name="battery_low_percent_format" msgid="2900940511201380775">"Остава/т <xliff:g id="PERCENTAGE">%s</xliff:g>"</string>
+ <string name="battery_low_percent_format_hybrid" msgid="6838677459286775617">"Остава/т <xliff:g id="PERCENTAGE">%s</xliff:g> – още около <xliff:g id="TIME">%s</xliff:g> въз основа на използването"</string>
+ <string name="battery_low_percent_format_hybrid_short" msgid="9025795469949145586">"Остава/т <xliff:g id="PERCENTAGE">%s</xliff:g> – още около <xliff:g id="TIME">%s</xliff:g>"</string>
<string name="battery_low_percent_format_saver_started" msgid="7879389868952879166">"Остава/т <xliff:g id="PERCENTAGE">%s</xliff:g>. Режимът за запазване на батерията е включен."</string>
<string name="invalid_charger" msgid="4549105996740522523">"Не се поддържа зареждане през USB.\nИзползвайте само доставеното зарядно устройство."</string>
<string name="invalid_charger_title" msgid="3515740382572798460">"Зареждането през USB не се поддържа."</string>
@@ -67,14 +70,15 @@
<string name="usb_debugging_secondary_user_message" msgid="6067122453571699801">"Потребителят, който понастоящем е влязъл в това устройство, не може да включи функцията за отстраняване на грешки през USB. За да я използвате, превключете към основния потребител."</string>
<string name="compat_mode_on" msgid="6623839244840638213">"Мащаб – запълва екрана"</string>
<string name="compat_mode_off" msgid="4434467572461327898">"Разпъване – запълва екрана"</string>
+ <string name="global_action_screenshot" msgid="8329831278085426283">"Екранна снимка"</string>
<string name="screenshot_saving_ticker" msgid="7403652894056693515">"Екранната снимка се запазва..."</string>
<string name="screenshot_saving_title" msgid="8242282144535555697">"Екранната снимка се запазва..."</string>
- <string name="screenshot_saving_text" msgid="2419718443411738818">"Екранната снимка се запазва."</string>
- <string name="screenshot_saved_title" msgid="6461865960961414961">"Екранната снимка е заснета."</string>
- <string name="screenshot_saved_text" msgid="2685605830386712477">"Докоснете, за да видите екранната снимка."</string>
- <string name="screenshot_failed_title" msgid="705781116746922771">"Екранната снимка не можа да бъде заснета."</string>
- <string name="screenshot_failed_to_save_unknown_text" msgid="7887826345701753830">"При запазването на екранната снимка възникна проблем."</string>
- <string name="screenshot_failed_to_save_text" msgid="2592658083866306296">"Екранната снимка не може да се запази поради ограничено място в хранилището."</string>
+ <string name="screenshot_saving_text" msgid="2545047868936087248">"Екранната снимка се запазва"</string>
+ <string name="screenshot_saved_title" msgid="5637073968117370753">"Екранната снимка е запазена"</string>
+ <string name="screenshot_saved_text" msgid="7574667448002050363">"Докоснете, за да видите екранната снимка"</string>
+ <string name="screenshot_failed_title" msgid="9096484883063264803">"Екранната снимка не можа да бъде направена"</string>
+ <string name="screenshot_failed_to_save_unknown_text" msgid="8844781948876286488">"При запазването на екранната снимка възникна проблем"</string>
+ <string name="screenshot_failed_to_save_text" msgid="3041612585107107310">"Екранната снимка не може да се запази поради ограничено място в хранилището"</string>
<string name="screenshot_failed_to_capture_text" msgid="173674476457581486">"Правенето на екранни снимки не е разрешено от приложението или организацията ви"</string>
<string name="usb_preference_title" msgid="6551050377388882787">"Опции за пренос на файлове чрез USB"</string>
<string name="use_mtp_button_title" msgid="4333504413563023626">"Свързване като медиен плейър (MTP)"</string>
@@ -557,26 +561,19 @@
<string name="tuner_full_importance_settings_off" msgid="8208165412614935229">"Изкл."</string>
<string name="power_notification_controls_description" msgid="4372459941671353358">"С помощта на контролите за известията можете да зададете ниво на важност от 0 до 5 за известията от дадено приложение. \n\n"<b>"Ниво 5"</b>" \n– Показване най-горе в списъка с известия. \n– Разрешаване на прекъсването на цял екран. \n– Известията винаги се показват мимолетно. \n\n"<b>"Ниво 4"</b>" \n– Предотвратяване на прекъсването на цял екран. \n– Известията винаги се показват мимолетно. \n\n"<b>"Ниво 3"</b>" \n– Предотвратяване на прекъсването на цял екран. \n– Известията никога не се показват мимолетно. \n\n"<b>"Ниво 2"</b>" \n– Предотвратяване на прекъсването на цял екран. \n– Известията никога не се показват мимолетно. \n– Без издаване на звуков сигнал и вибриране. \n\n"<b>"Ниво 1"</b>" \n– Предотвратяване на прекъсването на цял екран. \n– Известията никога не се показват мимолетно. \n– Без издаване на звуков сигнал и вибриране. \n– Скриване от заключения екран и лентата на състоянието. \n– Показване най-долу в списъка с известия. \n\n"<b>"Ниво 0"</b>" \n– Блокиране на всички известия от приложението."</string>
<string name="notification_header_default_channel" msgid="7506845022070889909">"Известия"</string>
- <string name="notification_channel_disabled" msgid="2139193533791840539">"Вече няма да получавате тези известия"</string>
- <string name="notification_num_channels" msgid="2048144408999179471">"<xliff:g id="NUMBER">%d</xliff:g> категории известия"</string>
- <string name="notification_default_channel_desc" msgid="2506053815870808359">"За това приложение няма категории на известията"</string>
- <string name="notification_unblockable_desc" msgid="3561016061737896906">"Известията от това приложение не могат да бъдат изключени"</string>
- <plurals name="notification_num_channels_desc" formatted="false" msgid="5492793452274077663">
- <item quantity="other">1 от <xliff:g id="NUMBER_1">%s</xliff:g> категории известия от това приложение</item>
- <item quantity="one">1 от <xliff:g id="NUMBER_0">%s</xliff:g> категория известия от това приложение</item>
- </plurals>
- <string name="notification_channels_list_desc_2" msgid="6214732715833946441">"„<xliff:g id="CHANNEL_NAME_1">%1$s</xliff:g>“, „<xliff:g id="CHANNEL_NAME_2">%2$s</xliff:g>“"</string>
- <plurals name="notification_channels_list_desc_2_and_others" formatted="false" msgid="2747813553355336157">
- <item quantity="other">„<xliff:g id="CHANNEL_NAME_1_3">%1$s</xliff:g>“, „<xliff:g id="CHANNEL_NAME_2_4">%2$s</xliff:g>“ и още <xliff:g id="NUMBER_5">%3$d</xliff:g></item>
- <item quantity="one">„<xliff:g id="CHANNEL_NAME_1_0">%1$s</xliff:g>“, „<xliff:g id="CHANNEL_NAME_2_1">%2$s</xliff:g>“ и още <xliff:g id="NUMBER_2">%3$d</xliff:g></item>
- </plurals>
+ <string name="notification_channel_disabled" msgid="344536703863700565">"Вече няма да виждате тези известия"</string>
+ <string name="inline_keep_showing" msgid="8945102997083836858">"Тези известия да продължат ли да се показват?"</string>
+ <string name="inline_stop_button" msgid="4172980096860941033">"Спиране на известията"</string>
+ <string name="inline_keep_button" msgid="6665940297019018232">"Да продължат да се показват"</string>
+ <string name="inline_keep_showing_app" msgid="1723113469580031041">"Да продължат ли да се показват известията от това приложение?"</string>
+ <string name="notification_unblockable_desc" msgid="1037434112919403708">"Тези известия не могат да бъдат изключени"</string>
<string name="notification_channel_controls_opened_accessibility" msgid="6553950422055908113">"Контролите за известията за <xliff:g id="APP_NAME">%1$s</xliff:g> са оттворени"</string>
<string name="notification_channel_controls_closed_accessibility" msgid="7521619812603693144">"Контролите за известията за <xliff:g id="APP_NAME">%1$s</xliff:g> са затворени"</string>
<string name="notification_channel_switch_accessibility" msgid="3420796005601900717">"Разрешаване на известия от този канал"</string>
- <string name="notification_all_categories" msgid="5407190218055113282">"Всички категории"</string>
<string name="notification_more_settings" msgid="816306283396553571">"Още настройки"</string>
- <string name="notification_app_settings" msgid="3743278649182392015">"Персонализиране: <xliff:g id="SUB_CATEGORY">%1$s</xliff:g>"</string>
+ <string name="notification_app_settings" msgid="420348114670768449">"Персонализиране"</string>
<string name="notification_done" msgid="5279426047273930175">"Готово"</string>
+ <string name="inline_undo" msgid="558916737624706010">"Отмяна"</string>
<string name="notification_menu_accessibility" msgid="2046162834248888553">"<xliff:g id="MENU_DESCRIPTION">%2$s</xliff:g> от <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
<string name="notification_menu_gear_description" msgid="2204480013726775108">"контроли за известията"</string>
<string name="notification_menu_snooze_description" msgid="3653669438131034525">"опции за отлагане на известията"</string>
@@ -731,8 +728,7 @@
<string name="pip_phone_expand" msgid="5889780005575693909">"Разгъване"</string>
<string name="pip_phone_minimize" msgid="1079119422589131792">"Намаляване"</string>
<string name="pip_phone_close" msgid="8416647892889710330">"Затваряне"</string>
- <!-- no translation found for pip_phone_settings (8080777499521528521) -->
- <skip />
+ <string name="pip_phone_settings" msgid="8080777499521528521">"Настройки"</string>
<string name="pip_phone_dismiss_hint" msgid="6351678169095923899">"Преместете надолу с плъзгане, за да отхвърлите"</string>
<string name="pip_menu_title" msgid="4707292089961887657">"Меню"</string>
<string name="pip_notification_title" msgid="3204024940158161322">"<xliff:g id="NAME">%s</xliff:g> е в режима „Картина в картината“"</string>
diff --git a/packages/SystemUI/res/values-bn/strings.xml b/packages/SystemUI/res/values-bn/strings.xml
index 4b163ec9b5d4..a8e0c2b1430c 100644
--- a/packages/SystemUI/res/values-bn/strings.xml
+++ b/packages/SystemUI/res/values-bn/strings.xml
@@ -33,7 +33,13 @@
<string name="status_bar_ongoing_events_title" msgid="1682504513316879202">"চলতে-থাকা"</string>
<string name="status_bar_latest_events_title" msgid="6594767438577593172">"বিজ্ঞপ্তিগুলি"</string>
<string name="battery_low_title" msgid="6456385927409742437">"ব্যাটারি কম"</string>
+ <!-- no translation found for battery_low_title_hybrid (6268991275887381595) -->
+ <skip />
<string name="battery_low_percent_format" msgid="2900940511201380775">"<xliff:g id="PERCENTAGE">%s</xliff:g> অবশিষ্ট আছে"</string>
+ <!-- no translation found for battery_low_percent_format_hybrid (6838677459286775617) -->
+ <skip />
+ <!-- no translation found for battery_low_percent_format_hybrid_short (9025795469949145586) -->
+ <skip />
<string name="battery_low_percent_format_saver_started" msgid="7879389868952879166">"<xliff:g id="PERCENTAGE">%s</xliff:g> অবশিষ্ট আছে। ব্যাটারি সেভার চালু আছে।"</string>
<string name="invalid_charger" msgid="4549105996740522523">"USB চার্জিং সমর্থিত নয়৷\nকেবলমাত্র সরবহারকৃত চার্জার ব্যবহার করুন৷"</string>
<string name="invalid_charger_title" msgid="3515740382572798460">"USB চার্জিং সমর্থিত নয়।"</string>
@@ -67,14 +73,22 @@
<string name="usb_debugging_secondary_user_message" msgid="6067122453571699801">"ব্যবহারকারী এখন এই ডিভাইসে সাইন-ইন করেছেন তাই USB ডিবাগিং চালু করা যাবে না। এই বৈশিষ্ট্যটি ব্যবহার করতে, প্রাথমিক ব্যবহারকারীতে পাল্টে নিন।"</string>
<string name="compat_mode_on" msgid="6623839244840638213">"স্ক্রীণ পূরণ করতে জুম করুন"</string>
<string name="compat_mode_off" msgid="4434467572461327898">"ফুল স্ক্রিন করুন"</string>
+ <!-- no translation found for global_action_screenshot (8329831278085426283) -->
+ <skip />
<string name="screenshot_saving_ticker" msgid="7403652894056693515">"স্ক্রিনশট সেভ করা হচ্ছে..."</string>
<string name="screenshot_saving_title" msgid="8242282144535555697">"স্ক্রিনশট সেভ করা হচ্ছে..."</string>
- <string name="screenshot_saving_text" msgid="2419718443411738818">"স্ক্রিনশট সেভ করা হচ্ছে৷"</string>
- <string name="screenshot_saved_title" msgid="6461865960961414961">"স্ক্রিনশট নেওয়া হযেছে৷"</string>
- <string name="screenshot_saved_text" msgid="2685605830386712477">"আপনার স্ক্রিনশট দেখতে আলতো চাপ দিন৷"</string>
- <string name="screenshot_failed_title" msgid="705781116746922771">"স্ক্রিনশট নেওয়া যায়নি৷"</string>
- <string name="screenshot_failed_to_save_unknown_text" msgid="7887826345701753830">"স্ক্রিনশট সেভের সময়ে সমস্যা হয়েছে৷"</string>
- <string name="screenshot_failed_to_save_text" msgid="2592658083866306296">"স্টোরেজ সীমিত থাকায় স্ক্রিনশটটি সেভ করা যাবে না৷"</string>
+ <!-- no translation found for screenshot_saving_text (2545047868936087248) -->
+ <skip />
+ <!-- no translation found for screenshot_saved_title (5637073968117370753) -->
+ <skip />
+ <!-- no translation found for screenshot_saved_text (7574667448002050363) -->
+ <skip />
+ <!-- no translation found for screenshot_failed_title (9096484883063264803) -->
+ <skip />
+ <!-- no translation found for screenshot_failed_to_save_unknown_text (8844781948876286488) -->
+ <skip />
+ <!-- no translation found for screenshot_failed_to_save_text (3041612585107107310) -->
+ <skip />
<string name="screenshot_failed_to_capture_text" msgid="173674476457581486">"এই অ্যাপ বা আপনার প্রতিষ্ঠান স্ক্রিনশট নেওয়ার অনুমতি দেয়নি"</string>
<string name="usb_preference_title" msgid="6551050377388882787">"USB ফাইল স্থানান্তরের বিকল্পগুলি"</string>
<string name="use_mtp_button_title" msgid="4333504413563023626">"একটি মিডিয়া প্লেয়ার হিসেবে মাউন্ট করুন (MTP)"</string>
@@ -557,26 +571,27 @@
<string name="tuner_full_importance_settings_off" msgid="8208165412614935229">"বন্ধ আছে"</string>
<string name="power_notification_controls_description" msgid="4372459941671353358">"পাওয়ার বিজ্ঞপ্তির নিয়ন্ত্রণগুলি ব্যহবার করে, আপনি কোনও অ্যাপ্লিকেশনের বিজ্ঞপ্তির জন্য ০ থেকে ৫ পর্যন্ত একটি গুরুত্বের লেভেলকে সেট করতে পারবেন৷ \n\n"<b>"লেভেল ৫"</b>" \n- বিজ্ঞপ্তি তালিকার শীর্ষে দেখায় \n- পূর্ণ স্ক্রিনের বাধাকে অনুমতি দেয় \n- সর্বদা স্ক্রিনে উপস্থিত হয় \n\n"<b>"লেভেল ৪"</b>" \n- পূর্ণ স্ক্রিনের বাধাকে আটকায় \n- সর্বদা স্ক্রিনে উপস্থিত হয় \n\n"<b>"লেভেল ৩"</b>" \n- পূর্ণ স্ক্রিনের বাধাকে আটকায় \n- কখনওই স্ক্রিনে উপস্থিত হয় না \n\n"<b>"লেভেল ২"</b>" \n- পূর্ণ স্ক্রিনের বাধাকে আটকায় \n- কখনওই স্ক্রিনে উপস্থিত হয় না \n- কখনওই শব্দ এবং কম্পন করে না \n\n"<b>"লেভেল ১"</b>" \n- পূর্ণ স্ক্রিনের বাধাকে আটকায় \n- কখনওই স্ক্রিনে উপস্থিত হয় না \n- কখনওই শব্দ এবং কম্পন করে না \n- লক স্ক্রিন এবং স্ট্যাটাস বার থেকে লুকায় \n- বিজ্ঞপ্তি তালিকার নীচের দিকে দেখায় \n\n"<b>"লেভেল ০"</b>" \n- অ্যাপ্লিকেশন থেকে সমস্ত বিজ্ঞপ্তিকে অবরূদ্ধ করে"</string>
<string name="notification_header_default_channel" msgid="7506845022070889909">"বিজ্ঞপ্তি"</string>
- <string name="notification_channel_disabled" msgid="2139193533791840539">"আপনি এই বিজ্ঞপ্তিগুলি আর পাবেন না"</string>
- <string name="notification_num_channels" msgid="2048144408999179471">"<xliff:g id="NUMBER">%d</xliff:g> বিজ্ঞপ্তির বিভাগগুলি"</string>
- <string name="notification_default_channel_desc" msgid="2506053815870808359">"এই অ্যাপটিতে বিজ্ঞপ্তির বিভাগ নেই"</string>
- <string name="notification_unblockable_desc" msgid="3561016061737896906">"এই অ্যাপ থেকে আসা বিজ্ঞপ্তি বন্ধ করা যাবে না"</string>
- <plurals name="notification_num_channels_desc" formatted="false" msgid="5492793452274077663">
- <item quantity="one">এই অ্যাপের <xliff:g id="NUMBER_1">%s</xliff:g>টি বিজ্ঞপ্তির বিভাগের মধ্যে ১টি</item>
- <item quantity="other">এই অ্যাপের <xliff:g id="NUMBER_1">%s</xliff:g>টি বিজ্ঞপ্তির বিভাগের মধ্যে ১টি</item>
- </plurals>
- <string name="notification_channels_list_desc_2" msgid="6214732715833946441">"<xliff:g id="CHANNEL_NAME_1">%1$s</xliff:g>, <xliff:g id="CHANNEL_NAME_2">%2$s</xliff:g>"</string>
- <plurals name="notification_channels_list_desc_2_and_others" formatted="false" msgid="2747813553355336157">
- <item quantity="one"><xliff:g id="CHANNEL_NAME_1_3">%1$s</xliff:g>, <xliff:g id="CHANNEL_NAME_2_4">%2$s</xliff:g>, এবং আরও <xliff:g id="NUMBER_5">%3$d</xliff:g>টি</item>
- <item quantity="other"><xliff:g id="CHANNEL_NAME_1_3">%1$s</xliff:g>, <xliff:g id="CHANNEL_NAME_2_4">%2$s</xliff:g>, এবং আরও <xliff:g id="NUMBER_5">%3$d</xliff:g>টি</item>
- </plurals>
+ <!-- no translation found for notification_channel_disabled (344536703863700565) -->
+ <skip />
+ <!-- no translation found for inline_keep_showing (8945102997083836858) -->
+ <skip />
+ <!-- no translation found for inline_stop_button (4172980096860941033) -->
+ <skip />
+ <!-- no translation found for inline_keep_button (6665940297019018232) -->
+ <skip />
+ <!-- no translation found for inline_keep_showing_app (1723113469580031041) -->
+ <skip />
+ <!-- no translation found for notification_unblockable_desc (1037434112919403708) -->
+ <skip />
<string name="notification_channel_controls_opened_accessibility" msgid="6553950422055908113">"<xliff:g id="APP_NAME">%1$s</xliff:g> খোলা থাকলে বিজ্ঞপ্তি নিয়ন্ত্রণ"</string>
<string name="notification_channel_controls_closed_accessibility" msgid="7521619812603693144">"<xliff:g id="APP_NAME">%1$s</xliff:g> বন্ধ থাকলে বিজ্ঞপ্তি নিয়ন্ত্রণ"</string>
<string name="notification_channel_switch_accessibility" msgid="3420796005601900717">"এই চ্যানেল থেকে বিজ্ঞপ্তি আসতে দেয়"</string>
- <string name="notification_all_categories" msgid="5407190218055113282">"সকল বিভাগ"</string>
<string name="notification_more_settings" msgid="816306283396553571">"আরও সেটিংস"</string>
- <string name="notification_app_settings" msgid="3743278649182392015">"কাস্টমাইজ করুন: <xliff:g id="SUB_CATEGORY">%1$s</xliff:g>"</string>
+ <!-- no translation found for notification_app_settings (420348114670768449) -->
+ <skip />
<string name="notification_done" msgid="5279426047273930175">"সম্পন্ন"</string>
+ <!-- no translation found for inline_undo (558916737624706010) -->
+ <skip />
<string name="notification_menu_accessibility" msgid="2046162834248888553">"<xliff:g id="APP_NAME">%1$s</xliff:g> <xliff:g id="MENU_DESCRIPTION">%2$s</xliff:g>"</string>
<string name="notification_menu_gear_description" msgid="2204480013726775108">"বিজ্ঞপ্তির নিয়ন্ত্রণগুলি"</string>
<string name="notification_menu_snooze_description" msgid="3653669438131034525">"বিজ্ঞপ্তি মনে করিয়ে দেওয়ার বিকল্পগুলি"</string>
@@ -731,8 +746,7 @@
<string name="pip_phone_expand" msgid="5889780005575693909">"বড় করুন"</string>
<string name="pip_phone_minimize" msgid="1079119422589131792">"ছোটো করুন"</string>
<string name="pip_phone_close" msgid="8416647892889710330">"বন্ধ করুন"</string>
- <!-- no translation found for pip_phone_settings (8080777499521528521) -->
- <skip />
+ <string name="pip_phone_settings" msgid="8080777499521528521">"সেটিংস"</string>
<string name="pip_phone_dismiss_hint" msgid="6351678169095923899">"খারিজ করতে নিচের দিকে টেনে আনুন"</string>
<string name="pip_menu_title" msgid="4707292089961887657">"মেনু"</string>
<string name="pip_notification_title" msgid="3204024940158161322">"ছবির-মধ্যে-ছবি তে <xliff:g id="NAME">%s</xliff:g> আছেন"</string>
diff --git a/packages/SystemUI/res/values-bs/strings.xml b/packages/SystemUI/res/values-bs/strings.xml
index fc246c406159..69b8fbed5342 100644
--- a/packages/SystemUI/res/values-bs/strings.xml
+++ b/packages/SystemUI/res/values-bs/strings.xml
@@ -34,7 +34,10 @@
<string name="status_bar_ongoing_events_title" msgid="1682504513316879202">"U toku"</string>
<string name="status_bar_latest_events_title" msgid="6594767438577593172">"Obavještenja"</string>
<string name="battery_low_title" msgid="6456385927409742437">"Baterija je skoro prazna"</string>
+ <string name="battery_low_title_hybrid" msgid="6268991275887381595">"Baterija je skoro prazna. Uključite Uštedu baterije"</string>
<string name="battery_low_percent_format" msgid="2900940511201380775">"Preostalo <xliff:g id="PERCENTAGE">%s</xliff:g>"</string>
+ <string name="battery_low_percent_format_hybrid" msgid="6838677459286775617">"Još <xliff:g id="PERCENTAGE">%s</xliff:g>. Preostalo je oko <xliff:g id="TIME">%s</xliff:g>, na osnovu vašeg korištenja"</string>
+ <string name="battery_low_percent_format_hybrid_short" msgid="9025795469949145586">"Još <xliff:g id="PERCENTAGE">%s</xliff:g>. Preostalo je oko <xliff:g id="TIME">%s</xliff:g>"</string>
<string name="battery_low_percent_format_saver_started" msgid="7879389868952879166">"Preostalo <xliff:g id="PERCENTAGE">%s</xliff:g>. Uključena je Ušteda baterije."</string>
<string name="invalid_charger" msgid="4549105996740522523">"USB punjenje nije podržano.\nKoristite samo priloženi punjač."</string>
<string name="invalid_charger_title" msgid="3515740382572798460">"Punjenje pomoću USB-a nije podržano."</string>
@@ -68,14 +71,15 @@
<string name="usb_debugging_secondary_user_message" msgid="6067122453571699801">"Korisnik koji je trenutno prijavljen na ovaj uređaj ne može uključiti opciju za otklanjanje grešaka koristeći USB. Da koristite tu funkciju, prebacite se na primarnog korisnika."</string>
<string name="compat_mode_on" msgid="6623839244840638213">"Uvećaj prikaz na ekran"</string>
<string name="compat_mode_off" msgid="4434467572461327898">"Razvuci prikaz na ekran"</string>
+ <string name="global_action_screenshot" msgid="8329831278085426283">"Snimak ekrana"</string>
<string name="screenshot_saving_ticker" msgid="7403652894056693515">"Spašavanje snimka ekrana..."</string>
<string name="screenshot_saving_title" msgid="8242282144535555697">"Spašavanje snimka ekrana..."</string>
- <string name="screenshot_saving_text" msgid="2419718443411738818">"Spašavanje snimka ekrana u toku."</string>
- <string name="screenshot_saved_title" msgid="6461865960961414961">"Ekran snimljen."</string>
- <string name="screenshot_saved_text" msgid="2685605830386712477">"Dodirnite za prikaz snimka ekrana."</string>
- <string name="screenshot_failed_title" msgid="705781116746922771">"Došlo je do greške prilikom snimanja ekrana."</string>
- <string name="screenshot_failed_to_save_unknown_text" msgid="7887826345701753830">"Došlo je do problema prilikom spašavanja snimka ekrana."</string>
- <string name="screenshot_failed_to_save_text" msgid="2592658083866306296">"Snimak ekrana se ne može sačuvati zbog manjka prostora za pohranu."</string>
+ <string name="screenshot_saving_text" msgid="2545047868936087248">"Snimak ekrana se čuva"</string>
+ <string name="screenshot_saved_title" msgid="5637073968117370753">"Snimak ekrana je sačuvan"</string>
+ <string name="screenshot_saved_text" msgid="7574667448002050363">"Dodirnite za prikaz snimka ekrana"</string>
+ <string name="screenshot_failed_title" msgid="9096484883063264803">"Pravljenje snimka ekrana nije uspjelo"</string>
+ <string name="screenshot_failed_to_save_unknown_text" msgid="8844781948876286488">"Došlo je do problema prilikom čuvanja snimka ekrana"</string>
+ <string name="screenshot_failed_to_save_text" msgid="3041612585107107310">"Snimak ekrana se ne može sačuvati zbog manjka prostora za pohranu"</string>
<string name="screenshot_failed_to_capture_text" msgid="173674476457581486">"Ova aplikacija ili vaša organizacija ne dozvoljavaju snimanje ekrana"</string>
<string name="usb_preference_title" msgid="6551050377388882787">"Opcije USB prijenosa fajlova"</string>
<string name="use_mtp_button_title" msgid="4333504413563023626">"Reproduciranje medijskih sadržaja (MTP)"</string>
@@ -561,28 +565,19 @@
<string name="tuner_full_importance_settings_off" msgid="8208165412614935229">"Isključeno"</string>
<string name="power_notification_controls_description" msgid="4372459941671353358">"Uz kontrolu obavještenja o napajanju, možete postaviti nivo značaja obavještenja iz aplikacije, i to od nivoa 0 do 5. \n\n"<b>"Nivo 5"</b>" \n- Prikaži na vrhu liste obavještenja \n- Dopusti prekid prikaza cijelog ekrana \n- Uvijek izviruj \n\n"<b>"Nvio 4"</b>" \n- Spriječi prekid prikaza cijelog ekrana \n- Uvijek izviruj \n\n"<b>"Nivo 3"</b>" \n- Spriječi prekid prikaza cijelog ekrana \n- Nikad ne izviruj \n\n"<b>"Nivo 2"</b>" \n- Spriječi prekid prikaza cijelog ekrana \n- Nikad ne izviruj \n- Nikada ne puštaj zvuk ili vibraciju \n\n"<b>"Nivo 1"</b>" \n- Spriječi prekid prikaza cijelog ekrana \n- Nikada ne izviruj \n- Nikada ne puštaj zvuk ili vibraciju \n- Sakrij sa ekrana za zaključavanje i statusne trake \n- Prikaži na dnu liste obavještenja \n\n"<b>"Nivo 0"</b>" \n- Blokiraj sva obavještenja iz aplikacije"</string>
<string name="notification_header_default_channel" msgid="7506845022070889909">"Obavještenja"</string>
- <string name="notification_channel_disabled" msgid="2139193533791840539">"Nećete više primati ova obavještenja"</string>
- <string name="notification_num_channels" msgid="2048144408999179471">"Kategorije obavještenja: <xliff:g id="NUMBER">%d</xliff:g>"</string>
- <string name="notification_default_channel_desc" msgid="2506053815870808359">"Ova aplikacija nema kategorije obavještenja"</string>
- <string name="notification_unblockable_desc" msgid="3561016061737896906">"Obavještenja iz ove aplikacije nije moguće isključiti"</string>
- <plurals name="notification_num_channels_desc" formatted="false" msgid="5492793452274077663">
- <item quantity="one">1 od <xliff:g id="NUMBER_1">%s</xliff:g> kategorije obavještenja iz ove aplikacije</item>
- <item quantity="few">1 od <xliff:g id="NUMBER_1">%s</xliff:g> kategorije obavještenja iz ove aplikacije</item>
- <item quantity="other">1 od <xliff:g id="NUMBER_1">%s</xliff:g> kategorija obavještenja iz ove aplikacije</item>
- </plurals>
- <string name="notification_channels_list_desc_2" msgid="6214732715833946441">"<xliff:g id="CHANNEL_NAME_1">%1$s</xliff:g>, <xliff:g id="CHANNEL_NAME_2">%2$s</xliff:g>"</string>
- <plurals name="notification_channels_list_desc_2_and_others" formatted="false" msgid="2747813553355336157">
- <item quantity="one"><xliff:g id="CHANNEL_NAME_1_3">%1$s</xliff:g>, <xliff:g id="CHANNEL_NAME_2_4">%2$s</xliff:g>, i još <xliff:g id="NUMBER_5">%3$d</xliff:g></item>
- <item quantity="few"><xliff:g id="CHANNEL_NAME_1_3">%1$s</xliff:g>, <xliff:g id="CHANNEL_NAME_2_4">%2$s</xliff:g>, i još <xliff:g id="NUMBER_5">%3$d</xliff:g></item>
- <item quantity="other"><xliff:g id="CHANNEL_NAME_1_3">%1$s</xliff:g>, <xliff:g id="CHANNEL_NAME_2_4">%2$s</xliff:g>, i još <xliff:g id="NUMBER_5">%3$d</xliff:g></item>
- </plurals>
+ <string name="notification_channel_disabled" msgid="344536703863700565">"Nećete više vidjeti ova obavještenja"</string>
+ <string name="inline_keep_showing" msgid="8945102997083836858">"Nastaviti prikazivanje ovih obavještenja?"</string>
+ <string name="inline_stop_button" msgid="4172980096860941033">"Zaustavi obavještenja"</string>
+ <string name="inline_keep_button" msgid="6665940297019018232">"Nastavi prikazivanje"</string>
+ <string name="inline_keep_showing_app" msgid="1723113469580031041">"Nastaviti prikazivanje obavještenja iz ove aplikacije?"</string>
+ <string name="notification_unblockable_desc" msgid="1037434112919403708">"Ova obavještenja nije moguće isključiti"</string>
<string name="notification_channel_controls_opened_accessibility" msgid="6553950422055908113">"Otvorene su kontrole obavještenja za aplikaciju <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
<string name="notification_channel_controls_closed_accessibility" msgid="7521619812603693144">"Zatvorene su kontrole obavještenja za aplikaciju <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
<string name="notification_channel_switch_accessibility" msgid="3420796005601900717">"Dozvoli obavještenja s ovog kanala"</string>
- <string name="notification_all_categories" msgid="5407190218055113282">"Sve kategorije"</string>
<string name="notification_more_settings" msgid="816306283396553571">"Više postavki"</string>
- <string name="notification_app_settings" msgid="3743278649182392015">"Prilagodite: <xliff:g id="SUB_CATEGORY">%1$s</xliff:g>"</string>
+ <string name="notification_app_settings" msgid="420348114670768449">"Prilagodi"</string>
<string name="notification_done" msgid="5279426047273930175">"Gotovo"</string>
+ <string name="inline_undo" msgid="558916737624706010">"Opozovi"</string>
<string name="notification_menu_accessibility" msgid="2046162834248888553">"<xliff:g id="APP_NAME">%1$s</xliff:g> <xliff:g id="MENU_DESCRIPTION">%2$s</xliff:g>"</string>
<string name="notification_menu_gear_description" msgid="2204480013726775108">"kontrole obavještenja"</string>
<string name="notification_menu_snooze_description" msgid="3653669438131034525">"opcije za odgodu obavještenja"</string>
@@ -739,8 +734,7 @@
<string name="pip_phone_expand" msgid="5889780005575693909">"Proširi"</string>
<string name="pip_phone_minimize" msgid="1079119422589131792">"Umanji"</string>
<string name="pip_phone_close" msgid="8416647892889710330">"Zatvori"</string>
- <!-- no translation found for pip_phone_settings (8080777499521528521) -->
- <skip />
+ <string name="pip_phone_settings" msgid="8080777499521528521">"Postavke"</string>
<string name="pip_phone_dismiss_hint" msgid="6351678169095923899">"Povucite prema dolje da odbacite"</string>
<string name="pip_menu_title" msgid="4707292089961887657">"Meni"</string>
<string name="pip_notification_title" msgid="3204024940158161322">"<xliff:g id="NAME">%s</xliff:g> je u načinu priakza Slika u slici"</string>
diff --git a/packages/SystemUI/res/values-ca/strings.xml b/packages/SystemUI/res/values-ca/strings.xml
index 4ff8e2c55deb..d61d15e6c4c7 100644
--- a/packages/SystemUI/res/values-ca/strings.xml
+++ b/packages/SystemUI/res/values-ca/strings.xml
@@ -33,7 +33,10 @@
<string name="status_bar_ongoing_events_title" msgid="1682504513316879202">"Continu"</string>
<string name="status_bar_latest_events_title" msgid="6594767438577593172">"Notificacions"</string>
<string name="battery_low_title" msgid="6456385927409742437">"Queda poca bateria"</string>
+ <string name="battery_low_title_hybrid" msgid="6268991275887381595">"Queda poca bateria. Activa el mode Estalvi de bateria."</string>
<string name="battery_low_percent_format" msgid="2900940511201380775">"Queda un <xliff:g id="PERCENTAGE">%s</xliff:g>."</string>
+ <string name="battery_low_percent_format_hybrid" msgid="6838677459286775617">"Queda un <xliff:g id="PERCENTAGE">%s</xliff:g>; temps restant aproximat segons l\'ús que en fas: <xliff:g id="TIME">%s</xliff:g>"</string>
+ <string name="battery_low_percent_format_hybrid_short" msgid="9025795469949145586">"Queda un <xliff:g id="PERCENTAGE">%s</xliff:g>; temps restant aproximat: <xliff:g id="TIME">%s</xliff:g>"</string>
<string name="battery_low_percent_format_saver_started" msgid="7879389868952879166">"Queda un <xliff:g id="PERCENTAGE">%s</xliff:g>. La funció Estalvi de bateria està activada."</string>
<string name="invalid_charger" msgid="4549105996740522523">"Pujada d\'USB no admesa.\nUtilitza només el carregador proporcionat."</string>
<string name="invalid_charger_title" msgid="3515740382572798460">"La pujada per USB no és compatible."</string>
@@ -67,14 +70,15 @@
<string name="usb_debugging_secondary_user_message" msgid="6067122453571699801">"L\'usuari que té iniciada la sessió al dispositiu en aquest moment no pot activar la depuració per USB. Per utilitzar aquesta funció, cal canviar a l\'usuari principal."</string>
<string name="compat_mode_on" msgid="6623839244840638213">"Zoom per omplir pantalla"</string>
<string name="compat_mode_off" msgid="4434467572461327898">"Estira per omplir pant."</string>
+ <string name="global_action_screenshot" msgid="8329831278085426283">"Captura de pantalla"</string>
<string name="screenshot_saving_ticker" msgid="7403652894056693515">"S\'està desant captura de pantalla..."</string>
<string name="screenshot_saving_title" msgid="8242282144535555697">"S\'està desant la captura de pantalla..."</string>
- <string name="screenshot_saving_text" msgid="2419718443411738818">"La captura de pantalla s\'ha desat."</string>
- <string name="screenshot_saved_title" msgid="6461865960961414961">"S\'ha fet una captura de pantalla."</string>
- <string name="screenshot_saved_text" msgid="2685605830386712477">"Toca la notificació per veure la captura de pantalla."</string>
- <string name="screenshot_failed_title" msgid="705781116746922771">"No s\'ha pogut fer una captura de pantalla."</string>
- <string name="screenshot_failed_to_save_unknown_text" msgid="7887826345701753830">"S\'ha trobat un problema en desar la captura de pantalla."</string>
- <string name="screenshot_failed_to_save_text" msgid="2592658083866306296">"La captura de pantalla no es pot desar perquè no hi ha prou espai d\'emmagatzematge."</string>
+ <string name="screenshot_saving_text" msgid="2545047868936087248">"S\'està desant la captura de pantalla"</string>
+ <string name="screenshot_saved_title" msgid="5637073968117370753">"S\'ha desat la captura de pantalla"</string>
+ <string name="screenshot_saved_text" msgid="7574667448002050363">"Toca per veure la captura de pantalla"</string>
+ <string name="screenshot_failed_title" msgid="9096484883063264803">"No s\'ha pogut fer la captura de pantalla"</string>
+ <string name="screenshot_failed_to_save_unknown_text" msgid="8844781948876286488">"S\'ha trobat un problema en desar la captura de pantalla"</string>
+ <string name="screenshot_failed_to_save_text" msgid="3041612585107107310">"La captura de pantalla no es pot desar perquè no hi ha prou espai d\'emmagatzematge"</string>
<string name="screenshot_failed_to_capture_text" msgid="173674476457581486">"L\'aplicació o la teva organització no permeten fer captures de pantalla"</string>
<string name="usb_preference_title" msgid="6551050377388882787">"Opcions transf. fitxers USB"</string>
<string name="use_mtp_button_title" msgid="4333504413563023626">"Munta com a reproductor multimèdia (MTP)"</string>
@@ -557,26 +561,19 @@
<string name="tuner_full_importance_settings_off" msgid="8208165412614935229">"Desactivat"</string>
<string name="power_notification_controls_description" msgid="4372459941671353358">"Amb els controls de notificació millorats, pots establir un nivell d\'importància d\'entre 0 i 5 per a les notificacions d\'una aplicació. \n\n"<b>"Nivell 5"</b>" \n- Mostra les notificacions a la part superior de la llista \n- Permet la interrupció de la pantalla completa \n- Permet sempre la previsualització \n\n"<b>"Nivell 4"</b>" \n- No permet la interrupció de la pantalla completa \n- Permet sempre la previsualització \n\n"<b>"Nivell 3"</b>" \n- No permet la interrupció de la pantalla completa \n- No permet mai la previsualització \n\n"<b>"Nivell 2"</b>" \n- No permet la interrupció de la pantalla completa \n- No permet mai la previsualització \n- Les notificacions no poden emetre sons ni vibracions \n\n"<b>"Nivell 1"</b>" \n- No permet la interrupció de la pantalla completa \n- No permet mai la previsualització \n- No activa mai el so ni la vibració \n- Amaga les notificacions de la pantalla de bloqueig i de la barra d\'estat \n- Mostra les notificacions a la part inferior de la llista \n\n"<b>"Nivell 0"</b>" \n- Bloqueja totes les notificacions de l\'aplicació"</string>
<string name="notification_header_default_channel" msgid="7506845022070889909">"Notificacions"</string>
- <string name="notification_channel_disabled" msgid="2139193533791840539">"Ja no rebràs aquestes notificacions"</string>
- <string name="notification_num_channels" msgid="2048144408999179471">"<xliff:g id="NUMBER">%d</xliff:g> categories de notificació"</string>
- <string name="notification_default_channel_desc" msgid="2506053815870808359">"Aquesta aplicació no té categories de notificació"</string>
- <string name="notification_unblockable_desc" msgid="3561016061737896906">"Les notificacions d\'aquesta aplicació no es poden desactivar"</string>
- <plurals name="notification_num_channels_desc" formatted="false" msgid="5492793452274077663">
- <item quantity="other">1 de <xliff:g id="NUMBER_1">%s</xliff:g> categories de notificació d\'aquesta aplicació</item>
- <item quantity="one">1 de <xliff:g id="NUMBER_0">%s</xliff:g> categoria de notificació d\'aquesta aplicació</item>
- </plurals>
- <string name="notification_channels_list_desc_2" msgid="6214732715833946441">"<xliff:g id="CHANNEL_NAME_1">%1$s</xliff:g>, <xliff:g id="CHANNEL_NAME_2">%2$s</xliff:g>"</string>
- <plurals name="notification_channels_list_desc_2_and_others" formatted="false" msgid="2747813553355336157">
- <item quantity="other"><xliff:g id="CHANNEL_NAME_1_3">%1$s</xliff:g>, <xliff:g id="CHANNEL_NAME_2_4">%2$s</xliff:g> i <xliff:g id="NUMBER_5">%3$d</xliff:g> més</item>
- <item quantity="one"><xliff:g id="CHANNEL_NAME_1_0">%1$s</xliff:g>, <xliff:g id="CHANNEL_NAME_2_1">%2$s</xliff:g> i <xliff:g id="NUMBER_2">%3$d</xliff:g> més</item>
- </plurals>
+ <string name="notification_channel_disabled" msgid="344536703863700565">"Ja no veuràs aquestes notificacions"</string>
+ <string name="inline_keep_showing" msgid="8945102997083836858">"Vols continuar rebent aquestes notificacions?"</string>
+ <string name="inline_stop_button" msgid="4172980096860941033">"Deixa d\'enviar notificacions"</string>
+ <string name="inline_keep_button" msgid="6665940297019018232">"Continua rebent"</string>
+ <string name="inline_keep_showing_app" msgid="1723113469580031041">"Vols continuar rebent notificacions d\'aquesta aplicació?"</string>
+ <string name="notification_unblockable_desc" msgid="1037434112919403708">"Aquestes notificacions no es poden desactivar"</string>
<string name="notification_channel_controls_opened_accessibility" msgid="6553950422055908113">"S\'han obert els controls de notificació per a <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
<string name="notification_channel_controls_closed_accessibility" msgid="7521619812603693144">"S\'han tancat els controls de notificació per a <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
<string name="notification_channel_switch_accessibility" msgid="3420796005601900717">"Permet les notificacions d\'aquest canal"</string>
- <string name="notification_all_categories" msgid="5407190218055113282">"Totes les categories"</string>
<string name="notification_more_settings" msgid="816306283396553571">"Més opcions"</string>
- <string name="notification_app_settings" msgid="3743278649182392015">"Personalitza: <xliff:g id="SUB_CATEGORY">%1$s</xliff:g>"</string>
+ <string name="notification_app_settings" msgid="420348114670768449">"Personalitza"</string>
<string name="notification_done" msgid="5279426047273930175">"Fet"</string>
+ <string name="inline_undo" msgid="558916737624706010">"Desfés"</string>
<string name="notification_menu_accessibility" msgid="2046162834248888553">"<xliff:g id="APP_NAME">%1$s</xliff:g> <xliff:g id="MENU_DESCRIPTION">%2$s</xliff:g>"</string>
<string name="notification_menu_gear_description" msgid="2204480013726775108">"controls de notificació"</string>
<string name="notification_menu_snooze_description" msgid="3653669438131034525">"opcions per posposar la notificació"</string>
@@ -731,8 +728,7 @@
<string name="pip_phone_expand" msgid="5889780005575693909">"Desplega"</string>
<string name="pip_phone_minimize" msgid="1079119422589131792">"Minimitza"</string>
<string name="pip_phone_close" msgid="8416647892889710330">"Tanca"</string>
- <!-- no translation found for pip_phone_settings (8080777499521528521) -->
- <skip />
+ <string name="pip_phone_settings" msgid="8080777499521528521">"Configuració"</string>
<string name="pip_phone_dismiss_hint" msgid="6351678169095923899">"Arrossega cap avall per ignorar-ho"</string>
<string name="pip_menu_title" msgid="4707292089961887657">"Menú"</string>
<string name="pip_notification_title" msgid="3204024940158161322">"<xliff:g id="NAME">%s</xliff:g> està en pantalla en pantalla"</string>
diff --git a/packages/SystemUI/res/values-da/strings.xml b/packages/SystemUI/res/values-da/strings.xml
index 543843456aaa..e2ff065f3672 100644
--- a/packages/SystemUI/res/values-da/strings.xml
+++ b/packages/SystemUI/res/values-da/strings.xml
@@ -33,7 +33,10 @@
<string name="status_bar_ongoing_events_title" msgid="1682504513316879202">"I gang"</string>
<string name="status_bar_latest_events_title" msgid="6594767438577593172">"Underretninger"</string>
<string name="battery_low_title" msgid="6456385927409742437">"Batteriniveauet er lavt"</string>
+ <string name="battery_low_title_hybrid" msgid="6268991275887381595">"Batteriniveauet er lavt – aktivér Batterisparefunktion"</string>
<string name="battery_low_percent_format" msgid="2900940511201380775">"<xliff:g id="PERCENTAGE">%s</xliff:g> tilbage"</string>
+ <string name="battery_low_percent_format_hybrid" msgid="6838677459286775617">"Der er <xliff:g id="PERCENTAGE">%s</xliff:g> tilbage eller ca. <xliff:g id="TIME">%s</xliff:g>, alt efter hvordan du bruger enheden"</string>
+ <string name="battery_low_percent_format_hybrid_short" msgid="9025795469949145586">"<xliff:g id="PERCENTAGE">%s</xliff:g> tilbage eller ca. <xliff:g id="TIME">%s</xliff:g>"</string>
<string name="battery_low_percent_format_saver_started" msgid="7879389868952879166">"<xliff:g id="PERCENTAGE">%s</xliff:g> tilbage. Batterisparefunktion er aktiveret."</string>
<string name="invalid_charger" msgid="4549105996740522523">"Opladning via USB understøttes ikke.\nBrug kun den medfølgende oplader."</string>
<string name="invalid_charger_title" msgid="3515740382572798460">"USB-opladning understøttes ikke."</string>
@@ -67,14 +70,15 @@
<string name="usb_debugging_secondary_user_message" msgid="6067122453571699801">"Den bruger, der i øjeblikket er logget ind på denne enhed, kan ikke aktivere USB-fejlretning. Skift til den primære bruger for at bruge denne funktion."</string>
<string name="compat_mode_on" msgid="6623839244840638213">"Zoom til fuld skærm"</string>
<string name="compat_mode_off" msgid="4434467572461327898">"Stræk til fuld skærm"</string>
+ <string name="global_action_screenshot" msgid="8329831278085426283">"Screenshot"</string>
<string name="screenshot_saving_ticker" msgid="7403652894056693515">"Gemmer screenshot..."</string>
<string name="screenshot_saving_title" msgid="8242282144535555697">"Gemmer screenshot..."</string>
- <string name="screenshot_saving_text" msgid="2419718443411738818">"Screenshottet gemmes."</string>
- <string name="screenshot_saved_title" msgid="6461865960961414961">"Screenshottet er gemt."</string>
- <string name="screenshot_saved_text" msgid="2685605830386712477">"Tryk for at se dit screenshot."</string>
- <string name="screenshot_failed_title" msgid="705781116746922771">"Screenshottet kunne ikke tages."</string>
- <string name="screenshot_failed_to_save_unknown_text" msgid="7887826345701753830">"Der opstod et problem ved lagringen af screenshottet."</string>
- <string name="screenshot_failed_to_save_text" msgid="2592658083866306296">"Screenshottet kan ikke gemmes pga. begrænset lagerplads."</string>
+ <string name="screenshot_saving_text" msgid="2545047868936087248">"Screenshottet gemmes"</string>
+ <string name="screenshot_saved_title" msgid="5637073968117370753">"Screenshottet blev gemt"</string>
+ <string name="screenshot_saved_text" msgid="7574667448002050363">"Tryk for at se dit screenshot"</string>
+ <string name="screenshot_failed_title" msgid="9096484883063264803">"Screenshottet kunne ikke tages"</string>
+ <string name="screenshot_failed_to_save_unknown_text" msgid="8844781948876286488">"Der opstod et problem, da screenshottet skulle gemmes"</string>
+ <string name="screenshot_failed_to_save_text" msgid="3041612585107107310">"Screenshottet kan ikke gemmes, fordi der er begrænset lagerplads"</string>
<string name="screenshot_failed_to_capture_text" msgid="173674476457581486">"Appen eller din organisation tillader ikke, at du tager screenshots"</string>
<string name="usb_preference_title" msgid="6551050377388882787">"Muligheder for USB-filoverførsel"</string>
<string name="use_mtp_button_title" msgid="4333504413563023626">"Isæt som en medieafspiller (MTP)"</string>
@@ -557,26 +561,19 @@
<string name="tuner_full_importance_settings_off" msgid="8208165412614935229">"Fra"</string>
<string name="power_notification_controls_description" msgid="4372459941671353358">"Med kontrolelementer til underretninger om strøm kan du konfigurere et vigtighedsniveau fra 0 til 5 for en apps underretninger. \n\n"<b>"Niveau 5"</b>\n"- Vis øverst på listen over underretninger \n- Tillad afbrydelse af fuld skærm \n- Se altid smugkig \n\n"<b>"Niveau 4"</b>\n"- Ingen afbrydelse af fuld skærm \n- Se altid smugkig \n\n"<b>"Niveau 3"</b>\n"- Ingen afbrydelse af fuld skærm \n- Se aldrig smugkig \n\n"<b>"Niveau 2"</b>\n"- Ingen afbrydelse af fuld skærm \n Se aldrig smugkig \n- Ingen lyd og vibration \n\n"<b>"Niveau 1"</b>\n"- Ingen afbrydelse af fuld skærm \n- Se aldrig smugkig \n- Ingen lyd eller vibration \n- Skjul fra låseskærm og statusbjælke \n- Vis nederst på listen over underretninger \n\n"<b>"Niveau 0"</b>\n"- Bloker alle underretninger fra appen."</string>
<string name="notification_header_default_channel" msgid="7506845022070889909">"Underretninger"</string>
- <string name="notification_channel_disabled" msgid="2139193533791840539">"Du modtager ikke længere disse underretninger"</string>
- <string name="notification_num_channels" msgid="2048144408999179471">"<xliff:g id="NUMBER">%d</xliff:g> underretningskategorier"</string>
- <string name="notification_default_channel_desc" msgid="2506053815870808359">"Denne app har ingen underretningskategorier"</string>
- <string name="notification_unblockable_desc" msgid="3561016061737896906">"Underretninger fra denne app kan ikke deaktiveres"</string>
- <plurals name="notification_num_channels_desc" formatted="false" msgid="5492793452274077663">
- <item quantity="one">1 ud af <xliff:g id="NUMBER_1">%s</xliff:g> underretningskategori fra denne app</item>
- <item quantity="other">1 ud af <xliff:g id="NUMBER_1">%s</xliff:g> underretningskategorier fra denne app</item>
- </plurals>
- <string name="notification_channels_list_desc_2" msgid="6214732715833946441">"<xliff:g id="CHANNEL_NAME_1">%1$s</xliff:g>, <xliff:g id="CHANNEL_NAME_2">%2$s</xliff:g>"</string>
- <plurals name="notification_channels_list_desc_2_and_others" formatted="false" msgid="2747813553355336157">
- <item quantity="one"><xliff:g id="CHANNEL_NAME_1_3">%1$s</xliff:g>, <xliff:g id="CHANNEL_NAME_2_4">%2$s</xliff:g> og <xliff:g id="NUMBER_5">%3$d</xliff:g> anden</item>
- <item quantity="other"><xliff:g id="CHANNEL_NAME_1_3">%1$s</xliff:g>, <xliff:g id="CHANNEL_NAME_2_4">%2$s</xliff:g> og <xliff:g id="NUMBER_5">%3$d</xliff:g> andre</item>
- </plurals>
+ <string name="notification_channel_disabled" msgid="344536703863700565">"Du får ikke længere vist disse underretninger"</string>
+ <string name="inline_keep_showing" msgid="8945102997083836858">"Vil du fortsætte med at se disse underretninger?"</string>
+ <string name="inline_stop_button" msgid="4172980096860941033">"Stop underretninger"</string>
+ <string name="inline_keep_button" msgid="6665940297019018232">"Fortsæt med at vise underretninger"</string>
+ <string name="inline_keep_showing_app" msgid="1723113469580031041">"Vil du fortsætte med at se underretninger fra denne app?"</string>
+ <string name="notification_unblockable_desc" msgid="1037434112919403708">"Disse underretninger kan ikke deaktiveres"</string>
<string name="notification_channel_controls_opened_accessibility" msgid="6553950422055908113">"Styring af underretninger for <xliff:g id="APP_NAME">%1$s</xliff:g> blev åbnet"</string>
<string name="notification_channel_controls_closed_accessibility" msgid="7521619812603693144">"Styring af underretninger for <xliff:g id="APP_NAME">%1$s</xliff:g> blev lukket"</string>
<string name="notification_channel_switch_accessibility" msgid="3420796005601900717">"Tillad underretninger fra denne kanal"</string>
- <string name="notification_all_categories" msgid="5407190218055113282">"Alle kategorier"</string>
<string name="notification_more_settings" msgid="816306283396553571">"Flere indstillinger"</string>
- <string name="notification_app_settings" msgid="3743278649182392015">"Tilpas: <xliff:g id="SUB_CATEGORY">%1$s</xliff:g>"</string>
+ <string name="notification_app_settings" msgid="420348114670768449">"Tilpas"</string>
<string name="notification_done" msgid="5279426047273930175">"Udfør"</string>
+ <string name="inline_undo" msgid="558916737624706010">"Fortryd"</string>
<string name="notification_menu_accessibility" msgid="2046162834248888553">"<xliff:g id="APP_NAME">%1$s</xliff:g> <xliff:g id="MENU_DESCRIPTION">%2$s</xliff:g>"</string>
<string name="notification_menu_gear_description" msgid="2204480013726775108">"kontrolelementer til underretninger"</string>
<string name="notification_menu_snooze_description" msgid="3653669438131034525">"Indstillinger for udsættelse"</string>
diff --git a/packages/SystemUI/res/values-de/strings.xml b/packages/SystemUI/res/values-de/strings.xml
index 77a666db1ab7..53bf7d83f540 100644
--- a/packages/SystemUI/res/values-de/strings.xml
+++ b/packages/SystemUI/res/values-de/strings.xml
@@ -33,13 +33,10 @@
<string name="status_bar_ongoing_events_title" msgid="1682504513316879202">"Aktuell"</string>
<string name="status_bar_latest_events_title" msgid="6594767438577593172">"Benachrichtigungen"</string>
<string name="battery_low_title" msgid="6456385927409742437">"Akku ist schwach"</string>
- <!-- no translation found for battery_low_title_hybrid (6268991275887381595) -->
- <skip />
+ <string name="battery_low_title_hybrid" msgid="6268991275887381595">"Akku ist schwach. Energiesparmodus aktivieren."</string>
<string name="battery_low_percent_format" msgid="2900940511201380775">"<xliff:g id="PERCENTAGE">%s</xliff:g> verbleibend"</string>
- <!-- no translation found for battery_low_percent_format_hybrid (6838677459286775617) -->
- <skip />
- <!-- no translation found for battery_low_percent_format_hybrid_short (9025795469949145586) -->
- <skip />
+ <string name="battery_low_percent_format_hybrid" msgid="6838677459286775617">"<xliff:g id="PERCENTAGE">%s</xliff:g> ausstehend; noch ca. <xliff:g id="TIME">%s</xliff:g>, basierend auf deiner Nutzung"</string>
+ <string name="battery_low_percent_format_hybrid_short" msgid="9025795469949145586">"<xliff:g id="PERCENTAGE">%s</xliff:g> ausstehend; noch ca. <xliff:g id="TIME">%s</xliff:g>"</string>
<string name="battery_low_percent_format_saver_started" msgid="7879389868952879166">"Noch <xliff:g id="PERCENTAGE">%s</xliff:g>. Der Energiesparmodus ist aktiviert."</string>
<string name="invalid_charger" msgid="4549105996740522523">"USB-Aufladung wird nicht unterstützt.\nVerwende das mitgelieferte Aufladegerät."</string>
<string name="invalid_charger_title" msgid="3515740382572798460">"Laden per USB wird nicht unterstützt."</string>
@@ -73,22 +70,15 @@
<string name="usb_debugging_secondary_user_message" msgid="6067122453571699801">"Der momentan auf diesem Gerät angemeldete Nutzer kann das USB-Debugging nicht aktivieren. Um diese Funktion verwenden zu können, wechsle zum primären Nutzer."</string>
<string name="compat_mode_on" msgid="6623839244840638213">"Zoom auf Bildschirmgröße"</string>
<string name="compat_mode_off" msgid="4434467572461327898">"Auf Bildschirmgröße anpassen"</string>
- <!-- no translation found for global_action_screenshot (8329831278085426283) -->
- <skip />
+ <string name="global_action_screenshot" msgid="8329831278085426283">"Screenshot"</string>
<string name="screenshot_saving_ticker" msgid="7403652894056693515">"Screenshot wird gespeichert..."</string>
<string name="screenshot_saving_title" msgid="8242282144535555697">"Screenshot wird gespeichert..."</string>
- <!-- no translation found for screenshot_saving_text (2545047868936087248) -->
- <skip />
- <!-- no translation found for screenshot_saved_title (5637073968117370753) -->
- <skip />
- <!-- no translation found for screenshot_saved_text (7574667448002050363) -->
- <skip />
- <!-- no translation found for screenshot_failed_title (9096484883063264803) -->
- <skip />
- <!-- no translation found for screenshot_failed_to_save_unknown_text (8844781948876286488) -->
- <skip />
- <!-- no translation found for screenshot_failed_to_save_text (3041612585107107310) -->
- <skip />
+ <string name="screenshot_saving_text" msgid="2545047868936087248">"Screenshot wird gespeichert"</string>
+ <string name="screenshot_saved_title" msgid="5637073968117370753">"Screenshot gespeichert"</string>
+ <string name="screenshot_saved_text" msgid="7574667448002050363">"Tippe, um deinen Screenshot anzusehen"</string>
+ <string name="screenshot_failed_title" msgid="9096484883063264803">"Screenshot konnte nicht aufgenommen werden"</string>
+ <string name="screenshot_failed_to_save_unknown_text" msgid="8844781948876286488">"Beim Speichern des Screenshots ist ein Problem aufgetreten"</string>
+ <string name="screenshot_failed_to_save_text" msgid="3041612585107107310">"Speichern des Screenshots aufgrund von zu wenig Speicher nicht möglich"</string>
<string name="screenshot_failed_to_capture_text" msgid="173674476457581486">"Die App oder deine Organisation lässt das Erstellen von Screenshots nicht zu"</string>
<string name="usb_preference_title" msgid="6551050377388882787">"USB-Dateiübertragungsoptionen"</string>
<string name="use_mtp_button_title" msgid="4333504413563023626">"Als Medienplayer (MTP) bereitstellen"</string>
@@ -575,27 +565,19 @@
<string name="tuner_full_importance_settings_off" msgid="8208165412614935229">"Aus"</string>
<string name="power_notification_controls_description" msgid="4372459941671353358">"Mit den erweiterten Benachrichtigungseinstellungen kannst du für App-Benachrichtigungen eine Wichtigkeitsstufe von 0 bis 5 festlegen. \n\n"<b>"Stufe 5"</b>" \n- Auf der Benachrichtigungsleiste ganz oben anzeigen \n- Vollbildunterbrechung zulassen \n- Immer kurz einblenden \n\n"<b>"Stufe 4"</b>" \n- Keine Vollbildunterbrechung \n- Immer kurz einblenden \n\n"<b>"Stufe 3"</b>" \n- Keine Vollbildunterbrechung \n- Nie kurz einblenden \n\n"<b>"Stufe 2"</b>" \n- Keine Vollbildunterbrechung \n- Nie kurz einblenden \n- Weder Ton noch Vibration \n\n"<b>"Stufe 1"</b>" \n- Keine Vollbildunterbrechung \n- Nie kurz einblenden \n- Weder Ton noch Vibration \n- Auf Sperrbildschirm und Statusleiste verbergen \n- Auf der Benachrichtigungsleiste ganz unten anzeigen \n\n"<b>"Stufe 0"</b>" \n- Alle Benachrichtigungen der App sperren"</string>
<string name="notification_header_default_channel" msgid="7506845022070889909">"Benachrichtigungen"</string>
- <!-- no translation found for notification_channel_disabled (344536703863700565) -->
- <skip />
- <!-- no translation found for inline_keep_showing (8945102997083836858) -->
- <skip />
- <!-- no translation found for inline_stop_button (4172980096860941033) -->
- <skip />
- <!-- no translation found for inline_keep_button (6665940297019018232) -->
- <skip />
- <!-- no translation found for inline_keep_showing_app (1723113469580031041) -->
- <skip />
- <!-- no translation found for notification_unblockable_desc (1037434112919403708) -->
- <skip />
+ <string name="notification_channel_disabled" msgid="344536703863700565">"Du erhältst diese Benachrichtigungen nicht mehr"</string>
+ <string name="inline_keep_showing" msgid="8945102997083836858">"Diese Benachrichtigungen weiterhin anzeigen?"</string>
+ <string name="inline_stop_button" msgid="4172980096860941033">"Benachrichtigungen nicht mehr anzeigen"</string>
+ <string name="inline_keep_button" msgid="6665940297019018232">"Weiterhin anzeigen"</string>
+ <string name="inline_keep_showing_app" msgid="1723113469580031041">"Benachrichtigungen dieser App weiterhin anzeigen?"</string>
+ <string name="notification_unblockable_desc" msgid="1037434112919403708">"Diese Benachrichtigungen können nicht deaktiviert werden"</string>
<string name="notification_channel_controls_opened_accessibility" msgid="6553950422055908113">"Benachrichtigungseinstellungen für <xliff:g id="APP_NAME">%1$s</xliff:g> geöffnet"</string>
<string name="notification_channel_controls_closed_accessibility" msgid="7521619812603693144">"Benachrichtigungseinstellungen für <xliff:g id="APP_NAME">%1$s</xliff:g> geschlossen"</string>
<string name="notification_channel_switch_accessibility" msgid="3420796005601900717">"Benachrichtigungen von diesem Kanal zulassen"</string>
<string name="notification_more_settings" msgid="816306283396553571">"Weitere Einstellungen"</string>
- <!-- no translation found for notification_app_settings (420348114670768449) -->
- <skip />
+ <string name="notification_app_settings" msgid="420348114670768449">"Anpassen"</string>
<string name="notification_done" msgid="5279426047273930175">"Fertig"</string>
- <!-- no translation found for inline_undo (558916737624706010) -->
- <skip />
+ <string name="inline_undo" msgid="558916737624706010">"Rückgängig machen"</string>
<string name="notification_menu_accessibility" msgid="2046162834248888553">"<xliff:g id="MENU_DESCRIPTION">%2$s</xliff:g> – <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
<string name="notification_menu_gear_description" msgid="2204480013726775108">"Benachrichtigungseinstellungen"</string>
<string name="notification_menu_snooze_description" msgid="3653669438131034525">"Optionen für spätere Erinnerung bei Benachrichtigungen"</string>
diff --git a/packages/SystemUI/res/values-el/strings.xml b/packages/SystemUI/res/values-el/strings.xml
index 7464d31b401d..663191c6bc1d 100644
--- a/packages/SystemUI/res/values-el/strings.xml
+++ b/packages/SystemUI/res/values-el/strings.xml
@@ -33,7 +33,10 @@
<string name="status_bar_ongoing_events_title" msgid="1682504513316879202">"Εν εξελίξει"</string>
<string name="status_bar_latest_events_title" msgid="6594767438577593172">"Ειδοποιήσεις"</string>
<string name="battery_low_title" msgid="6456385927409742437">"Χαμηλή στάθμη μπαταρίας"</string>
+ <string name="battery_low_title_hybrid" msgid="6268991275887381595">"Χαμηλή στάθμη μπαταρίας. Ενεργοποιήστε την Εξοικονόμηση μπαταρίας"</string>
<string name="battery_low_percent_format" msgid="2900940511201380775">"Απομένουν <xliff:g id="PERCENTAGE">%s</xliff:g>"</string>
+ <string name="battery_low_percent_format_hybrid" msgid="6838677459286775617">"Απομένει <xliff:g id="PERCENTAGE">%s</xliff:g>, περίπου <xliff:g id="TIME">%s</xliff:g> με βάση τη χρήση σας"</string>
+ <string name="battery_low_percent_format_hybrid_short" msgid="9025795469949145586">"Απομένει <xliff:g id="PERCENTAGE">%s</xliff:g>, περίπου <xliff:g id="TIME">%s</xliff:g>"</string>
<string name="battery_low_percent_format_saver_started" msgid="7879389868952879166">"Απομένουν <xliff:g id="PERCENTAGE">%s</xliff:g>. Η Εξοικονόμηση μπαταρίας είναι ενεργή."</string>
<string name="invalid_charger" msgid="4549105996740522523">"Δεν υποστηρίζεται η φόρτιση USB.\nΧρησιμοποιείτε μόνο τον φορτιστή που παρέχεται."</string>
<string name="invalid_charger_title" msgid="3515740382572798460">"Δεν υποστηρίζεται η φόρτιση μέσω USB."</string>
@@ -67,14 +70,15 @@
<string name="usb_debugging_secondary_user_message" msgid="6067122453571699801">"Ο χρήστης που είναι συνδεδεμένος αυτήν τη στιγμή σε αυτήν τη συσκευή δεν μπορεί να ενεργοποιήσει τον εντοπισμό σφαλμάτων USB. Για να χρησιμοποιήσετε αυτήν τη λειτουργία, κάντε εναλλαγή στον κύριο χρήστη."</string>
<string name="compat_mode_on" msgid="6623839244840638213">"Ζουμ σε πλήρη οθόνη"</string>
<string name="compat_mode_off" msgid="4434467572461327898">"Προβoλή σε πλήρη οθ."</string>
+ <string name="global_action_screenshot" msgid="8329831278085426283">"Στιγμιότυπο οθόνης"</string>
<string name="screenshot_saving_ticker" msgid="7403652894056693515">"Αποθήκ. στιγμιότυπου οθόνης..."</string>
<string name="screenshot_saving_title" msgid="8242282144535555697">"Αποθήκευση στιγμιότυπου οθόνης..."</string>
- <string name="screenshot_saving_text" msgid="2419718443411738818">"Γίνεται αποθήκευση του στιγμιότυπου οθόνης."</string>
- <string name="screenshot_saved_title" msgid="6461865960961414961">"Λήφθηκε το στιγμιότυπο οθόνης ."</string>
- <string name="screenshot_saved_text" msgid="2685605830386712477">"Πατήστε για να δείτε το στιγμιότυπο οθόνης που δημιουργήσατε."</string>
- <string name="screenshot_failed_title" msgid="705781116746922771">"Αδύνατη η αποθήκευση του στιγμιότυπου οθόνης."</string>
- <string name="screenshot_failed_to_save_unknown_text" msgid="7887826345701753830">"Παρουσιάστηκε πρόβλημα κατά την αποθήκευση του στιγμιότυπου οθόνης."</string>
- <string name="screenshot_failed_to_save_text" msgid="2592658083866306296">"Δεν είναι δυνατή η αποθήκευση του στιγμιότυπου οθόνης λόγω περιορισμένου χώρου αποθήκευσης."</string>
+ <string name="screenshot_saving_text" msgid="2545047868936087248">"Γίνεται αποθήκευση του στιγμιότυπου οθόνης"</string>
+ <string name="screenshot_saved_title" msgid="5637073968117370753">"Το στιγμιότυπο οθόνης αποθηκεύτηκε"</string>
+ <string name="screenshot_saved_text" msgid="7574667448002050363">"Πατήστε για να δείτε το στιγμιότυπο οθόνης που δημιουργήσατε"</string>
+ <string name="screenshot_failed_title" msgid="9096484883063264803">"Αδύνατη η λήψη του στιγμιότυπου οθόνης."</string>
+ <string name="screenshot_failed_to_save_unknown_text" msgid="8844781948876286488">"Παρουσιάστηκε πρόβλημα κατά την αποθήκευση του στιγμιότυπου οθόνης"</string>
+ <string name="screenshot_failed_to_save_text" msgid="3041612585107107310">"Αδύνατη η αποθήκευση του στιγμιότυπου οθόνης λόγω περιορισμένου αποθηκευτικού χώρου"</string>
<string name="screenshot_failed_to_capture_text" msgid="173674476457581486">"Η λήψη στιγμιότυπων οθόνης δεν επιτρέπεται από την εφαρμογή ή τον οργανισμό σας"</string>
<string name="usb_preference_title" msgid="6551050377388882787">"Επιλογές μεταφοράς αρχείων μέσω USB"</string>
<string name="use_mtp_button_title" msgid="4333504413563023626">"Προσάρτηση ως μονάδας αναπαραγωγής μέσων (MTP)"</string>
@@ -557,26 +561,19 @@
<string name="tuner_full_importance_settings_off" msgid="8208165412614935229">"Ανενεργή"</string>
<string name="power_notification_controls_description" msgid="4372459941671353358">"Με τα στοιχεία ελέγχου ειδοποίησης ισχύος, μπορείτε να ορίσετε ένα επίπεδο βαρύτητας από 0 έως 5 για τις ειδοποιήσεις μιας εφαρμογής. \n\n"<b>"Επίπεδο 5"</b>" \n- Εμφάνιση στην κορυφή της λίστας ειδοποιήσεων \n- Να επιτρέπεται η διακοπή πλήρους οθόνης \n- Να γίνεται πάντα σύντομη προβολή \n\n"<b>"Επίπεδο 4"</b>" \n- Αποτροπή διακοπής πλήρους οθόνης \n- Να γίνεται πάντα σύντομη προβολή \n\n"<b>"Επίπεδο 3"</b>" \n- Αποτροπή διακοπής πλήρους οθόνης \n- Να μην γίνεται ποτέ σύντομη προβολή \n\n"<b>"Επίπεδο 2"</b>" \n- Αποτροπή διακοπής πλήρους οθόνης \n- Να μην γίνεται ποτέ σύντομη προβολή \n- Να μην χρησιμοποιείται ποτέ ήχος και δόνηση \n\n"<b>"Επίπεδο 1"</b>" \n- Αποτροπή διακοπής πλήρους οθόνης \n- Να μην γίνεται ποτέ σύντομη προβολή \n- Να μην χρησιμοποιείται ποτέ ήχος και δόνηση \n- Απόκρυψη από την οθόνη κλειδώματος και τη γραμμή κατάστασης \n- Εμφάνιση στο κάτω μέρος της λίστας ειδοποιήσεων \n\n"<b>"Επίπεδο 0"</b>" \n- Αποκλεισμός όλων των ειδοποιήσεων από την εφαρμογή"</string>
<string name="notification_header_default_channel" msgid="7506845022070889909">"Ειδοποιήσεις"</string>
- <string name="notification_channel_disabled" msgid="2139193533791840539">"Δεν θα λαμβάνετε πλέον αυτές τις ειδοποιήσεις"</string>
- <string name="notification_num_channels" msgid="2048144408999179471">"<xliff:g id="NUMBER">%d</xliff:g> κατηγορίες ειδοποιήσεων"</string>
- <string name="notification_default_channel_desc" msgid="2506053815870808359">"Αυτή η εφαρμογή δεν διαθέτει κατηγορίες ειδοποιήσεων"</string>
- <string name="notification_unblockable_desc" msgid="3561016061737896906">"Οι ειδοποιήσεις από αυτήν την εφαρμογή δεν μπορούν να απενεργοποιηθούν"</string>
- <plurals name="notification_num_channels_desc" formatted="false" msgid="5492793452274077663">
- <item quantity="other">1 από <xliff:g id="NUMBER_1">%s</xliff:g> κατηγορίες ειδοποιήσεων από αυτή την εφαρμογή</item>
- <item quantity="one">1 από <xliff:g id="NUMBER_0">%s</xliff:g> κατηγορία ειδοποιήσεων από αυτή την εφαρμογή</item>
- </plurals>
- <string name="notification_channels_list_desc_2" msgid="6214732715833946441">"<xliff:g id="CHANNEL_NAME_1">%1$s</xliff:g>, <xliff:g id="CHANNEL_NAME_2">%2$s</xliff:g>"</string>
- <plurals name="notification_channels_list_desc_2_and_others" formatted="false" msgid="2747813553355336157">
- <item quantity="other"><xliff:g id="CHANNEL_NAME_1_3">%1$s</xliff:g>, <xliff:g id="CHANNEL_NAME_2_4">%2$s</xliff:g> και <xliff:g id="NUMBER_5">%3$d</xliff:g> ακόμη</item>
- <item quantity="one"><xliff:g id="CHANNEL_NAME_1_0">%1$s</xliff:g>, <xliff:g id="CHANNEL_NAME_2_1">%2$s</xliff:g> και <xliff:g id="NUMBER_2">%3$d</xliff:g> ακόμη</item>
- </plurals>
+ <string name="notification_channel_disabled" msgid="344536703863700565">"Δεν θα βλέπετε πλέον αυτές τις ειδοποιήσεις"</string>
+ <string name="inline_keep_showing" msgid="8945102997083836858">"Να συνεχίσουν να εμφανίζονται αυτές οι ειδοποιήσεις;"</string>
+ <string name="inline_stop_button" msgid="4172980096860941033">"Διακοπή ειδοποιήσεων"</string>
+ <string name="inline_keep_button" msgid="6665940297019018232">"Συνέχιση εμφάνισης"</string>
+ <string name="inline_keep_showing_app" msgid="1723113469580031041">"Να συνεχίσουν να εμφανίζονται ειδοποιήσεις από αυτήν την εφαρμογή;"</string>
+ <string name="notification_unblockable_desc" msgid="1037434112919403708">"Αδύνατη η απενεργοποίηση αυτών των ειδοποιήσεων"</string>
<string name="notification_channel_controls_opened_accessibility" msgid="6553950422055908113">"Τα στοιχεία ελέγχου ειδοποιήσεων για την εφαρμογή <xliff:g id="APP_NAME">%1$s</xliff:g> άνοιξαν"</string>
<string name="notification_channel_controls_closed_accessibility" msgid="7521619812603693144">"Τα στοιχεία ελέγχου ειδοποιήσεων για την εφαρμογή <xliff:g id="APP_NAME">%1$s</xliff:g> έκλεισαν"</string>
<string name="notification_channel_switch_accessibility" msgid="3420796005601900717">"Να επιτρέπονται οι ειδοποιήσεις από αυτό το κανάλι"</string>
- <string name="notification_all_categories" msgid="5407190218055113282">"Όλες οι κατηγορίες"</string>
<string name="notification_more_settings" msgid="816306283396553571">"Περισσότερες ρυθμίσεις"</string>
- <string name="notification_app_settings" msgid="3743278649182392015">"Προσαρμογή: <xliff:g id="SUB_CATEGORY">%1$s</xliff:g>"</string>
+ <string name="notification_app_settings" msgid="420348114670768449">"Προσαρμογή"</string>
<string name="notification_done" msgid="5279426047273930175">"Τέλος"</string>
+ <string name="inline_undo" msgid="558916737624706010">"Αναίρεση"</string>
<string name="notification_menu_accessibility" msgid="2046162834248888553">"<xliff:g id="APP_NAME">%1$s</xliff:g> <xliff:g id="MENU_DESCRIPTION">%2$s</xliff:g>"</string>
<string name="notification_menu_gear_description" msgid="2204480013726775108">"στοιχεία ελέγχου ειδοποιήσεων"</string>
<string name="notification_menu_snooze_description" msgid="3653669438131034525">"επιλογές αφύπνισης ειδοποιήσεων"</string>
@@ -731,8 +728,7 @@
<string name="pip_phone_expand" msgid="5889780005575693909">"Ανάπτυξη"</string>
<string name="pip_phone_minimize" msgid="1079119422589131792">"Ελαχιστοποίηση"</string>
<string name="pip_phone_close" msgid="8416647892889710330">"Κλείσιμο"</string>
- <!-- no translation found for pip_phone_settings (8080777499521528521) -->
- <skip />
+ <string name="pip_phone_settings" msgid="8080777499521528521">"Ρυθμίσεις"</string>
<string name="pip_phone_dismiss_hint" msgid="6351678169095923899">"Σύρετε προς τα κάτω για παράβλεψη"</string>
<string name="pip_menu_title" msgid="4707292089961887657">"Μενού"</string>
<string name="pip_notification_title" msgid="3204024940158161322">"Η λειτουργία picture-in-picture είναι ενεργή σε <xliff:g id="NAME">%s</xliff:g>."</string>
diff --git a/packages/SystemUI/res/values-es-rUS/strings.xml b/packages/SystemUI/res/values-es-rUS/strings.xml
index 690168659f9f..cdb432bb17ef 100644
--- a/packages/SystemUI/res/values-es-rUS/strings.xml
+++ b/packages/SystemUI/res/values-es-rUS/strings.xml
@@ -33,7 +33,10 @@
<string name="status_bar_ongoing_events_title" msgid="1682504513316879202">"Continuo"</string>
<string name="status_bar_latest_events_title" msgid="6594767438577593172">"Notificaciones"</string>
<string name="battery_low_title" msgid="6456385927409742437">"Batería baja"</string>
+ <string name="battery_low_title_hybrid" msgid="6268991275887381595">"Queda poca batería. Activa el Ahorro de batería"</string>
<string name="battery_low_percent_format" msgid="2900940511201380775">"Queda un <xliff:g id="PERCENTAGE">%s</xliff:g> de batería."</string>
+ <string name="battery_low_percent_format_hybrid" msgid="6838677459286775617">"Batería: <xliff:g id="PERCENTAGE">%s</xliff:g> (tiempo restante aproximado según tu uso: <xliff:g id="TIME">%s</xliff:g>)"</string>
+ <string name="battery_low_percent_format_hybrid_short" msgid="9025795469949145586">"Batería: <xliff:g id="PERCENTAGE">%s</xliff:g> (tiempo restante aproximado: <xliff:g id="TIME">%s</xliff:g>)"</string>
<string name="battery_low_percent_format_saver_started" msgid="7879389868952879166">"Queda <xliff:g id="PERCENTAGE">%s</xliff:g> de batería. El Ahorro de batería está activado."</string>
<string name="invalid_charger" msgid="4549105996740522523">"No admite la carga USB.\nUsa sólo el cargador provisto."</string>
<string name="invalid_charger_title" msgid="3515740382572798460">"No se admite la carga por USB."</string>
@@ -67,14 +70,15 @@
<string name="usb_debugging_secondary_user_message" msgid="6067122453571699801">"El usuario al que accediste en este dispositivo no puede activar la depuración por USB. Para usar esta función, debes cambiar al usuario principal."</string>
<string name="compat_mode_on" msgid="6623839244840638213">"Zoom para ocupar la pantalla"</string>
<string name="compat_mode_off" msgid="4434467572461327898">"Estirar p/ ocupar la pantalla"</string>
+ <string name="global_action_screenshot" msgid="8329831278085426283">"Captura de pantalla"</string>
<string name="screenshot_saving_ticker" msgid="7403652894056693515">"Guardando captura de pantalla"</string>
<string name="screenshot_saving_title" msgid="8242282144535555697">"Guardando la captura de pantalla..."</string>
- <string name="screenshot_saving_text" msgid="2419718443411738818">"La captura de pantalla se está guardando."</string>
- <string name="screenshot_saved_title" msgid="6461865960961414961">"Se guardó la captura de pantalla."</string>
- <string name="screenshot_saved_text" msgid="2685605830386712477">"Presiona para ver tu captura de pantalla."</string>
- <string name="screenshot_failed_title" msgid="705781116746922771">"No se pudo guardar la captura de pantalla."</string>
- <string name="screenshot_failed_to_save_unknown_text" msgid="7887826345701753830">"Se produjo un error al guardar la captura de pantalla."</string>
- <string name="screenshot_failed_to_save_text" msgid="2592658083866306296">"No se puede guardar la captura de pantalla debido al almacenamiento limitado."</string>
+ <string name="screenshot_saving_text" msgid="2545047868936087248">"Se está guardando la captura de pantalla"</string>
+ <string name="screenshot_saved_title" msgid="5637073968117370753">"Se guardó la captura de pantalla"</string>
+ <string name="screenshot_saved_text" msgid="7574667448002050363">"Presiona para ver la captura de pantalla"</string>
+ <string name="screenshot_failed_title" msgid="9096484883063264803">"No se pudo tomar la captura de pantalla"</string>
+ <string name="screenshot_failed_to_save_unknown_text" msgid="8844781948876286488">"Se produjo un error al guardar la captura de pantalla"</string>
+ <string name="screenshot_failed_to_save_text" msgid="3041612585107107310">"No se puede guardar la captura de pantalla debido a que no hay suficiente espacio de almacenamiento"</string>
<string name="screenshot_failed_to_capture_text" msgid="173674476457581486">"La app o tu organización no permiten las capturas de pantalla"</string>
<string name="usb_preference_title" msgid="6551050377388882787">"Opciones de transferencia de archivos por USB"</string>
<string name="use_mtp_button_title" msgid="4333504413563023626">"Activar como reproductor de medios (MTP)"</string>
@@ -559,26 +563,19 @@
<string name="tuner_full_importance_settings_off" msgid="8208165412614935229">"Desactivado"</string>
<string name="power_notification_controls_description" msgid="4372459941671353358">"Con los controles de activación de notificaciones, puedes establecer un nivel de importancia para las notificaciones de una app. \n\n"<b>"Nivel 5"</b>" \n- Mostrar en la parte superior de la lista de notificaciones. \n- Permitir interrupción en la pantalla completa. \n- Mostrar siempre. \n\n"<b>"Nivel 4"</b>" \n- No permitir interrupción en la pantalla completa. \n- Mostrar siempre. \n\n"<b>"Nivel 3"</b>" \n- No permitir interrupción en la pantalla completa. \n- No mostrar. \n\n"<b>"Nivel 2"</b>" \n- No permitir interrupción en la pantalla completa. \n- No mostrar. \n- No sonar ni vibrar. \n\n"<b>"Nivel 1"</b>" \n- No permitir interrupción en la pantalla completa. \n- No mostrar. \n- No sonar ni vibrar. \n- Ocultar de la pantalla bloqueada y la barra de estado. \n- Mostrar al final de la lista de notificaciones. \n\n"<b>"Nivel 0"</b>" \n- Bloquear todas las notificaciones de la app."</string>
<string name="notification_header_default_channel" msgid="7506845022070889909">"Notificaciones"</string>
- <string name="notification_channel_disabled" msgid="2139193533791840539">"Ya no recibirás estas notificaciones"</string>
- <string name="notification_num_channels" msgid="2048144408999179471">"<xliff:g id="NUMBER">%d</xliff:g> categorías de notificaciones"</string>
- <string name="notification_default_channel_desc" msgid="2506053815870808359">"Esta app no tiene categorías de notificación"</string>
- <string name="notification_unblockable_desc" msgid="3561016061737896906">"No es posible desactivar las notificaciones de esta app"</string>
- <plurals name="notification_num_channels_desc" formatted="false" msgid="5492793452274077663">
- <item quantity="other">1 de <xliff:g id="NUMBER_1">%s</xliff:g> categorías de notificación de esta app</item>
- <item quantity="one">1 de <xliff:g id="NUMBER_0">%s</xliff:g> categoría de notificación de esta app</item>
- </plurals>
- <string name="notification_channels_list_desc_2" msgid="6214732715833946441">"<xliff:g id="CHANNEL_NAME_1">%1$s</xliff:g>, <xliff:g id="CHANNEL_NAME_2">%2$s</xliff:g>"</string>
- <plurals name="notification_channels_list_desc_2_and_others" formatted="false" msgid="2747813553355336157">
- <item quantity="other"><xliff:g id="CHANNEL_NAME_1_3">%1$s</xliff:g>, <xliff:g id="CHANNEL_NAME_2_4">%2$s</xliff:g> y <xliff:g id="NUMBER_5">%3$d</xliff:g> más</item>
- <item quantity="one"><xliff:g id="CHANNEL_NAME_1_0">%1$s</xliff:g>, <xliff:g id="CHANNEL_NAME_2_1">%2$s</xliff:g> y <xliff:g id="NUMBER_2">%3$d</xliff:g> más</item>
- </plurals>
+ <string name="notification_channel_disabled" msgid="344536703863700565">"Ya no verás estas notificaciones"</string>
+ <string name="inline_keep_showing" msgid="8945102997083836858">"¿Quieres seguir viendo estas notificaciones?"</string>
+ <string name="inline_stop_button" msgid="4172980096860941033">"Detener notificaciones"</string>
+ <string name="inline_keep_button" msgid="6665940297019018232">"Seguir viendo"</string>
+ <string name="inline_keep_showing_app" msgid="1723113469580031041">"¿Quieres seguir viendo las notificaciones de esta app?"</string>
+ <string name="notification_unblockable_desc" msgid="1037434112919403708">"No se pueden desactivar estas notificaciones"</string>
<string name="notification_channel_controls_opened_accessibility" msgid="6553950422055908113">"Se abrieron los controles de notificaciones de <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
<string name="notification_channel_controls_closed_accessibility" msgid="7521619812603693144">"Se cerraron los controles de notificaciones de <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
<string name="notification_channel_switch_accessibility" msgid="3420796005601900717">"Permitir las notificaciones de este canal"</string>
- <string name="notification_all_categories" msgid="5407190218055113282">"Todas las categorías"</string>
<string name="notification_more_settings" msgid="816306283396553571">"Más opciones de configuración"</string>
- <string name="notification_app_settings" msgid="3743278649182392015">"Personalizar: <xliff:g id="SUB_CATEGORY">%1$s</xliff:g>"</string>
+ <string name="notification_app_settings" msgid="420348114670768449">"Personalizar"</string>
<string name="notification_done" msgid="5279426047273930175">"Listo"</string>
+ <string name="inline_undo" msgid="558916737624706010">"Deshacer"</string>
<string name="notification_menu_accessibility" msgid="2046162834248888553">"<xliff:g id="MENU_DESCRIPTION">%2$s</xliff:g> de <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
<string name="notification_menu_gear_description" msgid="2204480013726775108">"controles de notificación"</string>
<string name="notification_menu_snooze_description" msgid="3653669438131034525">"opciones para posponer notificaciones"</string>
@@ -733,8 +730,7 @@
<string name="pip_phone_expand" msgid="5889780005575693909">"Expandir"</string>
<string name="pip_phone_minimize" msgid="1079119422589131792">"Minimizar"</string>
<string name="pip_phone_close" msgid="8416647892889710330">"Cerrar"</string>
- <!-- no translation found for pip_phone_settings (8080777499521528521) -->
- <skip />
+ <string name="pip_phone_settings" msgid="8080777499521528521">"Configuración"</string>
<string name="pip_phone_dismiss_hint" msgid="6351678169095923899">"Arrastra hacia abajo para descartar"</string>
<string name="pip_menu_title" msgid="4707292089961887657">"Menú"</string>
<string name="pip_notification_title" msgid="3204024940158161322">"<xliff:g id="NAME">%s</xliff:g> está en modo de imagen en imagen"</string>
diff --git a/packages/SystemUI/res/values-es/strings.xml b/packages/SystemUI/res/values-es/strings.xml
index a5d5c4427841..b467b389ecf8 100644
--- a/packages/SystemUI/res/values-es/strings.xml
+++ b/packages/SystemUI/res/values-es/strings.xml
@@ -33,7 +33,10 @@
<string name="status_bar_ongoing_events_title" msgid="1682504513316879202">"Entrante"</string>
<string name="status_bar_latest_events_title" msgid="6594767438577593172">"Notificaciones"</string>
<string name="battery_low_title" msgid="6456385927409742437">"Nivel de batería bajo"</string>
+ <string name="battery_low_title_hybrid" msgid="6268991275887381595">"Queda poca batería. Activa la función Ahorro de batería"</string>
<string name="battery_low_percent_format" msgid="2900940511201380775">"Queda un <xliff:g id="PERCENTAGE">%s</xliff:g> de batería"</string>
+ <string name="battery_low_percent_format_hybrid" msgid="6838677459286775617">"Queda un <xliff:g id="PERCENTAGE">%s</xliff:g> (tiempo restante aproximado según tu uso: <xliff:g id="TIME">%s</xliff:g>)"</string>
+ <string name="battery_low_percent_format_hybrid_short" msgid="9025795469949145586">"Queda un <xliff:g id="PERCENTAGE">%s</xliff:g> (tiempo restante aproximado: <xliff:g id="TIME">%s</xliff:g>)"</string>
<string name="battery_low_percent_format_saver_started" msgid="7879389868952879166">"Queda un <xliff:g id="PERCENTAGE">%s</xliff:g> de batería. Se ha activado la función Ahorro de energía."</string>
<string name="invalid_charger" msgid="4549105996740522523">"No se admite la carga por USB.\nUtiliza solo el cargador proporcionado."</string>
<string name="invalid_charger_title" msgid="3515740382572798460">"No se admite la carga por USB."</string>
@@ -67,14 +70,15 @@
<string name="usb_debugging_secondary_user_message" msgid="6067122453571699801">"El usuario con el que se ha iniciado sesión en este dispositivo no puede activar la depuración USB. Para utilizar esta función, inicia sesión con la cuenta de usuario principal."</string>
<string name="compat_mode_on" msgid="6623839244840638213">"Zoom para ajustar"</string>
<string name="compat_mode_off" msgid="4434467572461327898">"Expandir para ajustar"</string>
+ <string name="global_action_screenshot" msgid="8329831278085426283">"Captura de pantalla"</string>
<string name="screenshot_saving_ticker" msgid="7403652894056693515">"Guardando captura..."</string>
<string name="screenshot_saving_title" msgid="8242282144535555697">"Guardando captura..."</string>
- <string name="screenshot_saving_text" msgid="2419718443411738818">"La captura de pantalla se está guardando."</string>
- <string name="screenshot_saved_title" msgid="6461865960961414961">"Captura guardada"</string>
- <string name="screenshot_saved_text" msgid="2685605830386712477">"Toca para ver la captura de pantalla."</string>
- <string name="screenshot_failed_title" msgid="705781116746922771">"No se ha podido guardar la captura de pantalla."</string>
- <string name="screenshot_failed_to_save_unknown_text" msgid="7887826345701753830">"Se ha detectado un problema al guardar la captura de pantalla."</string>
- <string name="screenshot_failed_to_save_text" msgid="2592658083866306296">"No se puede guardar la captura de pantalla porque no hay espacio de almacenamiento suficiente."</string>
+ <string name="screenshot_saving_text" msgid="2545047868936087248">"La captura de pantalla se está guardando"</string>
+ <string name="screenshot_saved_title" msgid="5637073968117370753">"Se ha guardado la captura de pantalla"</string>
+ <string name="screenshot_saved_text" msgid="7574667448002050363">"Toca para ver la captura de pantalla"</string>
+ <string name="screenshot_failed_title" msgid="9096484883063264803">"No se ha podido guardar la captura de pantalla"</string>
+ <string name="screenshot_failed_to_save_unknown_text" msgid="8844781948876286488">"No se ha podido guardar la captura de pantalla"</string>
+ <string name="screenshot_failed_to_save_text" msgid="3041612585107107310">"No se puede guardar la captura de pantalla porque no hay espacio de almacenamiento suficiente"</string>
<string name="screenshot_failed_to_capture_text" msgid="173674476457581486">"La aplicación o tu organización no permiten realizar capturas de pantalla"</string>
<string name="usb_preference_title" msgid="6551050377388882787">"Opciones de transferencia de archivos por USB"</string>
<string name="use_mtp_button_title" msgid="4333504413563023626">"Activar como reproductor de medios (MTP)"</string>
@@ -559,26 +563,19 @@
<string name="tuner_full_importance_settings_off" msgid="8208165412614935229">"Desactivado"</string>
<string name="power_notification_controls_description" msgid="4372459941671353358">"Los controles de energía de las notificaciones permiten establecer un nivel de importancia de 0 a 5 para las notificaciones de las aplicaciones. \n\n"<b>"Nivel 5"</b>" \n- Mostrar en la parte superior de la lista de notificaciones \n- Permitir interrumpir en el modo de pantalla completa \n- Mostrar siempre \n\n"<b>"Nivel 4"</b>" \n- Evitar interrumpir en el modo de pantalla completa \n- Mostrar siempre \n\n"<b>"Nivel 3"</b>" \n- Evitar interrumpir en el modo de pantalla completa \n- No mostrar nunca \n\n"<b>"Nivel 2"</b>" \n- Evitar interrumpir en el modo de pantalla completa\n- No mostrar nunca \n- No emitir sonido ni vibrar nunca \n\n"<b>"Nivel 1"</b>" \n- Evitar interrumpir en el modo de pantalla completa \n- No mostrar nunca \n- No emitir sonido ni vibrar nunca \n- Ocultar de la pantalla de bloqueo y de la barra de estado \n- Mostrar en la parte inferior de la lista de notificaciones \n\n"<b>"Nivel 0"</b>" \n- Bloquear todas las notificaciones de la aplicación"</string>
<string name="notification_header_default_channel" msgid="7506845022070889909">"Notificaciones"</string>
- <string name="notification_channel_disabled" msgid="2139193533791840539">"Ya no recibirás estas notificaciones"</string>
- <string name="notification_num_channels" msgid="2048144408999179471">"<xliff:g id="NUMBER">%d</xliff:g> categorías de notificación"</string>
- <string name="notification_default_channel_desc" msgid="2506053815870808359">"Esta aplicación no tiene categorías de notificación"</string>
- <string name="notification_unblockable_desc" msgid="3561016061737896906">"No se pueden desactivar las notificaciones de esta aplicación"</string>
- <plurals name="notification_num_channels_desc" formatted="false" msgid="5492793452274077663">
- <item quantity="other">1 de <xliff:g id="NUMBER_1">%s</xliff:g> categorías de notificación de esta aplicación</item>
- <item quantity="one">1 de <xliff:g id="NUMBER_0">%s</xliff:g> categoría de notificación de esta aplicación</item>
- </plurals>
- <string name="notification_channels_list_desc_2" msgid="6214732715833946441">"<xliff:g id="CHANNEL_NAME_1">%1$s</xliff:g>, <xliff:g id="CHANNEL_NAME_2">%2$s</xliff:g>"</string>
- <plurals name="notification_channels_list_desc_2_and_others" formatted="false" msgid="2747813553355336157">
- <item quantity="other"><xliff:g id="CHANNEL_NAME_1_3">%1$s</xliff:g>, <xliff:g id="CHANNEL_NAME_2_4">%2$s</xliff:g> y <xliff:g id="NUMBER_5">%3$d</xliff:g> más</item>
- <item quantity="one"><xliff:g id="CHANNEL_NAME_1_0">%1$s</xliff:g>, <xliff:g id="CHANNEL_NAME_2_1">%2$s</xliff:g> y <xliff:g id="NUMBER_2">%3$d</xliff:g> más</item>
- </plurals>
+ <string name="notification_channel_disabled" msgid="344536703863700565">"No volverás a ver estas notificaciones"</string>
+ <string name="inline_keep_showing" msgid="8945102997083836858">"¿Quieres seguir viendo estas notificaciones?"</string>
+ <string name="inline_stop_button" msgid="4172980096860941033">"Detener las notificaciones"</string>
+ <string name="inline_keep_button" msgid="6665940297019018232">"Seguir mostrando"</string>
+ <string name="inline_keep_showing_app" msgid="1723113469580031041">"¿Quieres seguir viendo las notificaciones de esta aplicación?"</string>
+ <string name="notification_unblockable_desc" msgid="1037434112919403708">"Estas notificaciones no se pueden desactivar"</string>
<string name="notification_channel_controls_opened_accessibility" msgid="6553950422055908113">"Se han abierto los controles de las notificaciones de <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
<string name="notification_channel_controls_closed_accessibility" msgid="7521619812603693144">"Se han cerrado los controles de las notificaciones de <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
<string name="notification_channel_switch_accessibility" msgid="3420796005601900717">"Permite las notificaciones de este canal"</string>
- <string name="notification_all_categories" msgid="5407190218055113282">"Todas las categorías"</string>
<string name="notification_more_settings" msgid="816306283396553571">"Más ajustes"</string>
- <string name="notification_app_settings" msgid="3743278649182392015">"Personalizar: <xliff:g id="SUB_CATEGORY">%1$s</xliff:g>"</string>
+ <string name="notification_app_settings" msgid="420348114670768449">"Personalizar"</string>
<string name="notification_done" msgid="5279426047273930175">"Listo"</string>
+ <string name="inline_undo" msgid="558916737624706010">"Deshacer"</string>
<string name="notification_menu_accessibility" msgid="2046162834248888553">"<xliff:g id="MENU_DESCRIPTION">%2$s</xliff:g> de <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
<string name="notification_menu_gear_description" msgid="2204480013726775108">"Controles de las notificaciones"</string>
<string name="notification_menu_snooze_description" msgid="3653669438131034525">"Opciones para posponer las notificaciones"</string>
diff --git a/packages/SystemUI/res/values-et/strings.xml b/packages/SystemUI/res/values-et/strings.xml
index 84cbc444bead..1b8ad6530ed0 100644
--- a/packages/SystemUI/res/values-et/strings.xml
+++ b/packages/SystemUI/res/values-et/strings.xml
@@ -33,7 +33,10 @@
<string name="status_bar_ongoing_events_title" msgid="1682504513316879202">"Jätkuv"</string>
<string name="status_bar_latest_events_title" msgid="6594767438577593172">"Märguanded"</string>
<string name="battery_low_title" msgid="6456385927409742437">"Aku hakkab tühjaks saama"</string>
+ <string name="battery_low_title_hybrid" msgid="6268991275887381595">"Aku hakkab tühjaks saama. Lülitage sisse akusäästja"</string>
<string name="battery_low_percent_format" msgid="2900940511201380775">"Jäänud on <xliff:g id="PERCENTAGE">%s</xliff:g>"</string>
+ <string name="battery_low_percent_format_hybrid" msgid="6838677459286775617">"<xliff:g id="PERCENTAGE">%s</xliff:g> on alles, teie kasutuse põhjal on jäänud umbes <xliff:g id="TIME">%s</xliff:g>"</string>
+ <string name="battery_low_percent_format_hybrid_short" msgid="9025795469949145586">"<xliff:g id="PERCENTAGE">%s</xliff:g> on alles, umbes <xliff:g id="TIME">%s</xliff:g> on jäänud"</string>
<string name="battery_low_percent_format_saver_started" msgid="7879389868952879166">"Jäänud on <xliff:g id="PERCENTAGE">%s</xliff:g>. Akusäästja on sisse lülitatud."</string>
<string name="invalid_charger" msgid="4549105996740522523">"USB laadimist ei toetata.\nKasutage ainult tootja laadija."</string>
<string name="invalid_charger_title" msgid="3515740382572798460">"USB-ga laadimist ei toetata."</string>
@@ -67,14 +70,15 @@
<string name="usb_debugging_secondary_user_message" msgid="6067122453571699801">"Sellesse seadmesse praegu sisse logitud kasutaja ei saa USB-silumist sisse lülitada. Selle funktsiooni kasutamiseks vahetage peamisele kasutajale."</string>
<string name="compat_mode_on" msgid="6623839244840638213">"Suumi ekraani täitmiseks"</string>
<string name="compat_mode_off" msgid="4434467572461327898">"Venita ekraani täitmiseks"</string>
+ <string name="global_action_screenshot" msgid="8329831278085426283">"Ekraanipilt"</string>
<string name="screenshot_saving_ticker" msgid="7403652894056693515">"Kuvatõmmise salvestamine ..."</string>
<string name="screenshot_saving_title" msgid="8242282144535555697">"Kuvatõmmise salvestamine ..."</string>
- <string name="screenshot_saving_text" msgid="2419718443411738818">"Kuvatõmmist salvestatakse."</string>
- <string name="screenshot_saved_title" msgid="6461865960961414961">"Ekraanipilt on jäädvustatud."</string>
- <string name="screenshot_saved_text" msgid="2685605830386712477">"Puudutage ekraanipildi vaatamiseks."</string>
- <string name="screenshot_failed_title" msgid="705781116746922771">"Kuvatõmmist ei saanud jäädvustada."</string>
- <string name="screenshot_failed_to_save_unknown_text" msgid="7887826345701753830">"Ekraanipildi salvestamisel ilmnes probleem."</string>
- <string name="screenshot_failed_to_save_text" msgid="2592658083866306296">"Piiratud salvestusruumi tõttu ei saa ekraanipilti salvestada."</string>
+ <string name="screenshot_saving_text" msgid="2545047868936087248">"Ekraanipilti salvestatakse"</string>
+ <string name="screenshot_saved_title" msgid="5637073968117370753">"Ekraanipilt salvestati"</string>
+ <string name="screenshot_saved_text" msgid="7574667448002050363">"Puudutage ekraanipildi vaatamiseks"</string>
+ <string name="screenshot_failed_title" msgid="9096484883063264803">"Ekraanipilti ei saanud jäädvustada"</string>
+ <string name="screenshot_failed_to_save_unknown_text" msgid="8844781948876286488">"Ekraanipildi salvestamisel ilmnes probleem"</string>
+ <string name="screenshot_failed_to_save_text" msgid="3041612585107107310">"Piiratud salvestusruumi tõttu ei saa ekraanipilti salvestada"</string>
<string name="screenshot_failed_to_capture_text" msgid="173674476457581486">"Rakendus või teie organisatsioon ei luba ekraanipilte jäädvustada"</string>
<string name="usb_preference_title" msgid="6551050377388882787">"USB-failiedastuse valikud"</string>
<string name="use_mtp_button_title" msgid="4333504413563023626">"Paigalda meediumimängijana (MTP)"</string>
@@ -559,26 +563,19 @@
<string name="tuner_full_importance_settings_off" msgid="8208165412614935229">"Väljas"</string>
<string name="power_notification_controls_description" msgid="4372459941671353358">"Toite märguannete juhtnuppudega saate määrata rakenduse märguannete tähtsuse taseme vahemikus 0–5. \n\n"<b>"5. tase"</b>" \n- Kuva märguannete loendi ülaosas\n- Luba täisekraanil häirimine \n- Kuva alati ekraani servas \n\n"<b>"4. tase"</b>" \n- Keela täisekraanil häirimine \n- Kuva alati ekraani servas \n\n"<b>"3. tase"</b>" \n- Keela täisekraanil häirimine \n- Ära kunagi kuva ekraani servas \n\n"<b>"2. tase"</b>" \n- Keela täisekraanil häirimine \n- Ära kunagi kuva ekraani servas \n- Ära kunagi helise ega vibreeri \n\n"<b>"1. tase"</b>" \n- Keela täisekraanil häirimine \n- Ära kunagi kuva ekraani servas \n- Ära kunagi helise ega vibreeri \n- Peida lukustuskuval ja olekuribal \n- Kuva märguannete loendi allosas \n\n"<b>"Tase 0"</b>" \n- Blokeeri kõik rakenduse märguanded"</string>
<string name="notification_header_default_channel" msgid="7506845022070889909">"Märguanded"</string>
- <string name="notification_channel_disabled" msgid="2139193533791840539">"Te ei saa enam neid märguandeid"</string>
- <string name="notification_num_channels" msgid="2048144408999179471">"<xliff:g id="NUMBER">%d</xliff:g> märguandekategooriat"</string>
- <string name="notification_default_channel_desc" msgid="2506053815870808359">"Sellel rakendusel ei ole märguannete kategooriaid"</string>
- <string name="notification_unblockable_desc" msgid="3561016061737896906">"Selle rakenduse märguandeid ei saa välja lülitada"</string>
- <plurals name="notification_num_channels_desc" formatted="false" msgid="5492793452274077663">
- <item quantity="other">1 <xliff:g id="NUMBER_1">%s</xliff:g>-st märguannete kategooriast sellelt rakenduselt</item>
- <item quantity="one">1 <xliff:g id="NUMBER_0">%s</xliff:g>-st märguannete kategooriast sellelt rakenduselt</item>
- </plurals>
- <string name="notification_channels_list_desc_2" msgid="6214732715833946441">"<xliff:g id="CHANNEL_NAME_1">%1$s</xliff:g>, <xliff:g id="CHANNEL_NAME_2">%2$s</xliff:g>"</string>
- <plurals name="notification_channels_list_desc_2_and_others" formatted="false" msgid="2747813553355336157">
- <item quantity="other"><xliff:g id="CHANNEL_NAME_1_3">%1$s</xliff:g>, <xliff:g id="CHANNEL_NAME_2_4">%2$s</xliff:g> ja veel <xliff:g id="NUMBER_5">%3$d</xliff:g> kanalit</item>
- <item quantity="one"><xliff:g id="CHANNEL_NAME_1_0">%1$s</xliff:g>, <xliff:g id="CHANNEL_NAME_2_1">%2$s</xliff:g> ja veel <xliff:g id="NUMBER_2">%3$d</xliff:g> kanal</item>
- </plurals>
+ <string name="notification_channel_disabled" msgid="344536703863700565">"Te ei näe enam neid märguandeid"</string>
+ <string name="inline_keep_showing" msgid="8945102997083836858">"Kas soovite nende märguannete kuvamist jätkata?"</string>
+ <string name="inline_stop_button" msgid="4172980096860941033">"Peata märguanded"</string>
+ <string name="inline_keep_button" msgid="6665940297019018232">"Jätka kuvamist"</string>
+ <string name="inline_keep_showing_app" msgid="1723113469580031041">"Kas jätkata selle rakenduse märguannete kuvamist?"</string>
+ <string name="notification_unblockable_desc" msgid="1037434112919403708">"Neid märguandeid ei saa välja lülitada"</string>
<string name="notification_channel_controls_opened_accessibility" msgid="6553950422055908113">"Rakenduse <xliff:g id="APP_NAME">%1$s</xliff:g> märguannete juhtelemendid on avatud"</string>
<string name="notification_channel_controls_closed_accessibility" msgid="7521619812603693144">"Rakenduse <xliff:g id="APP_NAME">%1$s</xliff:g> märguannete juhtelemendid on suletud"</string>
<string name="notification_channel_switch_accessibility" msgid="3420796005601900717">"Lubab selle kanali märguanded"</string>
- <string name="notification_all_categories" msgid="5407190218055113282">"Kõik kategooriad"</string>
<string name="notification_more_settings" msgid="816306283396553571">"Rohkem seadeid"</string>
- <string name="notification_app_settings" msgid="3743278649182392015">"Kohandamine: <xliff:g id="SUB_CATEGORY">%1$s</xliff:g>"</string>
+ <string name="notification_app_settings" msgid="420348114670768449">"Kohandamine"</string>
<string name="notification_done" msgid="5279426047273930175">"Valmis"</string>
+ <string name="inline_undo" msgid="558916737624706010">"Võta tagasi"</string>
<string name="notification_menu_accessibility" msgid="2046162834248888553">"<xliff:g id="APP_NAME">%1$s</xliff:g>, <xliff:g id="MENU_DESCRIPTION">%2$s</xliff:g>"</string>
<string name="notification_menu_gear_description" msgid="2204480013726775108">"märguannete juhtnupud"</string>
<string name="notification_menu_snooze_description" msgid="3653669438131034525">"märguannete edasilükkamise valikud"</string>
@@ -733,8 +730,7 @@
<string name="pip_phone_expand" msgid="5889780005575693909">"Laiendamine"</string>
<string name="pip_phone_minimize" msgid="1079119422589131792">"Minimeeri"</string>
<string name="pip_phone_close" msgid="8416647892889710330">"Sule"</string>
- <!-- no translation found for pip_phone_settings (8080777499521528521) -->
- <skip />
+ <string name="pip_phone_settings" msgid="8080777499521528521">"Seaded"</string>
<string name="pip_phone_dismiss_hint" msgid="6351678169095923899">"Loobumiseks lohistage alla"</string>
<string name="pip_menu_title" msgid="4707292089961887657">"Menüü"</string>
<string name="pip_notification_title" msgid="3204024940158161322">"<xliff:g id="NAME">%s</xliff:g> on režiimis Pilt pildis"</string>
diff --git a/packages/SystemUI/res/values-eu/strings.xml b/packages/SystemUI/res/values-eu/strings.xml
index 1e5274eb55b4..1d49b3be15b9 100644
--- a/packages/SystemUI/res/values-eu/strings.xml
+++ b/packages/SystemUI/res/values-eu/strings.xml
@@ -33,13 +33,10 @@
<string name="status_bar_ongoing_events_title" msgid="1682504513316879202">"Abian"</string>
<string name="status_bar_latest_events_title" msgid="6594767438577593172">"Jakinarazpenak"</string>
<string name="battery_low_title" msgid="6456385927409742437">"Bateria agortzen ari da"</string>
- <!-- no translation found for battery_low_title_hybrid (6268991275887381595) -->
- <skip />
+ <string name="battery_low_title_hybrid" msgid="6268991275887381595">"Bateria gutxi gelditzen da. Aktibatu Bateria-aurrezlea."</string>
<string name="battery_low_percent_format" msgid="2900940511201380775">"<xliff:g id="PERCENTAGE">%s</xliff:g> gelditzen da"</string>
- <!-- no translation found for battery_low_percent_format_hybrid (6838677459286775617) -->
- <skip />
- <!-- no translation found for battery_low_percent_format_hybrid_short (9025795469949145586) -->
- <skip />
+ <string name="battery_low_percent_format_hybrid" msgid="6838677459286775617">"<xliff:g id="PERCENTAGE">%s</xliff:g> gelditzen da; <xliff:g id="TIME">%s</xliff:g> inguru gelditzen dira, erabileraren arabera"</string>
+ <string name="battery_low_percent_format_hybrid_short" msgid="9025795469949145586">"<xliff:g id="PERCENTAGE">%s</xliff:g> gelditzen da; <xliff:g id="TIME">%s</xliff:g> inguru gelditzen dira"</string>
<string name="battery_low_percent_format_saver_started" msgid="7879389868952879166">"<xliff:g id="PERCENTAGE">%s</xliff:g> gelditzen da. Bateria-aurrezlea aktibatuta dago."</string>
<string name="invalid_charger" msgid="4549105996740522523">"Ez da USB bidez kargatzea onartzen.\nErabili hornitu zaizun kargagailua soilik."</string>
<string name="invalid_charger_title" msgid="3515740382572798460">"Ez da USB bidez kargatzea onartzen."</string>
@@ -73,22 +70,15 @@
<string name="usb_debugging_secondary_user_message" msgid="6067122453571699801">"Gailu honetan saioa hasita duen erabiltzaileak ezin du aktibatu USB arazketa. Eginbide hori erabiltzeko, aldatu erabiltzaile nagusira."</string>
<string name="compat_mode_on" msgid="6623839244840638213">"Handiagotu pantaila betetzeko"</string>
<string name="compat_mode_off" msgid="4434467572461327898">"Luzatu pantaila betetzeko"</string>
- <!-- no translation found for global_action_screenshot (8329831278085426283) -->
- <skip />
+ <string name="global_action_screenshot" msgid="8329831278085426283">"Pantaila-argazkia"</string>
<string name="screenshot_saving_ticker" msgid="7403652894056693515">"Pantaila-argazkia gordetzen…"</string>
<string name="screenshot_saving_title" msgid="8242282144535555697">"Pantaila-argazkia gordetzen…"</string>
- <!-- no translation found for screenshot_saving_text (2545047868936087248) -->
- <skip />
- <!-- no translation found for screenshot_saved_title (5637073968117370753) -->
- <skip />
- <!-- no translation found for screenshot_saved_text (7574667448002050363) -->
- <skip />
- <!-- no translation found for screenshot_failed_title (9096484883063264803) -->
- <skip />
- <!-- no translation found for screenshot_failed_to_save_unknown_text (8844781948876286488) -->
- <skip />
- <!-- no translation found for screenshot_failed_to_save_text (3041612585107107310) -->
- <skip />
+ <string name="screenshot_saving_text" msgid="2545047868936087248">"Pantaila-argazkia gordetzen ari da"</string>
+ <string name="screenshot_saved_title" msgid="5637073968117370753">"Gorde da pantaila-argazkia"</string>
+ <string name="screenshot_saved_text" msgid="7574667448002050363">"Sakatu pantaila-argazkia ikusteko"</string>
+ <string name="screenshot_failed_title" msgid="9096484883063264803">"Ezin izan da atera pantaila-argazkia"</string>
+ <string name="screenshot_failed_to_save_unknown_text" msgid="8844781948876286488">"Arazo bat izan da pantaila-argazkia gordetzean"</string>
+ <string name="screenshot_failed_to_save_text" msgid="3041612585107107310">"Ezin da atera pantaila-argazkia ez delako gelditzen tokirik"</string>
<string name="screenshot_failed_to_capture_text" msgid="173674476457581486">"Aplikazioak edo erakundeak ez du onartzen pantaila-argazkiak ateratzea"</string>
<string name="usb_preference_title" msgid="6551050377388882787">"USB fitxategiak transferitzeko aukerak"</string>
<string name="use_mtp_button_title" msgid="4333504413563023626">"Muntatu multimedia-erreproduzigailu gisa (MTP)"</string>
@@ -573,27 +563,19 @@
<string name="tuner_full_importance_settings_off" msgid="8208165412614935229">"Desaktibatuta"</string>
<string name="power_notification_controls_description" msgid="4372459941671353358">"Bateria-mailaren arabera jakinarazpenak kontrolatzeko aukerekin, 0 eta 5 bitarteko garrantzi-mailetan sailka ditzakezu aplikazioen jakinarazpenak. \n\n"<b>"5. maila"</b>" \n- Erakutsi jakinarazpenen zerrendaren goialdean. \n- Baimendu etetea pantaila osoko moduan zaudenean. \n- Agerrarazi beti jakinarazpenak. \n\n"<b>"4. maila"</b>" \n- Galarazi etetea pantaila osoko moduan zaudenean. \n- Agerrarazi beti jakinarazpenak. \n\n"<b>"3. maila"</b>" \n- Galarazi etetea pantaila osoko moduan zaudenean. \n- Ez agerrarazi jakinarazpenik inoiz. \n\n"<b>"2. maila"</b>" \n- Galarazi etetea pantaila osoko moduan zaudenean. \n- Ez agerrarazi jakinarazpenik inoiz. \n- Ez egin soinurik edo dardararik inoiz. \n\n"<b>"1. maila"</b>" \n- Galarazi etetea pantaila osoko moduan zaudenean. \n- Ez agerrarazi jakinarazpenik inoiz. \n- Ez egin soinurik edo dardararik inoiz. \n- Ezkutatu pantaila blokeatutik eta egoera-barratik. \n- Erakutsi jakinarazpenen zerrendaren behealdean. \n\n"<b>"0. maila"</b>" \n- Blokeatu aplikazioaren jakinarazpen guztiak."</string>
<string name="notification_header_default_channel" msgid="7506845022070889909">"Jakinarazpenak"</string>
- <!-- no translation found for notification_channel_disabled (344536703863700565) -->
- <skip />
- <!-- no translation found for inline_keep_showing (8945102997083836858) -->
- <skip />
- <!-- no translation found for inline_stop_button (4172980096860941033) -->
- <skip />
- <!-- no translation found for inline_keep_button (6665940297019018232) -->
- <skip />
- <!-- no translation found for inline_keep_showing_app (1723113469580031041) -->
- <skip />
- <!-- no translation found for notification_unblockable_desc (1037434112919403708) -->
- <skip />
+ <string name="notification_channel_disabled" msgid="344536703863700565">"Aurrerantzean ez duzu ikusiko horrelako jakinarazpenik"</string>
+ <string name="inline_keep_showing" msgid="8945102997083836858">"Jakinarazpenak erakusten jarraitzea nahi duzu?"</string>
+ <string name="inline_stop_button" msgid="4172980096860941033">"Blokeatu jakinarazpenak"</string>
+ <string name="inline_keep_button" msgid="6665940297019018232">"Jarraitu erakusten"</string>
+ <string name="inline_keep_showing_app" msgid="1723113469580031041">"Aplikazio honen jakinarazpenak erakusten jarraitzea nahi duzu?"</string>
+ <string name="notification_unblockable_desc" msgid="1037434112919403708">"Jakinarazpen hauek ezin dira desaktibatu"</string>
<string name="notification_channel_controls_opened_accessibility" msgid="6553950422055908113">"Ireki dira <xliff:g id="APP_NAME">%1$s</xliff:g> aplikazioaren jakinarazpenak kontrolatzeko aukerak"</string>
<string name="notification_channel_controls_closed_accessibility" msgid="7521619812603693144">"Itxi dira <xliff:g id="APP_NAME">%1$s</xliff:g> aplikazioaren jakinarazpenak kontrolatzeko aukerak"</string>
<string name="notification_channel_switch_accessibility" msgid="3420796005601900717">"Onartu kanal honen jakinarazpenak"</string>
<string name="notification_more_settings" msgid="816306283396553571">"Ezarpen gehiago"</string>
- <!-- no translation found for notification_app_settings (420348114670768449) -->
- <skip />
+ <string name="notification_app_settings" msgid="420348114670768449">"Pertsonalizatu"</string>
<string name="notification_done" msgid="5279426047273930175">"Eginda"</string>
- <!-- no translation found for inline_undo (558916737624706010) -->
- <skip />
+ <string name="inline_undo" msgid="558916737624706010">"Desegin"</string>
<string name="notification_menu_accessibility" msgid="2046162834248888553">"<xliff:g id="APP_NAME">%1$s</xliff:g> <xliff:g id="MENU_DESCRIPTION">%2$s</xliff:g>"</string>
<string name="notification_menu_gear_description" msgid="2204480013726775108">"jakinarazpena kontrolatzeko aukerak"</string>
<string name="notification_menu_snooze_description" msgid="3653669438131034525">"jakinarazpena atzeratzeko aukerak"</string>
diff --git a/packages/SystemUI/res/values-fa/strings.xml b/packages/SystemUI/res/values-fa/strings.xml
index 834397d8c702..e5975696614d 100644
--- a/packages/SystemUI/res/values-fa/strings.xml
+++ b/packages/SystemUI/res/values-fa/strings.xml
@@ -33,7 +33,10 @@
<string name="status_bar_ongoing_events_title" msgid="1682504513316879202">"در حال انجام"</string>
<string name="status_bar_latest_events_title" msgid="6594767438577593172">"اعلان‌ها"</string>
<string name="battery_low_title" msgid="6456385927409742437">"شارژ باتری کم است"</string>
+ <string name="battery_low_title_hybrid" msgid="6268991275887381595">"شارژ باتری کم است. «بهینه‌سازی باتری» را روشن کنید"</string>
<string name="battery_low_percent_format" msgid="2900940511201380775">"<xliff:g id="PERCENTAGE">%s</xliff:g> باقی مانده است"</string>
+ <string name="battery_low_percent_format_hybrid" msgid="6838677459286775617">"<xliff:g id="PERCENTAGE">%s</xliff:g> باقی مانده، براساس میزان مصرف شما حدود <xliff:g id="TIME">%s</xliff:g> باقی مانده است"</string>
+ <string name="battery_low_percent_format_hybrid_short" msgid="9025795469949145586">"<xliff:g id="PERCENTAGE">%s</xliff:g> باقی مانده، حدود <xliff:g id="TIME">%s</xliff:g> باقی مانده است"</string>
<string name="battery_low_percent_format_saver_started" msgid="7879389868952879166">"<xliff:g id="PERCENTAGE">%s</xliff:g> باقی مانده است. بهینه‌سازی باتری روشن است."</string>
<string name="invalid_charger" msgid="4549105996740522523">"‏شارژ USB پشتیبانی نمی‌شود.\nفقط از شارژر ارائه شده استفاده کنید."</string>
<string name="invalid_charger_title" msgid="3515740382572798460">"‏شارژ با USB پشتیبانی نمی‌شود."</string>
@@ -67,14 +70,15 @@
<string name="usb_debugging_secondary_user_message" msgid="6067122453571699801">"‏کاربری که درحال حاضر در این دستگاه وارد سیستم شده است نمی‌تواند اشکال‌زدایی USB را روشن کند. برای استفاده از این قابلیت، به کاربر اصلی تغییر وضعیت دهید."</string>
<string name="compat_mode_on" msgid="6623839244840638213">"بزرگ‌نمایی برای پر کردن صفحه"</string>
<string name="compat_mode_off" msgid="4434467572461327898">"گسترده کردن برای پر کردن صفحه"</string>
+ <string name="global_action_screenshot" msgid="8329831278085426283">"عکس صفحه‌نمایش"</string>
<string name="screenshot_saving_ticker" msgid="7403652894056693515">"در حال ذخیره عکس صفحه‌نمایش..."</string>
<string name="screenshot_saving_title" msgid="8242282144535555697">"در حال ذخیره عکس صفحه‌نمایش..."</string>
- <string name="screenshot_saving_text" msgid="2419718443411738818">"عکس صفحه‌نمایش ذخیره شد."</string>
- <string name="screenshot_saved_title" msgid="6461865960961414961">"عکس صفحه‌نمایش گرفته شد."</string>
- <string name="screenshot_saved_text" msgid="2685605830386712477">"برای مشاهده عکس صفحه‌نمایشتان ضربه بزنید."</string>
- <string name="screenshot_failed_title" msgid="705781116746922771">"عکس صفحه‌نمایش گرفته نشد."</string>
- <string name="screenshot_failed_to_save_unknown_text" msgid="7887826345701753830">"هنگام ذخیره عکس صفحه‌نمایش مشکلی رخ داد."</string>
- <string name="screenshot_failed_to_save_text" msgid="2592658083866306296">"به دلیل محدود بودن فضای ذخیره‌سازی نمی‌توانید عکس صفحه‌نمایش را ذخیره کنید."</string>
+ <string name="screenshot_saving_text" msgid="2545047868936087248">"عکس صفحه‌نمایش درحال ذخیره شدن است"</string>
+ <string name="screenshot_saved_title" msgid="5637073968117370753">"عکس صفحه‌نمایش ذخیره شد"</string>
+ <string name="screenshot_saved_text" msgid="7574667448002050363">"برای مشاهده عکس صفحه‌نمایشتان ضربه بزنید"</string>
+ <string name="screenshot_failed_title" msgid="9096484883063264803">"عکس صفحه‌نمایش گرفته نشد"</string>
+ <string name="screenshot_failed_to_save_unknown_text" msgid="8844781948876286488">"هنگام ذخیره کردن عکس صفحه‌نمایش مشکلی پیش آمد"</string>
+ <string name="screenshot_failed_to_save_text" msgid="3041612585107107310">"به دلیل محدود بودن فضای ذخیره‌سازی نمی‌توان عکس صفحه‌نمایش را ذخیره کرد"</string>
<string name="screenshot_failed_to_capture_text" msgid="173674476457581486">"برنامه یا سازمان شما اجازه نمی‌دهند عکس صفحه‌نمایش بگیرید."</string>
<string name="usb_preference_title" msgid="6551050377388882787">"‏گزینه‌های انتقال فایل USB"</string>
<string name="use_mtp_button_title" msgid="4333504413563023626">"‏نصب به‌عنوان دستگاه پخش رسانه (MTP)"</string>
@@ -557,26 +561,19 @@
<string name="tuner_full_importance_settings_off" msgid="8208165412614935229">"خاموش"</string>
<string name="power_notification_controls_description" msgid="4372459941671353358">"با کنترل‌های قدرتمند اعلان می‌توانید سطح اهمیت اعلان‌های هر برنامه را از ۰ تا ۵ تعیین کنید. \n\n"<b>"سطح ۵"</b>" \n- در صدر فهرست اعلان‌ها نشان داده می‌شود \n- وقفه برای نمایش تمام‌صفحه مجاز است \n- همیشه اجمالی نشان داده می‌شود \n\n"<b>"سطح ۴"</b>" \n- وقفه برای نمایش تمام‌صفحه مجاز نیست \n- همیشه اجمالی نشان داده می‌شود \n\n"<b>"سطح ۳"</b>" \n- وقفه برای نمایش تمام‌صفحه مجاز نیست \n- هیچ‌وقت اجمالی نشان داده نمی‌شود \n\n"<b>"سطح ۲"</b>" \n- وقفه برای نمایش تمام‌صفحه مجاز نیست \n- هیچ‌وقت اجمالی نشان داده نمی‌شود \n- هیچ‌وقت صدا و لرزش ایجاد نمی‌کند \n\n"<b>"سطح ۱"</b>" \n- نمایش تمام صفحه مجاز نیست \n- هیچ‌وقت اجمالی نشان داده نمی‌شود \n- هیچ‌وقت صدا یا لرزش ایجاد نمی‌کند \n- در قفل صفحه و نوار وضعیت پنهان است \n- در پایین فهرست اعلان‌ها نشان داده می‌شود \n\n"<b>"سطح ۰"</b>" \n- همه اعلان‌های این برنامه مسدود است"</string>
<string name="notification_header_default_channel" msgid="7506845022070889909">"اعلان‌ها"</string>
- <string name="notification_channel_disabled" msgid="2139193533791840539">"دیگر این اعلان‌ها را دریافت نخواهید کرد"</string>
- <string name="notification_num_channels" msgid="2048144408999179471">"<xliff:g id="NUMBER">%d</xliff:g> دسته اعلان"</string>
- <string name="notification_default_channel_desc" msgid="2506053815870808359">"این برنامه دسته اعلان ندارد"</string>
- <string name="notification_unblockable_desc" msgid="3561016061737896906">"نمی‌توان اعلان‌های این برنامه را خاموش کرد"</string>
- <plurals name="notification_num_channels_desc" formatted="false" msgid="5492793452274077663">
- <item quantity="one">۱ از <xliff:g id="NUMBER_1">%s</xliff:g> دسته اعلان این برنامه</item>
- <item quantity="other">۱ از <xliff:g id="NUMBER_1">%s</xliff:g> دسته اعلان این برنامه</item>
- </plurals>
- <string name="notification_channels_list_desc_2" msgid="6214732715833946441">"<xliff:g id="CHANNEL_NAME_1">%1$s</xliff:g>، <xliff:g id="CHANNEL_NAME_2">%2$s</xliff:g>"</string>
- <plurals name="notification_channels_list_desc_2_and_others" formatted="false" msgid="2747813553355336157">
- <item quantity="one"><xliff:g id="CHANNEL_NAME_1_3">%1$s</xliff:g>، <xliff:g id="CHANNEL_NAME_2_4">%2$s</xliff:g> و <xliff:g id="NUMBER_5">%3$d</xliff:g> مورد دیگر</item>
- <item quantity="other"><xliff:g id="CHANNEL_NAME_1_3">%1$s</xliff:g>، <xliff:g id="CHANNEL_NAME_2_4">%2$s</xliff:g> و <xliff:g id="NUMBER_5">%3$d</xliff:g> مورد دیگر</item>
- </plurals>
+ <string name="notification_channel_disabled" msgid="344536703863700565">"دیگر این اعلان‌ها را نخواهید دید"</string>
+ <string name="inline_keep_showing" msgid="8945102997083836858">"نمایش این اعلان‌ها ادامه یابد؟"</string>
+ <string name="inline_stop_button" msgid="4172980096860941033">"توقف اعلان‌ها"</string>
+ <string name="inline_keep_button" msgid="6665940297019018232">"همچنان نشان داده شود"</string>
+ <string name="inline_keep_showing_app" msgid="1723113469580031041">"نمایش اعلان از این برنامه ادامه یابد؟"</string>
+ <string name="notification_unblockable_desc" msgid="1037434112919403708">"نمی‌توان این اعلان‌ها را خاموش کرد"</string>
<string name="notification_channel_controls_opened_accessibility" msgid="6553950422055908113">"کنترل‌های اعلان برای <xliff:g id="APP_NAME">%1$s</xliff:g> باز شد"</string>
<string name="notification_channel_controls_closed_accessibility" msgid="7521619812603693144">"کنترل‌های اعلان برای <xliff:g id="APP_NAME">%1$s</xliff:g> بسته شد"</string>
<string name="notification_channel_switch_accessibility" msgid="3420796005601900717">"مجاز کردن اعلان‌های این کانال"</string>
- <string name="notification_all_categories" msgid="5407190218055113282">"‏همه دسته‎ها"</string>
<string name="notification_more_settings" msgid="816306283396553571">"تنظیمات بیشتر"</string>
- <string name="notification_app_settings" msgid="3743278649182392015">"سفارشی کردن: <xliff:g id="SUB_CATEGORY">%1$s</xliff:g>"</string>
+ <string name="notification_app_settings" msgid="420348114670768449">"سفارشی کردن"</string>
<string name="notification_done" msgid="5279426047273930175">"تمام"</string>
+ <string name="inline_undo" msgid="558916737624706010">"واگرد"</string>
<string name="notification_menu_accessibility" msgid="2046162834248888553">"<xliff:g id="APP_NAME">%1$s</xliff:g> <xliff:g id="MENU_DESCRIPTION">%2$s</xliff:g>"</string>
<string name="notification_menu_gear_description" msgid="2204480013726775108">"کنترل‌های اعلان"</string>
<string name="notification_menu_snooze_description" msgid="3653669438131034525">"گزینه‌های تعویق اعلان"</string>
diff --git a/packages/SystemUI/res/values-fi/strings.xml b/packages/SystemUI/res/values-fi/strings.xml
index 51a71dedde22..59327c6107b9 100644
--- a/packages/SystemUI/res/values-fi/strings.xml
+++ b/packages/SystemUI/res/values-fi/strings.xml
@@ -33,7 +33,10 @@
<string name="status_bar_ongoing_events_title" msgid="1682504513316879202">"Käynnissä olevat"</string>
<string name="status_bar_latest_events_title" msgid="6594767438577593172">"Ilmoitukset"</string>
<string name="battery_low_title" msgid="6456385927409742437">"Akku on vähissä"</string>
+ <string name="battery_low_title_hybrid" msgid="6268991275887381595">"Akku on vähissä, ota virransäästö käyttöön"</string>
<string name="battery_low_percent_format" msgid="2900940511201380775">"<xliff:g id="PERCENTAGE">%s</xliff:g> jäljellä"</string>
+ <string name="battery_low_percent_format_hybrid" msgid="6838677459286775617">"<xliff:g id="PERCENTAGE">%s</xliff:g> käytettävissä, noin <xliff:g id="TIME">%s</xliff:g> jäljellä käytön perusteella"</string>
+ <string name="battery_low_percent_format_hybrid_short" msgid="9025795469949145586">"<xliff:g id="PERCENTAGE">%s</xliff:g> käytettävissä, noin <xliff:g id="TIME">%s</xliff:g> jäljellä"</string>
<string name="battery_low_percent_format_saver_started" msgid="7879389868952879166">"<xliff:g id="PERCENTAGE">%s</xliff:g> jäljellä. Virransäästö on käytössä."</string>
<string name="invalid_charger" msgid="4549105996740522523">"USB-latausta ei tueta.\nKäytä laitteen mukana tullutta laturia."</string>
<string name="invalid_charger_title" msgid="3515740382572798460">"USB-latausta ei tueta."</string>
@@ -67,14 +70,15 @@
<string name="usb_debugging_secondary_user_message" msgid="6067122453571699801">"Laitteelle tällä hetkellä kirjautunut käyttäjä ei voi ottaa USB-vianetsintää käyttöön. Vaihda käyttäjäksi ensisijainen käyttäjä, jotta voit käyttää tätä ominaisuutta."</string>
<string name="compat_mode_on" msgid="6623839244840638213">"Zoomaa koko näyttöön"</string>
<string name="compat_mode_off" msgid="4434467572461327898">"Venytä koko näyttöön"</string>
+ <string name="global_action_screenshot" msgid="8329831278085426283">"Kuvakaappaus"</string>
<string name="screenshot_saving_ticker" msgid="7403652894056693515">"Tallennetaan kuvakaappausta..."</string>
<string name="screenshot_saving_title" msgid="8242282144535555697">"Tallennetaan kuvakaappausta..."</string>
- <string name="screenshot_saving_text" msgid="2419718443411738818">"Kuvakaappausta tallennetaan."</string>
- <string name="screenshot_saved_title" msgid="6461865960961414961">"Kuvakaappaus tallennettu"</string>
- <string name="screenshot_saved_text" msgid="2685605830386712477">"Tarkastele kuvakaappausta napauttamalla"</string>
- <string name="screenshot_failed_title" msgid="705781116746922771">"Kuvakaappausta ei voitu tallentaa"</string>
- <string name="screenshot_failed_to_save_unknown_text" msgid="7887826345701753830">"Kuvakaappausta tallennettaessa tapahtui virhe."</string>
- <string name="screenshot_failed_to_save_text" msgid="2592658083866306296">"Kuvakaappauksen tallentaminen epäonnistui, sillä tallennustilaa ei ole riittävästi."</string>
+ <string name="screenshot_saving_text" msgid="2545047868936087248">"Kuvakaappausta tallennetaan"</string>
+ <string name="screenshot_saved_title" msgid="5637073968117370753">"Kuvakaappaus tallennettu"</string>
+ <string name="screenshot_saved_text" msgid="7574667448002050363">"Napauta katsoaksesi kuvakaappausta"</string>
+ <string name="screenshot_failed_title" msgid="9096484883063264803">"Kuvakaappauksen tallennus epäonnistui"</string>
+ <string name="screenshot_failed_to_save_unknown_text" msgid="8844781948876286488">"Kuvakaappausta tallennettaessa tapahtui virhe"</string>
+ <string name="screenshot_failed_to_save_text" msgid="3041612585107107310">"Kuvakaappauksen tallennus epäonnistui, sillä tallennustilaa ei ole riittävästi"</string>
<string name="screenshot_failed_to_capture_text" msgid="173674476457581486">"Sovellus tai organisaatio ei salli kuvakaappauksien tallentamista."</string>
<string name="usb_preference_title" msgid="6551050377388882787">"USB-tiedostonsiirtoasetukset"</string>
<string name="use_mtp_button_title" msgid="4333504413563023626">"Käytä mediasoittimena (MTP)"</string>
@@ -557,26 +561,19 @@
<string name="tuner_full_importance_settings_off" msgid="8208165412614935229">"Pois käytöstä"</string>
<string name="power_notification_controls_description" msgid="4372459941671353358">"Ilmoitusten tehohallinnan avulla voit määrittää sovelluksen ilmoituksille tärkeystason väliltä 0–5. \n\n"<b>"Taso 5"</b>" \n– Ilmoitukset näytetään ilmoitusluettelon yläosassa \n– Näkyminen koko näytön tilassa sallitaan \n– Ilmoitukset kurkistavat aina näytölle\n\n"<b>"Taso 4"</b>" \n– Näkyminen koko näytön tilassa estetään \n– Ilmoitukset kurkistavat aina näytölle \n\n"<b>"Taso 3"</b>" \n– Näkyminen koko näytön tilassa estetään \n– Ei kurkistamista \n\n"<b>"Taso 2"</b>" \n– Näkyminen koko näytön tilassa estetään \n– Ei kurkistamista \n– Ei ääniä eikä värinää \n\n"<b>"Taso 1"</b>" \n– Näkyminen koko näytön tilassa estetään \n– Ei kurkistamista \n– Ei ääniä eikä värinää \n– Ilmoitukset piilotetaan lukitusnäytöltä ja tilapalkista \n– Ilmoitukset näytetään ilmoitusluettelon alaosassa \n\n"<b>"Taso 0"</b>" \n– Kaikki sovelluksen ilmoitukset estetään"</string>
<string name="notification_header_default_channel" msgid="7506845022070889909">"Ilmoitukset"</string>
- <string name="notification_channel_disabled" msgid="2139193533791840539">"Et saa näitä ilmoituksia enää."</string>
- <string name="notification_num_channels" msgid="2048144408999179471">"<xliff:g id="NUMBER">%d</xliff:g> ilmoitusluokkaa"</string>
- <string name="notification_default_channel_desc" msgid="2506053815870808359">"Tällä sovelluksella ei ole ilmoitusluokkia."</string>
- <string name="notification_unblockable_desc" msgid="3561016061737896906">"Tämän sovelluksen ilmoituksia ei voi poistaa käytöstä."</string>
- <plurals name="notification_num_channels_desc" formatted="false" msgid="5492793452274077663">
- <item quantity="other">Tämä sovellus: 1/<xliff:g id="NUMBER_1">%s</xliff:g> ilmoitusluokkaa</item>
- <item quantity="one">Tämä sovellus: 1/<xliff:g id="NUMBER_0">%s</xliff:g> ilmoitusluokkaa</item>
- </plurals>
- <string name="notification_channels_list_desc_2" msgid="6214732715833946441">"<xliff:g id="CHANNEL_NAME_1">%1$s</xliff:g>, <xliff:g id="CHANNEL_NAME_2">%2$s</xliff:g>"</string>
- <plurals name="notification_channels_list_desc_2_and_others" formatted="false" msgid="2747813553355336157">
- <item quantity="other"><xliff:g id="CHANNEL_NAME_1_3">%1$s</xliff:g>, <xliff:g id="CHANNEL_NAME_2_4">%2$s</xliff:g> ja <xliff:g id="NUMBER_5">%3$d</xliff:g> muuta</item>
- <item quantity="one"><xliff:g id="CHANNEL_NAME_1_0">%1$s</xliff:g>, <xliff:g id="CHANNEL_NAME_2_1">%2$s</xliff:g> ja <xliff:g id="NUMBER_2">%3$d</xliff:g> toinen</item>
- </plurals>
+ <string name="notification_channel_disabled" msgid="344536703863700565">"Et näe näitä ilmoituksia enää"</string>
+ <string name="inline_keep_showing" msgid="8945102997083836858">"Jatketaanko näiden ilmoitusten näyttämistä?"</string>
+ <string name="inline_stop_button" msgid="4172980096860941033">"Lopeta ilmoitukset"</string>
+ <string name="inline_keep_button" msgid="6665940297019018232">"Jatka näyttämistä"</string>
+ <string name="inline_keep_showing_app" msgid="1723113469580031041">"Jatketaanko ilmoitusten näyttämistä tästä sovelluksesta?"</string>
+ <string name="notification_unblockable_desc" msgid="1037434112919403708">"Näitä ilmoituksia ei voi poistaa käytöstä"</string>
<string name="notification_channel_controls_opened_accessibility" msgid="6553950422055908113">"Sovelluksen <xliff:g id="APP_NAME">%1$s</xliff:g> ilmoitusten hallinta on avattu."</string>
<string name="notification_channel_controls_closed_accessibility" msgid="7521619812603693144">"Sovelluksen <xliff:g id="APP_NAME">%1$s</xliff:g> ilmoitusten hallinta on suljettu."</string>
<string name="notification_channel_switch_accessibility" msgid="3420796005601900717">"Salli ilmoitukset tältä kanavalta."</string>
- <string name="notification_all_categories" msgid="5407190218055113282">"Kaikki luokat"</string>
<string name="notification_more_settings" msgid="816306283396553571">"Lisäasetukset"</string>
- <string name="notification_app_settings" msgid="3743278649182392015">"Muokkaa: <xliff:g id="SUB_CATEGORY">%1$s</xliff:g>"</string>
+ <string name="notification_app_settings" msgid="420348114670768449">"Muokkaa"</string>
<string name="notification_done" msgid="5279426047273930175">"Valmis"</string>
+ <string name="inline_undo" msgid="558916737624706010">"Kumoa"</string>
<string name="notification_menu_accessibility" msgid="2046162834248888553">"<xliff:g id="APP_NAME">%1$s</xliff:g> <xliff:g id="MENU_DESCRIPTION">%2$s</xliff:g>"</string>
<string name="notification_menu_gear_description" msgid="2204480013726775108">"Ilmoitusten hallinta"</string>
<string name="notification_menu_snooze_description" msgid="3653669438131034525">"Ilmoitusten torkkuasetukset"</string>
@@ -731,8 +728,7 @@
<string name="pip_phone_expand" msgid="5889780005575693909">"Laajenna"</string>
<string name="pip_phone_minimize" msgid="1079119422589131792">"Pienennä"</string>
<string name="pip_phone_close" msgid="8416647892889710330">"Sulje"</string>
- <!-- no translation found for pip_phone_settings (8080777499521528521) -->
- <skip />
+ <string name="pip_phone_settings" msgid="8080777499521528521">"Asetukset"</string>
<string name="pip_phone_dismiss_hint" msgid="6351678169095923899">"Hylkää vetämällä alas."</string>
<string name="pip_menu_title" msgid="4707292089961887657">"Valikko"</string>
<string name="pip_notification_title" msgid="3204024940158161322">"<xliff:g id="NAME">%s</xliff:g> on kuva kuvassa ‑tilassa"</string>
diff --git a/packages/SystemUI/res/values-gl/strings.xml b/packages/SystemUI/res/values-gl/strings.xml
index 987ea598d079..23a22e63defc 100644
--- a/packages/SystemUI/res/values-gl/strings.xml
+++ b/packages/SystemUI/res/values-gl/strings.xml
@@ -33,7 +33,10 @@
<string name="status_bar_ongoing_events_title" msgid="1682504513316879202">"En curso"</string>
<string name="status_bar_latest_events_title" msgid="6594767438577593172">"Notificacións"</string>
<string name="battery_low_title" msgid="6456385927409742437">"Queda pouca batería"</string>
+ <string name="battery_low_title_hybrid" msgid="6268991275887381595">"Queda pouca batería. Activa a función Aforro de batería"</string>
<string name="battery_low_percent_format" msgid="2900940511201380775">"<xliff:g id="PERCENTAGE">%s</xliff:g> restante"</string>
+ <string name="battery_low_percent_format_hybrid" msgid="6838677459286775617">"Queda un <xliff:g id="PERCENTAGE">%s</xliff:g>, é dicir, aproximadamente <xliff:g id="TIME">%s</xliff:g> en función do uso que fas"</string>
+ <string name="battery_low_percent_format_hybrid_short" msgid="9025795469949145586">"Queda un <xliff:g id="PERCENTAGE">%s</xliff:g>, é dicir, aproximadamente <xliff:g id="TIME">%s</xliff:g>"</string>
<string name="battery_low_percent_format_saver_started" msgid="7879389868952879166">"<xliff:g id="PERCENTAGE">%s</xliff:g> restante. Está activada a función Aforro de batería."</string>
<string name="invalid_charger" msgid="4549105996740522523">"Non compatible coa carga por USB.\nUtiliza só o cargador proporcionado."</string>
<string name="invalid_charger_title" msgid="3515740382572798460">"Non se admite a carga mediante USB."</string>
@@ -67,14 +70,15 @@
<string name="usb_debugging_secondary_user_message" msgid="6067122453571699801">"O usuario coa sesión iniciada actualmente neste dispositivo non pode activar a depuración por USB. Para utilizar esta función, cambia ao usuario principal."</string>
<string name="compat_mode_on" msgid="6623839244840638213">"Ampliar ata ocupar todo"</string>
<string name="compat_mode_off" msgid="4434467572461327898">"Estirar ata ocupar todo"</string>
+ <string name="global_action_screenshot" msgid="8329831278085426283">"Captura de pantalla"</string>
<string name="screenshot_saving_ticker" msgid="7403652894056693515">"Gardando captura de pantalla…"</string>
<string name="screenshot_saving_title" msgid="8242282144535555697">"Gardando captura de pantalla…"</string>
- <string name="screenshot_saving_text" msgid="2419718443411738818">"Estase gardando a captura de pantalla."</string>
- <string name="screenshot_saved_title" msgid="6461865960961414961">"Captura de pantalla gardada."</string>
- <string name="screenshot_saved_text" msgid="2685605830386712477">"Toca para ver a captura de pantalla."</string>
- <string name="screenshot_failed_title" msgid="705781116746922771">"Non se puido facer a captura de pantalla."</string>
- <string name="screenshot_failed_to_save_unknown_text" msgid="7887826345701753830">"Produciuse un problema ao gardar a captura de pantalla."</string>
- <string name="screenshot_failed_to_save_text" msgid="2592658083866306296">"Non se pode gardar a captura de pantalla porque o espazo de almacenamento é limitado."</string>
+ <string name="screenshot_saving_text" msgid="2545047868936087248">"Estase gardando a captura de pantalla"</string>
+ <string name="screenshot_saved_title" msgid="5637073968117370753">"Gardouse a captura de pantalla"</string>
+ <string name="screenshot_saved_text" msgid="7574667448002050363">"Toca para ver a captura de pantalla"</string>
+ <string name="screenshot_failed_title" msgid="9096484883063264803">"Non se puido facer a captura de pantalla"</string>
+ <string name="screenshot_failed_to_save_unknown_text" msgid="8844781948876286488">"Produciuse un problema ao gardar a captura de pantalla"</string>
+ <string name="screenshot_failed_to_save_text" msgid="3041612585107107310">"Non se puido gardar a captura de pantalla porque o espazo de almacenamento é limitado"</string>
<string name="screenshot_failed_to_capture_text" msgid="173674476457581486">"A aplicación ou a túa organización non permite realizar capturas de pantalla"</string>
<string name="usb_preference_title" msgid="6551050377388882787">"Opcións de transferencia USB"</string>
<string name="use_mtp_button_title" msgid="4333504413563023626">"Inserir como reprodutor multimedia (MTP)"</string>
@@ -559,26 +563,19 @@
<string name="tuner_full_importance_settings_off" msgid="8208165412614935229">"Desactivar"</string>
<string name="power_notification_controls_description" msgid="4372459941671353358">"Cos controis de notificacións mellorados, podes asignarlles un nivel de importancia comprendido entre 0 e 5 ás notificacións dunha aplicación determinada. \n\n"<b>"Nivel 5"</b>" \n- Mostrar na parte superior da lista de notificacións. \n- Permitir interrupcións no modo de pantalla completa. \n- Mostrar sempre. \n\n"<b>"Nivel 4"</b>" \n- Impedir interrupcións no modo de pantalla completa. \n- Mostrar sempre. \n\n"<b>"Nivel 3"</b>" \n- Impedir interrupcións no modo de pantalla completa. \n- Non mostrar nunca. \n\n"<b>"Nivel 2"</b>" \n- Impedir interrupcións no modo de pantalla completa. \n- Non mostrar nunca. \n- Non soar nin vibrar nunca. \n\n"<b>"Nivel 1"</b>" \n- Impedir interrupcións no modo de pantalla completa. \n- Non mostrar nunca. \n- Non soar nin vibrar nunca. \n- Ocultar na pantalla de bloqueo e na barra de estado. \n- Mostrar na parte inferior da lista de notificacións. \n\n"<b>"Nivel 0"</b>" \n- Bloquear todas as notificacións da aplicación."</string>
<string name="notification_header_default_channel" msgid="7506845022070889909">"Notificacións"</string>
- <string name="notification_channel_disabled" msgid="2139193533791840539">"Deixarás de recibir estas notificacións"</string>
- <string name="notification_num_channels" msgid="2048144408999179471">"<xliff:g id="NUMBER">%d</xliff:g> categorías de notificacións"</string>
- <string name="notification_default_channel_desc" msgid="2506053815870808359">"Esta aplicación non ten categorías de notificacións"</string>
- <string name="notification_unblockable_desc" msgid="3561016061737896906">"Non se poden desactivar as notificacións desta aplicación"</string>
- <plurals name="notification_num_channels_desc" formatted="false" msgid="5492793452274077663">
- <item quantity="other">1 de <xliff:g id="NUMBER_1">%s</xliff:g> categorías de notificacións desta aplicación</item>
- <item quantity="one">1 de <xliff:g id="NUMBER_0">%s</xliff:g> categoría de notificación desta aplicación</item>
- </plurals>
- <string name="notification_channels_list_desc_2" msgid="6214732715833946441">"<xliff:g id="CHANNEL_NAME_1">%1$s</xliff:g>, <xliff:g id="CHANNEL_NAME_2">%2$s</xliff:g>"</string>
- <plurals name="notification_channels_list_desc_2_and_others" formatted="false" msgid="2747813553355336157">
- <item quantity="other"><xliff:g id="CHANNEL_NAME_1_3">%1$s</xliff:g>, <xliff:g id="CHANNEL_NAME_2_4">%2$s</xliff:g> e <xliff:g id="NUMBER_5">%3$d</xliff:g> máis</item>
- <item quantity="one"><xliff:g id="CHANNEL_NAME_1_0">%1$s</xliff:g>, <xliff:g id="CHANNEL_NAME_2_1">%2$s</xliff:g> e <xliff:g id="NUMBER_2">%3$d</xliff:g> máis</item>
- </plurals>
+ <string name="notification_channel_disabled" msgid="344536703863700565">"Deixarás de ver estas notificacións"</string>
+ <string name="inline_keep_showing" msgid="8945102997083836858">"Queres seguir mostrando estas notificacións?"</string>
+ <string name="inline_stop_button" msgid="4172980096860941033">"Deter notificacións"</string>
+ <string name="inline_keep_button" msgid="6665940297019018232">"Continuar mostrando notificacións"</string>
+ <string name="inline_keep_showing_app" msgid="1723113469580031041">"Queres seguir mostrando as notificacións desta aplicación?"</string>
+ <string name="notification_unblockable_desc" msgid="1037434112919403708">"Non se poden desactivar estas notificacións"</string>
<string name="notification_channel_controls_opened_accessibility" msgid="6553950422055908113">"Abríronse os controis de notificacións da aplicación <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
<string name="notification_channel_controls_closed_accessibility" msgid="7521619812603693144">"Pecháronse os controis de notificacións da aplicación <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
<string name="notification_channel_switch_accessibility" msgid="3420796005601900717">"Permitir notificacións desde esta canle"</string>
- <string name="notification_all_categories" msgid="5407190218055113282">"Todas as categorías"</string>
<string name="notification_more_settings" msgid="816306283396553571">"Máis opcións"</string>
- <string name="notification_app_settings" msgid="3743278649182392015">"Personalizar: <xliff:g id="SUB_CATEGORY">%1$s</xliff:g>"</string>
+ <string name="notification_app_settings" msgid="420348114670768449">"Personalizar"</string>
<string name="notification_done" msgid="5279426047273930175">"Feito"</string>
+ <string name="inline_undo" msgid="558916737624706010">"Desfacer"</string>
<string name="notification_menu_accessibility" msgid="2046162834248888553">"<xliff:g id="MENU_DESCRIPTION">%2$s</xliff:g> de <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
<string name="notification_menu_gear_description" msgid="2204480013726775108">"controis de notificacións"</string>
<string name="notification_menu_snooze_description" msgid="3653669438131034525">"opcións para adiar notificacións"</string>
@@ -733,8 +730,7 @@
<string name="pip_phone_expand" msgid="5889780005575693909">"Despregar"</string>
<string name="pip_phone_minimize" msgid="1079119422589131792">"Minimizar"</string>
<string name="pip_phone_close" msgid="8416647892889710330">"Pechar"</string>
- <!-- no translation found for pip_phone_settings (8080777499521528521) -->
- <skip />
+ <string name="pip_phone_settings" msgid="8080777499521528521">"Configuración"</string>
<string name="pip_phone_dismiss_hint" msgid="6351678169095923899">"Arrastra cara abaixo para ignorar"</string>
<string name="pip_menu_title" msgid="4707292089961887657">"Menú"</string>
<string name="pip_notification_title" msgid="3204024940158161322">"<xliff:g id="NAME">%s</xliff:g> está na pantalla superposta"</string>
diff --git a/packages/SystemUI/res/values-hi/strings.xml b/packages/SystemUI/res/values-hi/strings.xml
index 27ed38c19787..ec3785589ade 100644
--- a/packages/SystemUI/res/values-hi/strings.xml
+++ b/packages/SystemUI/res/values-hi/strings.xml
@@ -33,13 +33,10 @@
<string name="status_bar_ongoing_events_title" msgid="1682504513316879202">"ऑनगोइंग"</string>
<string name="status_bar_latest_events_title" msgid="6594767438577593172">"सूचनाएं"</string>
<string name="battery_low_title" msgid="6456385927409742437">"बैटरी कम है"</string>
- <!-- no translation found for battery_low_title_hybrid (6268991275887381595) -->
- <skip />
+ <string name="battery_low_title_hybrid" msgid="6268991275887381595">"बैटरी कम बची है. बैटरी सेवर चालू करें"</string>
<string name="battery_low_percent_format" msgid="2900940511201380775">"<xliff:g id="PERCENTAGE">%s</xliff:g> शेष"</string>
- <!-- no translation found for battery_low_percent_format_hybrid (6838677459286775617) -->
- <skip />
- <!-- no translation found for battery_low_percent_format_hybrid_short (9025795469949145586) -->
- <skip />
+ <string name="battery_low_percent_format_hybrid" msgid="6838677459286775617">"<xliff:g id="PERCENTAGE">%s</xliff:g> बची है, आपके इस्तेमाल करने के तरीके के हिसाब से बैटरी लगभग <xliff:g id="TIME">%s</xliff:g> चलेगी"</string>
+ <string name="battery_low_percent_format_hybrid_short" msgid="9025795469949145586">"<xliff:g id="PERCENTAGE">%s</xliff:g> बची है, बैटरी लगभग <xliff:g id="TIME">%s</xliff:g> चलेगी"</string>
<string name="battery_low_percent_format_saver_started" msgid="7879389868952879166">"<xliff:g id="PERCENTAGE">%s</xliff:g> बैटरी बची है. बैटरी सेवर चालू है."</string>
<string name="invalid_charger" msgid="4549105996740522523">"USB चार्जिंग समर्थित नहीं है.\nकेवल आपूर्ति किए गए चार्जर का उपयोग करें."</string>
<string name="invalid_charger_title" msgid="3515740382572798460">"USB चार्जिंग समर्थित नहीं है."</string>
@@ -73,22 +70,15 @@
<string name="usb_debugging_secondary_user_message" msgid="6067122453571699801">"अभी इस डिवाइस में जिस उपयोगकर्ता ने साइन इन किया है, वो USB डीबगिंग चालू नहीं कर सकता. इस सुविधा का इस्तेमाल करने के लिए, प्राथमिक उपयोगकर्ता में बदलें."</string>
<string name="compat_mode_on" msgid="6623839244840638213">"स्‍क्रीन भरने के लिए ज़ूम करें"</string>
<string name="compat_mode_off" msgid="4434467572461327898">"स्‍क्रीन भरने के लिए खींचें"</string>
- <!-- no translation found for global_action_screenshot (8329831278085426283) -->
- <skip />
+ <string name="global_action_screenshot" msgid="8329831278085426283">"स्क्रीनशॉट"</string>
<string name="screenshot_saving_ticker" msgid="7403652894056693515">"स्क्रीनशॉट सहेजा जा रहा है..."</string>
<string name="screenshot_saving_title" msgid="8242282144535555697">"स्क्रीनशॉट सहेजा जा रहा है..."</string>
- <!-- no translation found for screenshot_saving_text (2545047868936087248) -->
- <skip />
- <!-- no translation found for screenshot_saved_title (5637073968117370753) -->
- <skip />
- <!-- no translation found for screenshot_saved_text (7574667448002050363) -->
- <skip />
- <!-- no translation found for screenshot_failed_title (9096484883063264803) -->
- <skip />
- <!-- no translation found for screenshot_failed_to_save_unknown_text (8844781948876286488) -->
- <skip />
- <!-- no translation found for screenshot_failed_to_save_text (3041612585107107310) -->
- <skip />
+ <string name="screenshot_saving_text" msgid="2545047868936087248">"स्क्रीनशॉट सेव किया जा रहा है"</string>
+ <string name="screenshot_saved_title" msgid="5637073968117370753">"स्क्रीनशॉट सेव किया गया"</string>
+ <string name="screenshot_saved_text" msgid="7574667448002050363">"अपना स्क्रीनशॉट देखने के लिए टैप करें"</string>
+ <string name="screenshot_failed_title" msgid="9096484883063264803">"स्क्रीनशॉट नहीं लिया जा सका"</string>
+ <string name="screenshot_failed_to_save_unknown_text" msgid="8844781948876286488">"स्क्रीनशॉट सेव करते समय एक समस्या आई"</string>
+ <string name="screenshot_failed_to_save_text" msgid="3041612585107107310">"मेमोरी कम होने की वजह से स्क्रीनशॉट सेव नहीं किया जा सका"</string>
<string name="screenshot_failed_to_capture_text" msgid="173674476457581486">"ऐप्लिकेशन या आपका संगठन स्क्रीनशॉट लेने की अनुमति नहीं देता"</string>
<string name="usb_preference_title" msgid="6551050377388882787">"USB फ़ाइल स्थानांतरण विकल्प"</string>
<string name="use_mtp_button_title" msgid="4333504413563023626">"मीडिया प्लेयर के रूप में माउंट करें (MTP)"</string>
@@ -571,27 +561,19 @@
<string name="tuner_full_importance_settings_off" msgid="8208165412614935229">"बंद"</string>
<string name="power_notification_controls_description" msgid="4372459941671353358">"पावर सूचना नियंत्रण के ज़रिये, आप किसी ऐप की सूचना को उसकी अहमियत के हिसाब से 0 से 5 के लेवल पर सेट कर सकते हैं.\n\n"<b>"लेवल 5"</b>" \n- सूचना सूची में सबसे ऊपर दिखाएं \n- पूरे स्क्रीन को ढंकने की अनुमति दें \n- लगातार देखते रहें \n\n"<b>" लेवल 4"</b>" \n- पूरे स्क्रीन को ढंकें \n- लगातार देखते रहें \n\n"<b>"लेवल 3"</b>" \n- पूरे स्क्रीन को ढंकने से रोकें \n-कभी भी न देखें \n\n"<b>"लेवल 2"</b>" \n- पूरे स्क्रीन को ढंकने से रोकें \n- कभी भी देखें \n- कभी भी आवाज़ या कंपन (वाइब्रेशन) न करें \n\n"<b>"लेवल 1"</b>" \n- पूरे स्क्रीन को ढंकने से रोकें \n- कभी भी न देखें \n- कभी भी आवाज़ या कंपन (वाइब्रेशन) न करें \n- लॉक स्क्रीन और स्टेटस बार से छिपाएं \n- सूचना सूची के नीचे दिखाएं \n\n"<b>"लेवल 0"</b>" \n- ऐप्लिकेशन की सभी सूचनाएं रोक दें"</string>
<string name="notification_header_default_channel" msgid="7506845022070889909">"सूचना"</string>
- <!-- no translation found for notification_channel_disabled (344536703863700565) -->
- <skip />
- <!-- no translation found for inline_keep_showing (8945102997083836858) -->
- <skip />
- <!-- no translation found for inline_stop_button (4172980096860941033) -->
- <skip />
- <!-- no translation found for inline_keep_button (6665940297019018232) -->
- <skip />
- <!-- no translation found for inline_keep_showing_app (1723113469580031041) -->
- <skip />
- <!-- no translation found for notification_unblockable_desc (1037434112919403708) -->
- <skip />
+ <string name="notification_channel_disabled" msgid="344536703863700565">"अब आपको ये सूचनाएं दिखाई नहीं देंगी"</string>
+ <string name="inline_keep_showing" msgid="8945102997083836858">"ये सूचनाएं दिखाना जारी रखें?"</string>
+ <string name="inline_stop_button" msgid="4172980096860941033">"सूचनाएं दिखाना बंद करें"</string>
+ <string name="inline_keep_button" msgid="6665940297019018232">"दिखाना जारी रखें"</string>
+ <string name="inline_keep_showing_app" msgid="1723113469580031041">"इस ऐप्लिकेशन से जुड़ी सूचनाएं दिखाना जारी रखें?"</string>
+ <string name="notification_unblockable_desc" msgid="1037434112919403708">"ये सूचनाएं दिखाया जाना बंद नहीं किया जा सकता"</string>
<string name="notification_channel_controls_opened_accessibility" msgid="6553950422055908113">"<xliff:g id="APP_NAME">%1$s</xliff:g> के लिए सूचना नियंत्रण चालू हैं"</string>
<string name="notification_channel_controls_closed_accessibility" msgid="7521619812603693144">"<xliff:g id="APP_NAME">%1$s</xliff:g> के लिए सूचना नियंत्रण बंद हैं"</string>
<string name="notification_channel_switch_accessibility" msgid="3420796005601900717">"इस चैनल से सूचना की पाने की मंज़ूरी दें"</string>
<string name="notification_more_settings" msgid="816306283396553571">"और सेटिंग"</string>
- <!-- no translation found for notification_app_settings (420348114670768449) -->
- <skip />
+ <string name="notification_app_settings" msgid="420348114670768449">"पसंद के मुताबिक बनाएं"</string>
<string name="notification_done" msgid="5279426047273930175">"हो गया"</string>
- <!-- no translation found for inline_undo (558916737624706010) -->
- <skip />
+ <string name="inline_undo" msgid="558916737624706010">"पहले जैसा करें"</string>
<string name="notification_menu_accessibility" msgid="2046162834248888553">"<xliff:g id="APP_NAME">%1$s</xliff:g> <xliff:g id="MENU_DESCRIPTION">%2$s</xliff:g>"</string>
<string name="notification_menu_gear_description" msgid="2204480013726775108">"सूचना नियंत्रण"</string>
<string name="notification_menu_snooze_description" msgid="3653669438131034525">"सूचना को स्नूज़ (थोड़ी देर के लिए चुप करना) करने के विकल्प"</string>
diff --git a/packages/SystemUI/res/values-hr/strings.xml b/packages/SystemUI/res/values-hr/strings.xml
index 7395b6605217..cb6283478cec 100644
--- a/packages/SystemUI/res/values-hr/strings.xml
+++ b/packages/SystemUI/res/values-hr/strings.xml
@@ -34,7 +34,10 @@
<string name="status_bar_ongoing_events_title" msgid="1682504513316879202">"U tijeku"</string>
<string name="status_bar_latest_events_title" msgid="6594767438577593172">"Obavijesti"</string>
<string name="battery_low_title" msgid="6456385927409742437">"Niska razina baterije"</string>
+ <string name="battery_low_title_hybrid" msgid="6268991275887381595">"Baterija je skoro prazna. Uključite Štednju baterije"</string>
<string name="battery_low_percent_format" msgid="2900940511201380775">"Preostalo <xliff:g id="PERCENTAGE">%s</xliff:g>"</string>
+ <string name="battery_low_percent_format_hybrid" msgid="6838677459286775617">"Preostalo je <xliff:g id="PERCENTAGE">%s</xliff:g>, još otprilike <xliff:g id="TIME">%s</xliff:g> na temelju vaše upotrebe"</string>
+ <string name="battery_low_percent_format_hybrid_short" msgid="9025795469949145586">"Preostalo je <xliff:g id="PERCENTAGE">%s</xliff:g>, još otprilike <xliff:g id="TIME">%s</xliff:g>"</string>
<string name="battery_low_percent_format_saver_started" msgid="7879389868952879166">"Preostalo <xliff:g id="PERCENTAGE">%s</xliff:g>. Uključena je Štednja baterije."</string>
<string name="invalid_charger" msgid="4549105996740522523">"USB punjenje nije podržano.\nUpotrijebite samo priloženi punjač."</string>
<string name="invalid_charger_title" msgid="3515740382572798460">"Punjenje putem USB-a nije podržano."</string>
@@ -68,14 +71,15 @@
<string name="usb_debugging_secondary_user_message" msgid="6067122453571699801">"Korisnik koji je trenutačno prijavljen na ovaj uređaj ne može uključiti otklanjanje pogrešaka putem USB-a. Da biste upotrebljavali tu značajku, prijeđite na primarnog korisnika."</string>
<string name="compat_mode_on" msgid="6623839244840638213">"Zumiraj i ispuni zaslon"</string>
<string name="compat_mode_off" msgid="4434467572461327898">"Rastegni i ispuni zaslon"</string>
+ <string name="global_action_screenshot" msgid="8329831278085426283">"Snimka zaslona"</string>
<string name="screenshot_saving_ticker" msgid="7403652894056693515">"Spremanje snimke zaslona..."</string>
<string name="screenshot_saving_title" msgid="8242282144535555697">"Spremanje snimke zaslona..."</string>
- <string name="screenshot_saving_text" msgid="2419718443411738818">"Spremanje snimke zaslona."</string>
- <string name="screenshot_saved_title" msgid="6461865960961414961">"Zaslon je snimljen."</string>
- <string name="screenshot_saved_text" msgid="2685605830386712477">"Dodirnite da biste vidjeli snimku zaslona."</string>
- <string name="screenshot_failed_title" msgid="705781116746922771">"Nije bilo moguće snimiti zaslon."</string>
- <string name="screenshot_failed_to_save_unknown_text" msgid="7887826345701753830">"Prilikom spremanja snimke zaslona pojavio se problem."</string>
- <string name="screenshot_failed_to_save_text" msgid="2592658083866306296">"Zaslon nije snimljen zbog ograničenog prostora za pohranu."</string>
+ <string name="screenshot_saving_text" msgid="2545047868936087248">"Spremanje snimke zaslona"</string>
+ <string name="screenshot_saved_title" msgid="5637073968117370753">"Snimka zaslona spremljena"</string>
+ <string name="screenshot_saved_text" msgid="7574667448002050363">"Dodirnite da biste vidjeli snimku zaslona"</string>
+ <string name="screenshot_failed_title" msgid="9096484883063264803">"Nije bilo moguće snimiti zaslon"</string>
+ <string name="screenshot_failed_to_save_unknown_text" msgid="8844781948876286488">"Prilikom spremanja snimke zaslona pojavio se problem"</string>
+ <string name="screenshot_failed_to_save_text" msgid="3041612585107107310">"Zaslon nije snimljen zbog ograničenog prostora za pohranu"</string>
<string name="screenshot_failed_to_capture_text" msgid="173674476457581486">"Aplikacija ili vaša organizacija ne dopuštaju snimanje zaslona"</string>
<string name="usb_preference_title" msgid="6551050377388882787">"Opcije USB prijenosa datoteka"</string>
<string name="use_mtp_button_title" msgid="4333504413563023626">"Učitaj kao media player (MTP)"</string>
@@ -559,28 +563,19 @@
<string name="tuner_full_importance_settings_off" msgid="8208165412614935229">"Isključeno"</string>
<string name="power_notification_controls_description" msgid="4372459941671353358">"Napredne kontrole obavijesti omogućuju vam da postavite razinu važnosti za obavijesti aplikacije od 0 do 5. \n\n"<b>"Razina 5"</b>" \n– prikaži na vrhu popisa obavijesti \n– dopusti prekide prikaza na cijelom zaslonu \n– uvijek dopusti brzi pregled \n\n"<b>"Razina 4"</b>" \n– onemogući prekid prikaza na cijelom zaslonu \n– uvijek dopusti brzi pregled \n\n"<b>"Razina 3"</b>" \n– onemogući prekid prikaza na cijelom zaslonu \n– nikad ne dopusti brzi pregled\n\n"<b>"Razina 2"</b>" \n– onemogući prekid prikaza na cijelom zaslonu \n– nikad ne dopusti brzi pregled \n– nikad ne emitiraj zvuk ni vibraciju \n\n"<b>"Razina 1"</b>" \n– onemogući prekid prikaza na cijelom zaslonu \n– nikad ne dopusti brzi pregled \n– nikad ne emitiraj zvuk ni vibraciju \n– ne prikazuj na zaključanom zaslonu i traci statusa \n– prikaži na dnu popisa obavijesti \n\n"<b>"Razina 0"</b>" \n– blokiraj sve obavijesti aplikacije"</string>
<string name="notification_header_default_channel" msgid="7506845022070889909">"Obavijesti"</string>
- <string name="notification_channel_disabled" msgid="2139193533791840539">"Više nećete primati te obavijesti"</string>
- <string name="notification_num_channels" msgid="2048144408999179471">"Broj kategorija obavijesti: <xliff:g id="NUMBER">%d</xliff:g>"</string>
- <string name="notification_default_channel_desc" msgid="2506053815870808359">"Ova aplikacija nema kategorije obavijesti"</string>
- <string name="notification_unblockable_desc" msgid="3561016061737896906">"Obavijesti ove aplikacije ne mogu se isključiti"</string>
- <plurals name="notification_num_channels_desc" formatted="false" msgid="5492793452274077663">
- <item quantity="one">1 od <xliff:g id="NUMBER_1">%s</xliff:g> kategorije obavijesti iz ove aplikacije</item>
- <item quantity="few">1 od <xliff:g id="NUMBER_1">%s</xliff:g> kategorije obavijesti iz ove aplikacije</item>
- <item quantity="other">1 od <xliff:g id="NUMBER_1">%s</xliff:g> kategorija obavijesti iz ove aplikacije</item>
- </plurals>
- <string name="notification_channels_list_desc_2" msgid="6214732715833946441">"<xliff:g id="CHANNEL_NAME_1">%1$s</xliff:g>, <xliff:g id="CHANNEL_NAME_2">%2$s</xliff:g>"</string>
- <plurals name="notification_channels_list_desc_2_and_others" formatted="false" msgid="2747813553355336157">
- <item quantity="one"><xliff:g id="CHANNEL_NAME_1_3">%1$s</xliff:g>, <xliff:g id="CHANNEL_NAME_2_4">%2$s</xliff:g> i još <xliff:g id="NUMBER_5">%3$d</xliff:g></item>
- <item quantity="few"><xliff:g id="CHANNEL_NAME_1_3">%1$s</xliff:g>, <xliff:g id="CHANNEL_NAME_2_4">%2$s</xliff:g> i još <xliff:g id="NUMBER_5">%3$d</xliff:g></item>
- <item quantity="other"><xliff:g id="CHANNEL_NAME_1_3">%1$s</xliff:g>, <xliff:g id="CHANNEL_NAME_2_4">%2$s</xliff:g> i još <xliff:g id="NUMBER_5">%3$d</xliff:g></item>
- </plurals>
+ <string name="notification_channel_disabled" msgid="344536703863700565">"Te vam se obavijesti više neće prikazivati"</string>
+ <string name="inline_keep_showing" msgid="8945102997083836858">"Želite li da se obavijesti nastave prikazivati?"</string>
+ <string name="inline_stop_button" msgid="4172980096860941033">"Zaustavi obavijesti"</string>
+ <string name="inline_keep_button" msgid="6665940297019018232">"Nastavi prikazivati"</string>
+ <string name="inline_keep_showing_app" msgid="1723113469580031041">"Želite li da se obavijesti te aplikacije nastave prikazivati?"</string>
+ <string name="notification_unblockable_desc" msgid="1037434112919403708">"Te se obavijesti ne mogu isključiti"</string>
<string name="notification_channel_controls_opened_accessibility" msgid="6553950422055908113">"Otvorene su kontrole obavijesti za <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
<string name="notification_channel_controls_closed_accessibility" msgid="7521619812603693144">"Zatvorene su kontrole obavijesti za <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
<string name="notification_channel_switch_accessibility" msgid="3420796005601900717">"Dopusti obavijesti za ovaj kanal"</string>
- <string name="notification_all_categories" msgid="5407190218055113282">"Sve kategorije"</string>
<string name="notification_more_settings" msgid="816306283396553571">"Više postavki"</string>
- <string name="notification_app_settings" msgid="3743278649182392015">"Prilagodite: <xliff:g id="SUB_CATEGORY">%1$s</xliff:g>"</string>
+ <string name="notification_app_settings" msgid="420348114670768449">"Prilagodi"</string>
<string name="notification_done" msgid="5279426047273930175">"Gotovo"</string>
+ <string name="inline_undo" msgid="558916737624706010">"Poništi"</string>
<string name="notification_menu_accessibility" msgid="2046162834248888553">"<xliff:g id="MENU_DESCRIPTION">%2$s</xliff:g> za aplikaciju <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
<string name="notification_menu_gear_description" msgid="2204480013726775108">"kontrole obavijesti"</string>
<string name="notification_menu_snooze_description" msgid="3653669438131034525">"opcije odgode obavijesti"</string>
@@ -737,8 +732,7 @@
<string name="pip_phone_expand" msgid="5889780005575693909">"Proširivanje"</string>
<string name="pip_phone_minimize" msgid="1079119422589131792">"Minimiziraj"</string>
<string name="pip_phone_close" msgid="8416647892889710330">"Zatvori"</string>
- <!-- no translation found for pip_phone_settings (8080777499521528521) -->
- <skip />
+ <string name="pip_phone_settings" msgid="8080777499521528521">"Postavke"</string>
<string name="pip_phone_dismiss_hint" msgid="6351678169095923899">"Povucite prema dolje da biste odbacili"</string>
<string name="pip_menu_title" msgid="4707292089961887657">"Izbornik"</string>
<string name="pip_notification_title" msgid="3204024940158161322">"<xliff:g id="NAME">%s</xliff:g> jest na slici u slici"</string>
diff --git a/packages/SystemUI/res/values-hu/strings.xml b/packages/SystemUI/res/values-hu/strings.xml
index 87ca49a18a83..2069952cde5c 100644
--- a/packages/SystemUI/res/values-hu/strings.xml
+++ b/packages/SystemUI/res/values-hu/strings.xml
@@ -33,7 +33,10 @@
<string name="status_bar_ongoing_events_title" msgid="1682504513316879202">"Folyamatban van"</string>
<string name="status_bar_latest_events_title" msgid="6594767438577593172">"Értesítések"</string>
<string name="battery_low_title" msgid="6456385927409742437">"Alacsony az energiaszint"</string>
+ <string name="battery_low_title_hybrid" msgid="6268991275887381595">"Az akkumulátor szintje alacsony. Kapcsolja be az akkumulátorkímélő módot."</string>
<string name="battery_low_percent_format" msgid="2900940511201380775">"<xliff:g id="PERCENTAGE">%s</xliff:g> maradt"</string>
+ <string name="battery_low_percent_format_hybrid" msgid="6838677459286775617">"<xliff:g id="PERCENTAGE">%s</xliff:g> maradt, körülbelül <xliff:g id="TIME">%s</xliff:g> van hátra a használat alapján"</string>
+ <string name="battery_low_percent_format_hybrid_short" msgid="9025795469949145586">"<xliff:g id="PERCENTAGE">%s</xliff:g> maradt, körülbelül <xliff:g id="TIME">%s</xliff:g> van hátra"</string>
<string name="battery_low_percent_format_saver_started" msgid="7879389868952879166">"<xliff:g id="PERCENTAGE">%s</xliff:g> maradt. Az Akkumulátorkímélő mód be van kapcsolva."</string>
<string name="invalid_charger" msgid="4549105996740522523">"Az USB-n keresztüli töltés nincs támogatva.\nHasználja a kapott töltőt."</string>
<string name="invalid_charger_title" msgid="3515740382572798460">"Az USB-n keresztüli töltés nem támogatott."</string>
@@ -67,14 +70,15 @@
<string name="usb_debugging_secondary_user_message" msgid="6067122453571699801">"Az eszközre jelenleg bejelentkezett felhasználó nem engedélyezheti az USB-hibakeresést. A funkció használatához váltson az elsődleges felhasználóra."</string>
<string name="compat_mode_on" msgid="6623839244840638213">"Nagyítás a kitöltéshez"</string>
<string name="compat_mode_off" msgid="4434467572461327898">"Nyújtás kitöltéshez"</string>
+ <string name="global_action_screenshot" msgid="8329831278085426283">"Képernyőkép"</string>
<string name="screenshot_saving_ticker" msgid="7403652894056693515">"Képernyőkép mentése..."</string>
<string name="screenshot_saving_title" msgid="8242282144535555697">"Képernyőkép mentése..."</string>
- <string name="screenshot_saving_text" msgid="2419718443411738818">"Képernyőkép mentése."</string>
- <string name="screenshot_saved_title" msgid="6461865960961414961">"Képernyőkép rögzítve."</string>
- <string name="screenshot_saved_text" msgid="2685605830386712477">"Koppintson a képernyőkép megtekintéséhez."</string>
- <string name="screenshot_failed_title" msgid="705781116746922771">"Nem sikerült rögzíteni a képernyőképet."</string>
- <string name="screenshot_failed_to_save_unknown_text" msgid="7887826345701753830">"Hiba történt a képernyőkép mentése során."</string>
- <string name="screenshot_failed_to_save_text" msgid="2592658083866306296">"Nem menthet képernyőképet, mert kevés a tárhely."</string>
+ <string name="screenshot_saving_text" msgid="2545047868936087248">"Képernyőkép mentése…"</string>
+ <string name="screenshot_saved_title" msgid="5637073968117370753">"A képernyőkép mentése sikerült"</string>
+ <string name="screenshot_saved_text" msgid="7574667448002050363">"Koppintson a képernyőkép megtekintéséhez"</string>
+ <string name="screenshot_failed_title" msgid="9096484883063264803">"Nem sikerült rögzíteni a képernyőképet"</string>
+ <string name="screenshot_failed_to_save_unknown_text" msgid="8844781948876286488">"Hiba történt a képernyőkép mentése során"</string>
+ <string name="screenshot_failed_to_save_text" msgid="3041612585107107310">"Nem menthet képernyőképet, mert kevés a tárhely"</string>
<string name="screenshot_failed_to_capture_text" msgid="173674476457581486">"Az alkalmazás vagy az Ön szervezete nem engedélyezi képernyőkép készítését"</string>
<string name="usb_preference_title" msgid="6551050377388882787">"USB-fájlátvitel beállításai"</string>
<string name="use_mtp_button_title" msgid="4333504413563023626">"Csatlakoztatás médialejátszóként (MTP)"</string>
@@ -557,26 +561,19 @@
<string name="tuner_full_importance_settings_off" msgid="8208165412614935229">"Kikapcsolva"</string>
<string name="power_notification_controls_description" msgid="4372459941671353358">"Az értesítési beállítások révén 0-tól 5-ig állíthatja be a fontossági szintet az alkalmazás értesítéseinél. \n\n"<b>"5. szint"</b>" \n– Megjelenítés az értesítési lista tetején \n– Teljes képernyő megszakításának engedélyezése \n– Mindig felugrik \n\n"<b>"4. szint"</b>" \n– Teljes képernyő megszakításának megakadályozása \n– Mindig felugrik \n\n"<b>"3. szint"</b>" \n– Teljes képernyő megszakításának megakadályozása \n– Soha nem ugrik fel \n\n"<b>"2. szint"</b>" \n– Teljes képernyő megszakításának megakadályozása \n– Soha nem ugrik fel \n– Soha nincs hangjelzés és rezgés \n\n"<b>"1. szint"</b>" \n– Teljes képernyő megszakításának megakadályozása \n– Soha nem ugrik fel \n– Soha nincs hangjelzés vagy rezgés \n– Elrejtés a lezárási képernyőről és az állapotsávról \n– Megjelenítés az értesítési lista alján \n\n"<b>"0. szint"</b>" \n– Az alkalmazás összes értesítésének letiltása"</string>
<string name="notification_header_default_channel" msgid="7506845022070889909">"Értesítések"</string>
- <string name="notification_channel_disabled" msgid="2139193533791840539">"Többé nem jelennek meg ezek az értesítések"</string>
- <string name="notification_num_channels" msgid="2048144408999179471">"<xliff:g id="NUMBER">%d</xliff:g> értesítéskategória"</string>
- <string name="notification_default_channel_desc" msgid="2506053815870808359">"Az alkalmazás nem rendelkezik értesítési kategóriákkal"</string>
- <string name="notification_unblockable_desc" msgid="3561016061737896906">"Az alkalmazástól érkező értesítések nem kapcsolhatók ki"</string>
- <plurals name="notification_num_channels_desc" formatted="false" msgid="5492793452274077663">
- <item quantity="other"><xliff:g id="NUMBER_1">%s</xliff:g>/1 értesítési kategória az alkalmazásból</item>
- <item quantity="one"><xliff:g id="NUMBER_0">%s</xliff:g>/1 értesítési kategória az alkalmazásból</item>
- </plurals>
- <string name="notification_channels_list_desc_2" msgid="6214732715833946441">"<xliff:g id="CHANNEL_NAME_1">%1$s</xliff:g>, <xliff:g id="CHANNEL_NAME_2">%2$s</xliff:g>"</string>
- <plurals name="notification_channels_list_desc_2_and_others" formatted="false" msgid="2747813553355336157">
- <item quantity="other"><xliff:g id="CHANNEL_NAME_1_3">%1$s</xliff:g>, <xliff:g id="CHANNEL_NAME_2_4">%2$s</xliff:g> és <xliff:g id="NUMBER_5">%3$d</xliff:g> másik</item>
- <item quantity="one"><xliff:g id="CHANNEL_NAME_1_0">%1$s</xliff:g>, <xliff:g id="CHANNEL_NAME_2_1">%2$s</xliff:g> és <xliff:g id="NUMBER_2">%3$d</xliff:g> másik</item>
- </plurals>
+ <string name="notification_channel_disabled" msgid="344536703863700565">"Többé nem jelennek meg ezek az értesítések"</string>
+ <string name="inline_keep_showing" msgid="8945102997083836858">"Továbbra is megjelenjenek ezek az értesítések?"</string>
+ <string name="inline_stop_button" msgid="4172980096860941033">"Értesítések letiltása"</string>
+ <string name="inline_keep_button" msgid="6665940297019018232">"Megjelenítés továbbra is"</string>
+ <string name="inline_keep_showing_app" msgid="1723113469580031041">"Továbbra is megjelenjenek az alkalmazás értesítései?"</string>
+ <string name="notification_unblockable_desc" msgid="1037434112919403708">"Ezeket az értesítéseket nem lehet kikapcsolni"</string>
<string name="notification_channel_controls_opened_accessibility" msgid="6553950422055908113">"A(z) <xliff:g id="APP_NAME">%1$s</xliff:g> értesítésvezérlői megnyitva"</string>
<string name="notification_channel_controls_closed_accessibility" msgid="7521619812603693144">"A(z) <xliff:g id="APP_NAME">%1$s</xliff:g> értesítésvezérlői kikapcsolva"</string>
<string name="notification_channel_switch_accessibility" msgid="3420796005601900717">"Értesítések engedélyezése erről a csatornáról"</string>
- <string name="notification_all_categories" msgid="5407190218055113282">"Minden kategória"</string>
<string name="notification_more_settings" msgid="816306283396553571">"További beállítások"</string>
- <string name="notification_app_settings" msgid="3743278649182392015">"Személyre szabás: <xliff:g id="SUB_CATEGORY">%1$s</xliff:g>"</string>
+ <string name="notification_app_settings" msgid="420348114670768449">"Személyre szabás"</string>
<string name="notification_done" msgid="5279426047273930175">"Kész"</string>
+ <string name="inline_undo" msgid="558916737624706010">"Visszavonás"</string>
<string name="notification_menu_accessibility" msgid="2046162834248888553">"<xliff:g id="APP_NAME">%1$s</xliff:g> – <xliff:g id="MENU_DESCRIPTION">%2$s</xliff:g>"</string>
<string name="notification_menu_gear_description" msgid="2204480013726775108">"értesítésvezérlők"</string>
<string name="notification_menu_snooze_description" msgid="3653669438131034525">"értesítések halasztási beállításai"</string>
@@ -731,8 +728,7 @@
<string name="pip_phone_expand" msgid="5889780005575693909">"Kibontás"</string>
<string name="pip_phone_minimize" msgid="1079119422589131792">"Kis méret"</string>
<string name="pip_phone_close" msgid="8416647892889710330">"Bezárás"</string>
- <!-- no translation found for pip_phone_settings (8080777499521528521) -->
- <skip />
+ <string name="pip_phone_settings" msgid="8080777499521528521">"Beállítások"</string>
<string name="pip_phone_dismiss_hint" msgid="6351678169095923899">"Elvetéshez húzza lefelé"</string>
<string name="pip_menu_title" msgid="4707292089961887657">"Menü"</string>
<string name="pip_notification_title" msgid="3204024940158161322">"A(z) <xliff:g id="NAME">%s</xliff:g> kép a képben funkciót használ"</string>
diff --git a/packages/SystemUI/res/values-hy/strings.xml b/packages/SystemUI/res/values-hy/strings.xml
index b6172c8e555c..0656f0c4e09a 100644
--- a/packages/SystemUI/res/values-hy/strings.xml
+++ b/packages/SystemUI/res/values-hy/strings.xml
@@ -33,7 +33,10 @@
<string name="status_bar_ongoing_events_title" msgid="1682504513316879202">"Ընթացիկ"</string>
<string name="status_bar_latest_events_title" msgid="6594767438577593172">"Ծանուցումներ"</string>
<string name="battery_low_title" msgid="6456385927409742437">"Մարտկոցի լիցքը սպառվում է"</string>
+ <string name="battery_low_title_hybrid" msgid="6268991275887381595">"Մարտկոցի լիցքը սպառվում է։ Միացրեք մարտկոցի տնտեսումը։"</string>
<string name="battery_low_percent_format" msgid="2900940511201380775">"Մնաց <xliff:g id="PERCENTAGE">%s</xliff:g>"</string>
+ <string name="battery_low_percent_format_hybrid" msgid="6838677459286775617">"Մարտկոցի լիցքը՝ <xliff:g id="PERCENTAGE">%s</xliff:g>, մնացել է մոտ <xliff:g id="TIME">%s</xliff:g>՝ օգտագործման եղանակից կախված"</string>
+ <string name="battery_low_percent_format_hybrid_short" msgid="9025795469949145586">"Մարտկոցի լիցքը՝ <xliff:g id="PERCENTAGE">%s</xliff:g>, մնացել է մոտ <xliff:g id="TIME">%s</xliff:g>"</string>
<string name="battery_low_percent_format_saver_started" msgid="7879389868952879166">"Մնացել է <xliff:g id="PERCENTAGE">%s</xliff:g>: Մարտկոցի տնտեսումը միացված է:"</string>
<string name="invalid_charger" msgid="4549105996740522523">"USB լիցքավորումը չի աջակցվում:\nՕգտվեք միայն գործող լիցքավորիչից:"</string>
<string name="invalid_charger_title" msgid="3515740382572798460">"USB լիցքավորումը չի աջակցվում:"</string>
@@ -67,14 +70,15 @@
<string name="usb_debugging_secondary_user_message" msgid="6067122453571699801">"Ընթացիկ հաշվի օգտատերը չի կարող միացնել USB վրիպազերծումը: Այս գործառույթը միացնելու համար մուտք գործեք հիմնական օգտատիրոջ հաշվով:"</string>
<string name="compat_mode_on" msgid="6623839244840638213">"Խոշորացնել` էկրանը լցնելու համար"</string>
<string name="compat_mode_off" msgid="4434467572461327898">"Ձգել` էկրանը լցնելու համար"</string>
+ <string name="global_action_screenshot" msgid="8329831278085426283">"Էկրանի պատկեր"</string>
<string name="screenshot_saving_ticker" msgid="7403652894056693515">"Էկրանի պատկերը պահվում է…"</string>
<string name="screenshot_saving_title" msgid="8242282144535555697">"Էկրանի պատկերը պահվում է..."</string>
- <string name="screenshot_saving_text" msgid="2419718443411738818">"Էկրանի պատկերը պահվում է:"</string>
- <string name="screenshot_saved_title" msgid="6461865960961414961">"Էկրանի պատկերը լուսանկարվել է:"</string>
- <string name="screenshot_saved_text" msgid="2685605830386712477">"Հպեք՝ էկրանի պատկերը տեսնելու համար:"</string>
- <string name="screenshot_failed_title" msgid="705781116746922771">"Չհաջողվեց լուսանկարել էկրանի պատկերը:"</string>
- <string name="screenshot_failed_to_save_unknown_text" msgid="7887826345701753830">"Էկրանի պատկերը պահելիս խնդիր առաջացավ:"</string>
- <string name="screenshot_failed_to_save_text" msgid="2592658083866306296">"Չհաջողվեց պահել էկրանի պատկերը սահմանափակ հիշողության պատճառով:"</string>
+ <string name="screenshot_saving_text" msgid="2545047868936087248">"Էկրանի պատկերը պահվում է"</string>
+ <string name="screenshot_saved_title" msgid="5637073968117370753">"Էկրանի պատկերը պահվեց"</string>
+ <string name="screenshot_saved_text" msgid="7574667448002050363">"Հպեք՝ էկրանի պատկերը տեսնելու համար"</string>
+ <string name="screenshot_failed_title" msgid="9096484883063264803">"Չհաջողվեց պահել էկրանի պատկերը"</string>
+ <string name="screenshot_failed_to_save_unknown_text" msgid="8844781948876286488">"Չհաջողվեց պահել էկրանի պատկերը"</string>
+ <string name="screenshot_failed_to_save_text" msgid="3041612585107107310">"Չհաջողվեց պահել էկրանի պատկերը անբավարար հիշողության պատճառով"</string>
<string name="screenshot_failed_to_capture_text" msgid="173674476457581486">"Հավելվածը կամ ձեր կազմակերպությունը չի թույլատրում էկրանի պատկերի ստացումը"</string>
<string name="usb_preference_title" msgid="6551050377388882787">"USB ֆայլերի փոխանցման ընտրանքներ"</string>
<string name="use_mtp_button_title" msgid="4333504413563023626">"Միացնել որպես մեդիա նվագարկիչ (MTP)"</string>
@@ -557,26 +561,19 @@
<string name="tuner_full_importance_settings_off" msgid="8208165412614935229">"Անջատել"</string>
<string name="power_notification_controls_description" msgid="4372459941671353358">"Ծանուցումների ընդլայնված կառավարման օգնությամբ կարող եք յուրաքանչյուր հավելվածի ծանուցումների համար նշանակել կարևորության աստիճան՝ 0-5 սահմաններում: \n\n"<b>"5-րդ աստիճան"</b>" \n- Ցուցադրել ծանուցումների ցանկի վերևում \n- Թույլատրել լիաէկրան ընդհատումները \n- Միշտ ցուցադրել կարճ ծանուցումները \n\n"<b>"4-րդ աստիճան"</b>" \n- Արգելել լիաէկրան ընդհատումները \n- Միշտ ցուցադրել կարճ ծանուցումները \n\n"<b>"3-րդ աստիճան"</b>" \n- Արգելել լիաէկրան ընդհատումները \n- Արգելել կարճ ծանուցումների ցուցադրումը \n\n"<b>"2-րդ աստիճան"</b>" \n- Արգելել լիաէկրան ընդհատումները \n- Արգելել կարճ ծանուցումների ցուցադրումը \n- Անջատել ձայնը և թրթռումը \n\n"<b>"1-ին աստիճան"</b>" \n- Արգելել լիաէկրան ընդհատումները \n- Արգելել կարճ ծանուցումների ցուցադրումը \n- Անջատել ձայնը և թրթռումը \n- Չցուցադրել կողպէկրանում և կարգավիճակի գոտում \n- Ցուցադրել ծանուցումների ցանկի ներքևում \n\n"<b>"0-րդ աստիճան"</b>\n"- Արգելափակել հավելվածի բոլոր ծանուցումները"</string>
<string name="notification_header_default_channel" msgid="7506845022070889909">"Ծանուցումներ"</string>
- <string name="notification_channel_disabled" msgid="2139193533791840539">"Այս ծանուցումներն այլևս չեք ստանա"</string>
- <string name="notification_num_channels" msgid="2048144408999179471">"<xliff:g id="NUMBER">%d</xliff:g> ծանուցման կատեգորիաներ"</string>
- <string name="notification_default_channel_desc" msgid="2506053815870808359">"Այս հավելվածը ծանուցման կատեգորիաներ չունի"</string>
- <string name="notification_unblockable_desc" msgid="3561016061737896906">"Այս հավելվածի ծանուցումները հնարավոր չէ անջատել"</string>
- <plurals name="notification_num_channels_desc" formatted="false" msgid="5492793452274077663">
- <item quantity="one">1 out of <xliff:g id="NUMBER_1">%s</xliff:g> notification categories from this app</item>
- <item quantity="other">1 ալիք` այս հավելվածի <xliff:g id="NUMBER_1">%s</xliff:g> կատեգորիաներից</item>
- </plurals>
- <string name="notification_channels_list_desc_2" msgid="6214732715833946441">"<xliff:g id="CHANNEL_NAME_1">%1$s</xliff:g>, <xliff:g id="CHANNEL_NAME_2">%2$s</xliff:g>"</string>
- <plurals name="notification_channels_list_desc_2_and_others" formatted="false" msgid="2747813553355336157">
- <item quantity="one"><xliff:g id="CHANNEL_NAME_1_3">%1$s</xliff:g>, <xliff:g id="CHANNEL_NAME_2_4">%2$s</xliff:g>, and <xliff:g id="NUMBER_5">%3$d</xliff:g> others</item>
- <item quantity="other"><xliff:g id="CHANNEL_NAME_1_3">%1$s</xliff:g>, <xliff:g id="CHANNEL_NAME_2_4">%2$s</xliff:g> ու <xliff:g id="NUMBER_5">%3$d</xliff:g> այլ</item>
- </plurals>
+ <string name="notification_channel_disabled" msgid="344536703863700565">"Դուք այլևս չեք ստանա այս ծանուցումները"</string>
+ <string name="inline_keep_showing" msgid="8945102997083836858">"Ցուցադրե՞լ այս ծանուցումները։"</string>
+ <string name="inline_stop_button" msgid="4172980096860941033">"Չցուցադրել ծանուցումներ"</string>
+ <string name="inline_keep_button" msgid="6665940297019018232">"Ցուցադրել"</string>
+ <string name="inline_keep_showing_app" msgid="1723113469580031041">"Ցուցադրե՞լ ծանուցումներ այս հավելվածից։"</string>
+ <string name="notification_unblockable_desc" msgid="1037434112919403708">"Այս ծանուցումները հնարավոր չէ անջատել"</string>
<string name="notification_channel_controls_opened_accessibility" msgid="6553950422055908113">"<xliff:g id="APP_NAME">%1$s</xliff:g> հավելվածի ծանուցումների կառավարումը բաց է"</string>
<string name="notification_channel_controls_closed_accessibility" msgid="7521619812603693144">"<xliff:g id="APP_NAME">%1$s</xliff:g> հավելվածի ծանուցումների կառավարումը փակ է"</string>
<string name="notification_channel_switch_accessibility" msgid="3420796005601900717">"Թույլ տալ ծանուցումներ այս ալիքից"</string>
- <string name="notification_all_categories" msgid="5407190218055113282">"Բոլոր կատեգորիաները"</string>
<string name="notification_more_settings" msgid="816306283396553571">"Այլ կարգավորումներ"</string>
- <string name="notification_app_settings" msgid="3743278649182392015">"Հարմարեցնել՝ <xliff:g id="SUB_CATEGORY">%1$s</xliff:g>"</string>
+ <string name="notification_app_settings" msgid="420348114670768449">"Կարգավորել"</string>
<string name="notification_done" msgid="5279426047273930175">"Պատրաստ է"</string>
+ <string name="inline_undo" msgid="558916737624706010">"Հետարկել"</string>
<string name="notification_menu_accessibility" msgid="2046162834248888553">"<xliff:g id="APP_NAME">%1$s</xliff:g> <xliff:g id="MENU_DESCRIPTION">%2$s</xliff:g>"</string>
<string name="notification_menu_gear_description" msgid="2204480013726775108">"ծանուցման կառավարներ"</string>
<string name="notification_menu_snooze_description" msgid="3653669438131034525">"ծանուցման հետաձգման ընտրանքներ"</string>
@@ -731,8 +728,7 @@
<string name="pip_phone_expand" msgid="5889780005575693909">"Ընդարձակել"</string>
<string name="pip_phone_minimize" msgid="1079119422589131792">"Ծալել"</string>
<string name="pip_phone_close" msgid="8416647892889710330">"Փակել"</string>
- <!-- no translation found for pip_phone_settings (8080777499521528521) -->
- <skip />
+ <string name="pip_phone_settings" msgid="8080777499521528521">"Կարգավորումներ"</string>
<string name="pip_phone_dismiss_hint" msgid="6351678169095923899">"Քաշեք վար՝ փակելու համար"</string>
<string name="pip_menu_title" msgid="4707292089961887657">"Ընտրացանկ"</string>
<string name="pip_notification_title" msgid="3204024940158161322">"<xliff:g id="NAME">%s</xliff:g>-ը «Նկար նկարի մեջ» ռեժիմում է"</string>
diff --git a/packages/SystemUI/res/values-is/strings.xml b/packages/SystemUI/res/values-is/strings.xml
index 35bf451d2500..dbdb2731f0cf 100644
--- a/packages/SystemUI/res/values-is/strings.xml
+++ b/packages/SystemUI/res/values-is/strings.xml
@@ -33,7 +33,10 @@
<string name="status_bar_ongoing_events_title" msgid="1682504513316879202">"Áframhaldandi"</string>
<string name="status_bar_latest_events_title" msgid="6594767438577593172">"Tilkynningar"</string>
<string name="battery_low_title" msgid="6456385927409742437">"Rafhlaðan er að tæmast"</string>
+ <string name="battery_low_title_hybrid" msgid="6268991275887381595">"Lítil hleðsla er á rafhlöðunni. Kveiktu á rafhlöðusparnaði"</string>
<string name="battery_low_percent_format" msgid="2900940511201380775">"<xliff:g id="PERCENTAGE">%s</xliff:g> eftir"</string>
+ <string name="battery_low_percent_format_hybrid" msgid="6838677459286775617">"<xliff:g id="PERCENTAGE">%s</xliff:g> eftir, um það bil <xliff:g id="TIME">%s</xliff:g> eftir miðað við notkun"</string>
+ <string name="battery_low_percent_format_hybrid_short" msgid="9025795469949145586">"<xliff:g id="PERCENTAGE">%s</xliff:g> eftir, um það bil <xliff:g id="TIME">%s</xliff:g> eftir"</string>
<string name="battery_low_percent_format_saver_started" msgid="7879389868952879166">"<xliff:g id="PERCENTAGE">%s</xliff:g> eftir. Kveikt er á rafhlöðusparnaði."</string>
<string name="invalid_charger" msgid="4549105996740522523">"USB-hleðsla er ekki studd.\nNotaðu eingöngu hleðslutækið sem fylgdi."</string>
<string name="invalid_charger_title" msgid="3515740382572798460">"Ekki er stuðningur við USB-hleðslu."</string>
@@ -67,14 +70,15 @@
<string name="usb_debugging_secondary_user_message" msgid="6067122453571699801">"Notandinn sem er skráður inn í þetta tæki núna getur ekki kveikt á USB-villuleit. Til þess að nota þennan eiginleika skaltu skipta yfir í aðalnotandann."</string>
<string name="compat_mode_on" msgid="6623839244840638213">"Fylla skjá með aðdrætti"</string>
<string name="compat_mode_off" msgid="4434467572461327898">"Teygja yfir allan skjáinn"</string>
+ <string name="global_action_screenshot" msgid="8329831278085426283">"Skjámynd"</string>
<string name="screenshot_saving_ticker" msgid="7403652894056693515">"Vistar skjámynd…"</string>
<string name="screenshot_saving_title" msgid="8242282144535555697">"Vistar skjámynd…"</string>
- <string name="screenshot_saving_text" msgid="2419718443411738818">"Verið er að vista skjámynd."</string>
- <string name="screenshot_saved_title" msgid="6461865960961414961">"Skjámynd var tekin."</string>
- <string name="screenshot_saved_text" msgid="2685605830386712477">"Ýttu til að sjá skjámyndina."</string>
- <string name="screenshot_failed_title" msgid="705781116746922771">"Ekki tókst að taka skjámynd."</string>
- <string name="screenshot_failed_to_save_unknown_text" msgid="7887826345701753830">"Upp kom vandamál við að vista skjámynd."</string>
- <string name="screenshot_failed_to_save_text" msgid="2592658083866306296">"Ekki tókst að vista skjámynd vegna takmarkaðs geymslupláss."</string>
+ <string name="screenshot_saving_text" msgid="2545047868936087248">"Vistar skjámynd"</string>
+ <string name="screenshot_saved_title" msgid="5637073968117370753">"Skjámynd vistuð"</string>
+ <string name="screenshot_saved_text" msgid="7574667448002050363">"Ýttu til skoða skjámyndina"</string>
+ <string name="screenshot_failed_title" msgid="9096484883063264803">"Ekki tókst að taka skjámynd"</string>
+ <string name="screenshot_failed_to_save_unknown_text" msgid="8844781948876286488">"Vandamál kom upp við að vista skjámynd"</string>
+ <string name="screenshot_failed_to_save_text" msgid="3041612585107107310">"Ekki tókst að vista skjámynd vegna takmarkaðs geymslupláss"</string>
<string name="screenshot_failed_to_capture_text" msgid="173674476457581486">"Forritið eða fyrirtækið þitt leyfir ekki skjámyndatöku"</string>
<string name="usb_preference_title" msgid="6551050377388882787">"Valkostir USB-skráaflutnings"</string>
<string name="use_mtp_button_title" msgid="4333504413563023626">"Tengja sem efnisspilara (MTP)"</string>
@@ -557,26 +561,19 @@
<string name="tuner_full_importance_settings_off" msgid="8208165412614935229">"Slökkt"</string>
<string name="power_notification_controls_description" msgid="4372459941671353358">"Með orkutilkynningastýringum geturðu stillt mikilvægi frá 0 upp í 5 fyrir tilkynningar forrita. \n\n"<b>"Stig 5"</b>" \n- Sýna efst á tilkynningalista \n- Leyfa truflun þegar birt er á öllum skjánum \n- Kíkja alltaf \n\n"<b>"Stig 4"</b>" \n- Hindra truflun við birtingu á öllum skjánum \n- Kíkja alltaf \n\n"<b>"Stig 3"</b>" \n- Hindra truflun við birtingu á öllum skjánum \n- Kíkja aldrei \n\n"<b>"Stig 2"</b>" \n- Hindra truflun við birtingu á öllum skjánum \n- Kíkja aldrei \n- Slökkva á hljóði og titringi \n\n"<b>"Stig 1"</b>" \n- Hindra truflun við birtingu á öllum skjánum \n- Kíkja aldrei \n- Slökkva á hljóði og titringi \n- Fela á lásskjá og stöðustiku \n- Sýna neðst á tilkynningalista \n\n"<b>"Stig 0"</b>" \n- Setja allar tilkynningar frá forriti á bannlista"</string>
<string name="notification_header_default_channel" msgid="7506845022070889909">"Tilkynningar"</string>
- <string name="notification_channel_disabled" msgid="2139193533791840539">"Þú færð þessar tilkynningar ekki framar"</string>
- <string name="notification_num_channels" msgid="2048144408999179471">"<xliff:g id="NUMBER">%d</xliff:g> tilkynningaflokkar"</string>
- <string name="notification_default_channel_desc" msgid="2506053815870808359">"Þetta forrit er ekki með tilkynningaflokka"</string>
- <string name="notification_unblockable_desc" msgid="3561016061737896906">"Ekki er hægt að slökkva á tilkynningum frá þessu forriti"</string>
- <plurals name="notification_num_channels_desc" formatted="false" msgid="5492793452274077663">
- <item quantity="one">1 af <xliff:g id="NUMBER_1">%s</xliff:g> tilkynningaflokki frá þessu forriti</item>
- <item quantity="other">1 af <xliff:g id="NUMBER_1">%s</xliff:g> tilkynningaflokkum frá þessu forriti</item>
- </plurals>
- <string name="notification_channels_list_desc_2" msgid="6214732715833946441">"<xliff:g id="CHANNEL_NAME_1">%1$s</xliff:g>, <xliff:g id="CHANNEL_NAME_2">%2$s</xliff:g>"</string>
- <plurals name="notification_channels_list_desc_2_and_others" formatted="false" msgid="2747813553355336157">
- <item quantity="one"><xliff:g id="CHANNEL_NAME_1_3">%1$s</xliff:g>, <xliff:g id="CHANNEL_NAME_2_4">%2$s</xliff:g> og <xliff:g id="NUMBER_5">%3$d</xliff:g> í viðbót</item>
- <item quantity="other"><xliff:g id="CHANNEL_NAME_1_3">%1$s</xliff:g>, <xliff:g id="CHANNEL_NAME_2_4">%2$s</xliff:g> og <xliff:g id="NUMBER_5">%3$d</xliff:g> í viðbót</item>
- </plurals>
+ <string name="notification_channel_disabled" msgid="344536703863700565">"Þú munt ekki sjá þessar tilkynningar aftur"</string>
+ <string name="inline_keep_showing" msgid="8945102997083836858">"Sýna áfram þessar tilkynningar?"</string>
+ <string name="inline_stop_button" msgid="4172980096860941033">"Stöðva tilkynningar"</string>
+ <string name="inline_keep_button" msgid="6665940297019018232">"Sýna áfram"</string>
+ <string name="inline_keep_showing_app" msgid="1723113469580031041">"Sýna áfram tilkynningar frá þessu forriti?"</string>
+ <string name="notification_unblockable_desc" msgid="1037434112919403708">"Ekki er hægt að slökkva á þessum tilkynningum"</string>
<string name="notification_channel_controls_opened_accessibility" msgid="6553950422055908113">"Opnað fyrir tilkynningastýringar <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
<string name="notification_channel_controls_closed_accessibility" msgid="7521619812603693144">"Lokað fyrir tilkynningastýringar <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
<string name="notification_channel_switch_accessibility" msgid="3420796005601900717">"Leyfa tilkynningar frá þessari rás"</string>
- <string name="notification_all_categories" msgid="5407190218055113282">"Allir flokkar"</string>
<string name="notification_more_settings" msgid="816306283396553571">"Fleiri stillingar"</string>
- <string name="notification_app_settings" msgid="3743278649182392015">"Sérstilla: <xliff:g id="SUB_CATEGORY">%1$s</xliff:g>"</string>
+ <string name="notification_app_settings" msgid="420348114670768449">"Sérsníða"</string>
<string name="notification_done" msgid="5279426047273930175">"Lokið"</string>
+ <string name="inline_undo" msgid="558916737624706010">"Afturkalla"</string>
<string name="notification_menu_accessibility" msgid="2046162834248888553">"<xliff:g id="APP_NAME">%1$s</xliff:g> <xliff:g id="MENU_DESCRIPTION">%2$s</xliff:g>"</string>
<string name="notification_menu_gear_description" msgid="2204480013726775108">"tilkynningastýringar"</string>
<string name="notification_menu_snooze_description" msgid="3653669438131034525">"þöggunarstillingar tilkynninga"</string>
@@ -731,8 +728,7 @@
<string name="pip_phone_expand" msgid="5889780005575693909">"Stækka"</string>
<string name="pip_phone_minimize" msgid="1079119422589131792">"Minnka"</string>
<string name="pip_phone_close" msgid="8416647892889710330">"Loka"</string>
- <!-- no translation found for pip_phone_settings (8080777499521528521) -->
- <skip />
+ <string name="pip_phone_settings" msgid="8080777499521528521">"Stillingar"</string>
<string name="pip_phone_dismiss_hint" msgid="6351678169095923899">"Draga niður til að hunsa"</string>
<string name="pip_menu_title" msgid="4707292089961887657">"Valmynd"</string>
<string name="pip_notification_title" msgid="3204024940158161322">"<xliff:g id="NAME">%s</xliff:g> er með mynd í mynd"</string>
diff --git a/packages/SystemUI/res/values-iw/strings.xml b/packages/SystemUI/res/values-iw/strings.xml
index 276fa3331894..4fd68c2caf8d 100644
--- a/packages/SystemUI/res/values-iw/strings.xml
+++ b/packages/SystemUI/res/values-iw/strings.xml
@@ -35,7 +35,10 @@
<string name="status_bar_ongoing_events_title" msgid="1682504513316879202">"מתמשך"</string>
<string name="status_bar_latest_events_title" msgid="6594767438577593172">"הודעות"</string>
<string name="battery_low_title" msgid="6456385927409742437">"עוצמת הסוללה נמוכה"</string>
+ <string name="battery_low_title_hybrid" msgid="6268991275887381595">"עוצמת הסוללה נמוכה. כדאי להפעיל את מצב החיסכון בסוללה"</string>
<string name="battery_low_percent_format" msgid="2900940511201380775">"נותרו <xliff:g id="PERCENTAGE">%s</xliff:g>"</string>
+ <string name="battery_low_percent_format_hybrid" msgid="6838677459286775617">"נותרו <xliff:g id="PERCENTAGE">%s</xliff:g>, נשארו בערך <xliff:g id="TIME">%s</xliff:g> על סמך השימוש במכשיר"</string>
+ <string name="battery_low_percent_format_hybrid_short" msgid="9025795469949145586">"נותרו <xliff:g id="PERCENTAGE">%s</xliff:g>, נשארו בערך <xliff:g id="TIME">%s</xliff:g>"</string>
<string name="battery_low_percent_format_saver_started" msgid="7879389868952879166">"נותרו <xliff:g id="PERCENTAGE">%s</xliff:g>. הופעלה תכונת החיסכון בסוללה."</string>
<string name="invalid_charger" msgid="4549105996740522523">"‏טעינה באמצעות USB אינה נתמכת.\nהשתמש אך ורק במטען שסופק."</string>
<string name="invalid_charger_title" msgid="3515740382572798460">"‏טעינה בחיבור USB אינה נתמכת."</string>
@@ -69,14 +72,15 @@
<string name="usb_debugging_secondary_user_message" msgid="6067122453571699801">"‏למשתמש המחובר לחשבון במכשיר הזה אין אפשרות להפעיל ניפוי באגים ב-USB. כדי להשתמש בתכונה הזו יש לעבור אל המשתמש הראשי."</string>
<string name="compat_mode_on" msgid="6623839244840638213">"הגדל תצוגה כדי למלא את המסך"</string>
<string name="compat_mode_off" msgid="4434467572461327898">"מתח כדי למלא את המסך"</string>
+ <string name="global_action_screenshot" msgid="8329831278085426283">"צילום מסך"</string>
<string name="screenshot_saving_ticker" msgid="7403652894056693515">"שומר צילום מסך..."</string>
<string name="screenshot_saving_title" msgid="8242282144535555697">"שומר צילום מסך..."</string>
- <string name="screenshot_saving_text" msgid="2419718443411738818">"מתבצעת שמירה של צילום המסך."</string>
- <string name="screenshot_saved_title" msgid="6461865960961414961">"צילום המסך בוצע."</string>
- <string name="screenshot_saved_text" msgid="2685605830386712477">"הקש כדי להציג את צילום המסך שלך."</string>
- <string name="screenshot_failed_title" msgid="705781116746922771">"לא ניתן לבצע צילום מסך."</string>
- <string name="screenshot_failed_to_save_unknown_text" msgid="7887826345701753830">"התגלתה בעיה בשמירת צילום מסך."</string>
- <string name="screenshot_failed_to_save_text" msgid="2592658083866306296">"לא ניתן לשמור צילום מסך עקב שטח אחסון מוגבל."</string>
+ <string name="screenshot_saving_text" msgid="2545047868936087248">"מתבצעת שמירה של צילום המסך"</string>
+ <string name="screenshot_saved_title" msgid="5637073968117370753">"צילום המסך נשמר"</string>
+ <string name="screenshot_saved_text" msgid="7574667448002050363">"אפשר להקיש כדי להציג את צילום המסך"</string>
+ <string name="screenshot_failed_title" msgid="9096484883063264803">"לא ניתן לבצע צילום מסך"</string>
+ <string name="screenshot_failed_to_save_unknown_text" msgid="8844781948876286488">"התגלתה בעיה בשמירת צילום המסך"</string>
+ <string name="screenshot_failed_to_save_text" msgid="3041612585107107310">"לא ניתן לשמור צילום מסך עקב שטח אחסון מוגבל"</string>
<string name="screenshot_failed_to_capture_text" msgid="173674476457581486">"האפליקציה או הארגון שלך אינם מתירים ליצור צילומי מסך"</string>
<string name="usb_preference_title" msgid="6551050377388882787">"‏אפשרויות העברת קבצים ב-USB"</string>
<string name="use_mtp_button_title" msgid="4333504413563023626">"‏טען כנגן מדיה (MTP)"</string>
@@ -561,30 +565,19 @@
<string name="tuner_full_importance_settings_off" msgid="8208165412614935229">"כבוי"</string>
<string name="power_notification_controls_description" msgid="4372459941671353358">"בעזרת פקדים של הודעות הפעלה, תוכל להגדיר רמת חשיבות מ-0 עד 5 להודעות אפליקציה. \n\n"<b>"רמה 5"</b>" \n- הצג בראש רשימת ההודעות \n- אפשר הפרעה במסך מלא \n- תמיד אפשר הצצה \n\n"<b>"רמה 4"</b>" \n- מנע הפרעה במסך מלא \n- תמיד אפשר הצצה \n\n"<b>"רמה 3"</b>" \n- מנע הפרעה במסך מלא \n- אף פעם אל תאפשר הצצה \n\n"<b>"רמה 2"</b>" \n- מנע הפרעה במסך מלא \n- אף פעם אל תאפשר הצצה \n- אף פעם אל תאפשר קול ורטט \n\n"<b>"רמה 1"</b>" \n- מנע הפרעה במסך מלא \n- אף פעם אל תאפשר הצצה \n- אף פעם אל תאפשר קול ורטט \n- הסתר ממסך הנעילה ומשורת הסטטוס \n- הצג בתחתית רשימת ההודעות \n\n"<b>"רמה 0"</b>" \n- חסום את כל ההודעות מהאפליקציה"</string>
<string name="notification_header_default_channel" msgid="7506845022070889909">"הודעות"</string>
- <string name="notification_channel_disabled" msgid="2139193533791840539">"לא תקבל את ההודעות האלה יותר"</string>
- <string name="notification_num_channels" msgid="2048144408999179471">"<xliff:g id="NUMBER">%d</xliff:g> קטגוריות של הודעות"</string>
- <string name="notification_default_channel_desc" msgid="2506053815870808359">"האפליקציה הזו לא תומכת בקטגוריות של הודעות"</string>
- <string name="notification_unblockable_desc" msgid="3561016061737896906">"לא ניתן לכבות הודעות של האפליקציה הזאת"</string>
- <plurals name="notification_num_channels_desc" formatted="false" msgid="5492793452274077663">
- <item quantity="two">קטגוריית הודעות אחת מתוך <xliff:g id="NUMBER_1">%s</xliff:g> מאפליקציה זו</item>
- <item quantity="many">קטגוריית הודעות אחת מתוך <xliff:g id="NUMBER_1">%s</xliff:g> מאפליקציה זו</item>
- <item quantity="other">קטגוריית הודעות אחת מתוך <xliff:g id="NUMBER_1">%s</xliff:g> מאפליקציה זו</item>
- <item quantity="one">קטגוריית הודעות אחת מתוך <xliff:g id="NUMBER_0">%s</xliff:g> מאפליקציה זו</item>
- </plurals>
- <string name="notification_channels_list_desc_2" msgid="6214732715833946441">"<xliff:g id="CHANNEL_NAME_1">%1$s</xliff:g>, <xliff:g id="CHANNEL_NAME_2">%2$s</xliff:g>"</string>
- <plurals name="notification_channels_list_desc_2_and_others" formatted="false" msgid="2747813553355336157">
- <item quantity="two"><xliff:g id="CHANNEL_NAME_1_3">%1$s</xliff:g>‏, <xliff:g id="CHANNEL_NAME_2_4">%2$s</xliff:g> ו-<xliff:g id="NUMBER_5">%3$d</xliff:g> אחרים</item>
- <item quantity="many"><xliff:g id="CHANNEL_NAME_1_3">%1$s</xliff:g>‏, <xliff:g id="CHANNEL_NAME_2_4">%2$s</xliff:g> ו-,<xliff:g id="NUMBER_5">%3$d</xliff:g> אחרים</item>
- <item quantity="other"><xliff:g id="CHANNEL_NAME_1_3">%1$s</xliff:g>‏, <xliff:g id="CHANNEL_NAME_2_4">%2$s</xliff:g> ו-<xliff:g id="NUMBER_5">%3$d</xliff:g> אחרים</item>
- <item quantity="one"><xliff:g id="CHANNEL_NAME_1_0">%1$s</xliff:g>‏, <xliff:g id="CHANNEL_NAME_2_1">%2$s</xliff:g> ו-<xliff:g id="NUMBER_2">%3$d</xliff:g> אחר</item>
- </plurals>
+ <string name="notification_channel_disabled" msgid="344536703863700565">"לא תראה יותר את ההודעות האלה"</string>
+ <string name="inline_keep_showing" msgid="8945102997083836858">"להמשיך להציג את ההודעות האלה?"</string>
+ <string name="inline_stop_button" msgid="4172980096860941033">"הפסקת הודעות"</string>
+ <string name="inline_keep_button" msgid="6665940297019018232">"להמשיך להציג"</string>
+ <string name="inline_keep_showing_app" msgid="1723113469580031041">"להמשיך להציג הודעות מהאפליקציה הזאת?"</string>
+ <string name="notification_unblockable_desc" msgid="1037434112919403708">"לא ניתן לכבות את ההודעות האלה"</string>
<string name="notification_channel_controls_opened_accessibility" msgid="6553950422055908113">"פקדי ההודעות של <xliff:g id="APP_NAME">%1$s</xliff:g> נפתחו"</string>
<string name="notification_channel_controls_closed_accessibility" msgid="7521619812603693144">"פקדי ההודעות של <xliff:g id="APP_NAME">%1$s</xliff:g> נסגרו"</string>
<string name="notification_channel_switch_accessibility" msgid="3420796005601900717">"התר הודעות מערוץ זה"</string>
- <string name="notification_all_categories" msgid="5407190218055113282">"כל הקטגוריות"</string>
<string name="notification_more_settings" msgid="816306283396553571">"הגדרות נוספות"</string>
- <string name="notification_app_settings" msgid="3743278649182392015">"התאמה אישית: <xliff:g id="SUB_CATEGORY">%1$s</xliff:g>"</string>
+ <string name="notification_app_settings" msgid="420348114670768449">"התאמה אישית"</string>
<string name="notification_done" msgid="5279426047273930175">"סיום"</string>
+ <string name="inline_undo" msgid="558916737624706010">"ביטול"</string>
<string name="notification_menu_accessibility" msgid="2046162834248888553">"<xliff:g id="APP_NAME">%1$s</xliff:g> <xliff:g id="MENU_DESCRIPTION">%2$s</xliff:g>"</string>
<string name="notification_menu_gear_description" msgid="2204480013726775108">"בקרת הודעות"</string>
<string name="notification_menu_snooze_description" msgid="3653669438131034525">"אפשרויות של דחיית הודעות לטיפול בהמשך"</string>
@@ -743,8 +736,7 @@
<string name="pip_phone_expand" msgid="5889780005575693909">"הרחב"</string>
<string name="pip_phone_minimize" msgid="1079119422589131792">"מזער"</string>
<string name="pip_phone_close" msgid="8416647892889710330">"סגור"</string>
- <!-- no translation found for pip_phone_settings (8080777499521528521) -->
- <skip />
+ <string name="pip_phone_settings" msgid="8080777499521528521">"הגדרות"</string>
<string name="pip_phone_dismiss_hint" msgid="6351678169095923899">"גרור למטה כדי לסגור"</string>
<string name="pip_menu_title" msgid="4707292089961887657">"תפריט"</string>
<string name="pip_notification_title" msgid="3204024940158161322">"<xliff:g id="NAME">%s</xliff:g> במצב תמונה בתוך תמונה"</string>
diff --git a/packages/SystemUI/res/values-ka/strings.xml b/packages/SystemUI/res/values-ka/strings.xml
index 870c89632fc1..09c978f1a22c 100644
--- a/packages/SystemUI/res/values-ka/strings.xml
+++ b/packages/SystemUI/res/values-ka/strings.xml
@@ -33,7 +33,10 @@
<string name="status_bar_ongoing_events_title" msgid="1682504513316879202">"მიმდინარე"</string>
<string name="status_bar_latest_events_title" msgid="6594767438577593172">"შეტყობინებები"</string>
<string name="battery_low_title" msgid="6456385927409742437">"ბატარეა იწურება"</string>
+ <string name="battery_low_title_hybrid" msgid="6268991275887381595">"ბატარეა იწურება. ჩართეთ ბატარეის დამზოგი"</string>
<string name="battery_low_percent_format" msgid="2900940511201380775">"დარჩენილია <xliff:g id="PERCENTAGE">%s</xliff:g>"</string>
+ <string name="battery_low_percent_format_hybrid" msgid="6838677459286775617">"დარჩენილია <xliff:g id="PERCENTAGE">%s</xliff:g>, რაც დაახლოებით <xliff:g id="TIME">%s</xliff:g> არის, მოხმარების გათვალისწინებით"</string>
+ <string name="battery_low_percent_format_hybrid_short" msgid="9025795469949145586">"დარჩენილია <xliff:g id="PERCENTAGE">%s</xliff:g>, რაც დაახლოებით <xliff:g id="TIME">%s</xliff:g> არის"</string>
<string name="battery_low_percent_format_saver_started" msgid="7879389868952879166">"დარჩენილია <xliff:g id="PERCENTAGE">%s</xliff:g>. ბატარეის დამზოგი ჩართულია."</string>
<string name="invalid_charger" msgid="4549105996740522523">"USB-ით დატენვა არ არის მხარდაჭერილი.\nგამოიყენეთ მხოლოდ ელექტრო-დამტენი."</string>
<string name="invalid_charger_title" msgid="3515740382572798460">"USB დატენვა მხარდაჭერილი არ არის."</string>
@@ -67,14 +70,15 @@
<string name="usb_debugging_secondary_user_message" msgid="6067122453571699801">"ამ მოწყობილობაზე ამჟამად შესულ მომხმარებელს არ შეუძლია USB ხარვეზების გამართვის ფუნქციის ჩართვა. ამ ფუნქციის გამოსაყენებლად, მიუერთდით მთავარ მომხმარებელს."</string>
<string name="compat_mode_on" msgid="6623839244840638213">"მასშტაბი შეცვალეთ ეკრანის შესავსებად."</string>
<string name="compat_mode_off" msgid="4434467572461327898">"გაწიეთ ეკრანის შესავსებად."</string>
+ <string name="global_action_screenshot" msgid="8329831278085426283">"ეკრანის ანაბეჭდი"</string>
<string name="screenshot_saving_ticker" msgid="7403652894056693515">"სკრინშოტის შენახვა…"</string>
<string name="screenshot_saving_title" msgid="8242282144535555697">"ეკრანის სურათის შენახვა…"</string>
- <string name="screenshot_saving_text" msgid="2419718443411738818">"ეკრანის სურათი შენახულია."</string>
- <string name="screenshot_saved_title" msgid="6461865960961414961">"სკრინშოტი გადაღებულია."</string>
- <string name="screenshot_saved_text" msgid="2685605830386712477">"შეეხეთ ეკრანის ანაბეჭდის სანახავად."</string>
- <string name="screenshot_failed_title" msgid="705781116746922771">"ვერ მოხერხდა ეკრანის ანაბეჭდის გადაღება."</string>
- <string name="screenshot_failed_to_save_unknown_text" msgid="7887826345701753830">"ეკრანის ანაბეჭდის შენახვისას წარმოიქმნა პრობლემა."</string>
- <string name="screenshot_failed_to_save_text" msgid="2592658083866306296">"ეკრანის ანაბეჭდის შენახვა ვერ მოხერხდა შეზღუდული მეხსიერების გამო."</string>
+ <string name="screenshot_saving_text" msgid="2545047868936087248">"ეკრანის ანაბეჭდი შენახულია"</string>
+ <string name="screenshot_saved_title" msgid="5637073968117370753">"ეკრანის ანაბეჭდი შენახულია"</string>
+ <string name="screenshot_saved_text" msgid="7574667448002050363">"შეეხეთ ეკრანის ანაბეჭდის სანახავად"</string>
+ <string name="screenshot_failed_title" msgid="9096484883063264803">"ვერ მოხერხდა ეკრანის ანაბეჭდის გადაღება"</string>
+ <string name="screenshot_failed_to_save_unknown_text" msgid="8844781948876286488">"ეკრანის ანაბეჭდის შენახვისას წარმოიქმნა პრობლემა"</string>
+ <string name="screenshot_failed_to_save_text" msgid="3041612585107107310">"ეკრანის ანაბეჭდის შენახვა ვერ მოხერხდა შეზღუდული მეხსიერების გამო"</string>
<string name="screenshot_failed_to_capture_text" msgid="173674476457581486">"ეკრანის ანაბეჭდების შექმნა არ არის ნებადართული აპის ან თქვენი ორგანიზაციის მიერ"</string>
<string name="usb_preference_title" msgid="6551050377388882787">"USB ფაილის ტრანსფერის პარამეტრები"</string>
<string name="use_mtp_button_title" msgid="4333504413563023626">"მედია-საკრავად (MTP) ჩართვა"</string>
@@ -557,26 +561,19 @@
<string name="tuner_full_importance_settings_off" msgid="8208165412614935229">"გამორთული"</string>
<string name="power_notification_controls_description" msgid="4372459941671353358">"შეტყობინებების მართვის საშუალებების მეშვეობით, შეგიძლიათ განსაზღვროთ აპის შეტყობინებების მნიშვნელობის დონე 0-დან 5-მდე დიაპაზონში. \n\n"<b>"დონე 5"</b>" \n— შეტყობინებათა სიის თავში ჩვენება \n— სრულეკრანიანი რეჟიმის შეფერხების დაშვება \n— ეკრანზე ყოველთვის გამოჩენა \n\n"<b>"დონე 4"</b>" \n— სრულეკრანიანი რეჟიმის შეფერხების აღკვეთა \n— ეკრანზე ყოველთვის გამოჩენა \n\n"<b>"დონე 3"</b>" \n— სრულეკრანიანი რეჟიმის შეფერხების აღკვეთა \n— ეკრანზე გამოჩენის აღკვეთა \n\n"<b>"დონე 2"</b>" \n— სრულეკრანიანი რეჟიმის შეფერხების აღკვეთა \n— ეკრანზე გამოჩენის აღკვეთა \n— ხმისა და ვიბრაციის აღკვეთა \n\n"<b>"დონე 1"</b>" \n— სრულეკრანიანი რეჟიმის შეფერხების აღკვეთა \n— ეკრანზე გამოჩენის აღკვეთა \n— ხმისა და ვიბრაციის აღკვეთა \n— ჩაკეტილი ეკრანიდან და სტატუსის ზოლიდან დამალვა \n— შეტყობინებათა სიის ბოლოში ჩვენება \n\n"<b>"დონე 0"</b>" \n— აპის ყველა შეტყობინების დაბლოკვა"</string>
<string name="notification_header_default_channel" msgid="7506845022070889909">"შეტყობინებები"</string>
- <string name="notification_channel_disabled" msgid="2139193533791840539">"ამ შეტყობინებებს აღარ მიიღებთ"</string>
- <string name="notification_num_channels" msgid="2048144408999179471">"შეტყობინებების <xliff:g id="NUMBER">%d</xliff:g> კატეგორია"</string>
- <string name="notification_default_channel_desc" msgid="2506053815870808359">"ამ აპს შეტყობინებების კატეგორიები არ აქვს"</string>
- <string name="notification_unblockable_desc" msgid="3561016061737896906">"ამ აპიდან შეტყობინებების გამორთვა ვერ მოხერხდება"</string>
- <plurals name="notification_num_channels_desc" formatted="false" msgid="5492793452274077663">
- <item quantity="other">ამ აპის შეტყობინებების <xliff:g id="NUMBER_1">%s</xliff:g> კატეგორიიდან 1</item>
- <item quantity="one">ამ აპის შეტყობინებების <xliff:g id="NUMBER_0">%s</xliff:g> კატეგორიიდან 1</item>
- </plurals>
- <string name="notification_channels_list_desc_2" msgid="6214732715833946441">"<xliff:g id="CHANNEL_NAME_1">%1$s</xliff:g>, <xliff:g id="CHANNEL_NAME_2">%2$s</xliff:g>"</string>
- <plurals name="notification_channels_list_desc_2_and_others" formatted="false" msgid="2747813553355336157">
- <item quantity="other"><xliff:g id="CHANNEL_NAME_1_3">%1$s</xliff:g>, <xliff:g id="CHANNEL_NAME_2_4">%2$s</xliff:g> და <xliff:g id="NUMBER_5">%3$d</xliff:g> სხვა</item>
- <item quantity="one"><xliff:g id="CHANNEL_NAME_1_0">%1$s</xliff:g>, <xliff:g id="CHANNEL_NAME_2_1">%2$s</xliff:g> და <xliff:g id="NUMBER_2">%3$d</xliff:g> სხვა</item>
- </plurals>
+ <string name="notification_channel_disabled" msgid="344536703863700565">"ამ შეტყობინებებს აღარ დაინახავთ"</string>
+ <string name="inline_keep_showing" msgid="8945102997083836858">"გაგრძელდეს ამ შეტყობინებათა ჩვენება?"</string>
+ <string name="inline_stop_button" msgid="4172980096860941033">"შეტყობინებების შეწყვეტა"</string>
+ <string name="inline_keep_button" msgid="6665940297019018232">"ჩვენების გაგრძელება"</string>
+ <string name="inline_keep_showing_app" msgid="1723113469580031041">"გაგრძელდეს შეტყობინებათა ჩვენება ამ აპიდან?"</string>
+ <string name="notification_unblockable_desc" msgid="1037434112919403708">"ამ შეტყობინებათა გამორთვა ვერ მოხერხდება"</string>
<string name="notification_channel_controls_opened_accessibility" msgid="6553950422055908113">"შეტყობინებების მართვა „<xliff:g id="APP_NAME">%1$s</xliff:g>“-ისთვის გახსნილია"</string>
<string name="notification_channel_controls_closed_accessibility" msgid="7521619812603693144">"შეტყობინებების მართვა „<xliff:g id="APP_NAME">%1$s</xliff:g>“-ისთვის დახურულია"</string>
<string name="notification_channel_switch_accessibility" msgid="3420796005601900717">"ამ არხიდან შეტყობინებების დაშვება"</string>
- <string name="notification_all_categories" msgid="5407190218055113282">"ყველა კატეგორია"</string>
<string name="notification_more_settings" msgid="816306283396553571">"დამატებითი პარამეტრები"</string>
- <string name="notification_app_settings" msgid="3743278649182392015">"მორგება: <xliff:g id="SUB_CATEGORY">%1$s</xliff:g>"</string>
+ <string name="notification_app_settings" msgid="420348114670768449">"მორგება"</string>
<string name="notification_done" msgid="5279426047273930175">"მზადაა"</string>
+ <string name="inline_undo" msgid="558916737624706010">"მოქმედების გაუქმება"</string>
<string name="notification_menu_accessibility" msgid="2046162834248888553">"<xliff:g id="APP_NAME">%1$s</xliff:g> <xliff:g id="MENU_DESCRIPTION">%2$s</xliff:g>"</string>
<string name="notification_menu_gear_description" msgid="2204480013726775108">"შეტყობინებების მართვის საშუალებები"</string>
<string name="notification_menu_snooze_description" msgid="3653669438131034525">"შეტყობინებების ჩაჩუმების ვარიანტები"</string>
@@ -731,8 +728,7 @@
<string name="pip_phone_expand" msgid="5889780005575693909">"გაშლა"</string>
<string name="pip_phone_minimize" msgid="1079119422589131792">"ჩაკეცვა"</string>
<string name="pip_phone_close" msgid="8416647892889710330">"დახურვა"</string>
- <!-- no translation found for pip_phone_settings (8080777499521528521) -->
- <skip />
+ <string name="pip_phone_settings" msgid="8080777499521528521">"პარამეტრები"</string>
<string name="pip_phone_dismiss_hint" msgid="6351678169095923899">"დასახურად ჩავლებით ჩამოიტანეთ ქვემოთ"</string>
<string name="pip_menu_title" msgid="4707292089961887657">"მენიუ"</string>
<string name="pip_notification_title" msgid="3204024940158161322">"<xliff:g id="NAME">%s</xliff:g> იყენებს რეჟიმს „ეკრანი ეკრანში“"</string>
diff --git a/packages/SystemUI/res/values-kk/strings.xml b/packages/SystemUI/res/values-kk/strings.xml
index c4ae759aa7a9..061a926e1e0a 100644
--- a/packages/SystemUI/res/values-kk/strings.xml
+++ b/packages/SystemUI/res/values-kk/strings.xml
@@ -33,7 +33,10 @@
<string name="status_bar_ongoing_events_title" msgid="1682504513316879202">"Ағымдағы"</string>
<string name="status_bar_latest_events_title" msgid="6594767438577593172">"Хабарлар"</string>
<string name="battery_low_title" msgid="6456385927409742437">"Батарея заряды төмен"</string>
+ <string name="battery_low_title_hybrid" msgid="6268991275887381595">"Батарея заряды аз. \"Battery Saver\" функциясын қосыңыз"</string>
<string name="battery_low_percent_format" msgid="2900940511201380775">"<xliff:g id="PERCENTAGE">%s</xliff:g> қалды"</string>
+ <string name="battery_low_percent_format_hybrid" msgid="6838677459286775617">"Пайдалану барысына байланысты <xliff:g id="PERCENTAGE">%s</xliff:g> заряд, шамамен <xliff:g id="TIME">%s</xliff:g> қалды"</string>
+ <string name="battery_low_percent_format_hybrid_short" msgid="9025795469949145586">"<xliff:g id="PERCENTAGE">%s</xliff:g> заряд, шамамен <xliff:g id="TIME">%s</xliff:g> қалды"</string>
<string name="battery_low_percent_format_saver_started" msgid="7879389868952879166">"<xliff:g id="PERCENTAGE">%s</xliff:g> қалды. Battery Saver қосулы."</string>
<string name="invalid_charger" msgid="4549105996740522523">"USB зарядтауды қолдау ұсынылмаған.\nЖабдықталған зарядтағыш құрылғысын ғана қолданыңыз."</string>
<string name="invalid_charger_title" msgid="3515740382572798460">"USB арқылы зарядтауға қолдау көрсетілмейді."</string>
@@ -67,14 +70,15 @@
<string name="usb_debugging_secondary_user_message" msgid="6067122453571699801">"Бұл құрылғыға жаңа кірген пайдаланушы USB түзетуін іске қосылмайды. Бұл мүмкіндікті пайдалану үшін негізгі пайдаланушыға ауысыңыз."</string>
<string name="compat_mode_on" msgid="6623839244840638213">"Экранды толтыру үшін ұлғайту"</string>
<string name="compat_mode_off" msgid="4434467572461327898">"Экранды толтыру үшін созу"</string>
+ <string name="global_action_screenshot" msgid="8329831278085426283">"Скриншот"</string>
<string name="screenshot_saving_ticker" msgid="7403652894056693515">"Скриншотты сақтауда…"</string>
<string name="screenshot_saving_title" msgid="8242282144535555697">"Скриншотты сақтауда…"</string>
- <string name="screenshot_saving_text" msgid="2419718443411738818">"Скриншот сақталуда."</string>
- <string name="screenshot_saved_title" msgid="6461865960961414961">"Скриншот сақталды."</string>
- <string name="screenshot_saved_text" msgid="2685605830386712477">"Скриншотты көру үшін түртіңіз."</string>
- <string name="screenshot_failed_title" msgid="705781116746922771">"Скриншот жасалмады."</string>
- <string name="screenshot_failed_to_save_unknown_text" msgid="7887826345701753830">"Скриншотты сақтау кезінде мәселе туындады."</string>
- <string name="screenshot_failed_to_save_text" msgid="2592658083866306296">"Жадтағы шектеулі бос орынға байланысты скриншотты сақтау мүмкін емес."</string>
+ <string name="screenshot_saving_text" msgid="2545047868936087248">"Скриншот сақталуда"</string>
+ <string name="screenshot_saved_title" msgid="5637073968117370753">"Скриншот сақталды"</string>
+ <string name="screenshot_saved_text" msgid="7574667448002050363">"Скриншотты көру үшін түртіңіз"</string>
+ <string name="screenshot_failed_title" msgid="9096484883063264803">"Скриншот жасалмады"</string>
+ <string name="screenshot_failed_to_save_unknown_text" msgid="8844781948876286488">"Скриншотты сақтау кезінде ақау болды"</string>
+ <string name="screenshot_failed_to_save_text" msgid="3041612585107107310">"Жадтағы шектеулі бос орынға байланысты скриншот сақталмайды"</string>
<string name="screenshot_failed_to_capture_text" msgid="173674476457581486">"Қолданба немесе ұйым скриншоттар түсіруге рұқсат етпейді"</string>
<string name="usb_preference_title" msgid="6551050377388882787">"USB файлын жіберу опциялары"</string>
<string name="use_mtp_button_title" msgid="4333504413563023626">"Медиа ойнатқыш (MTP) ретінде қосыңыз"</string>
@@ -557,26 +561,19 @@
<string name="tuner_full_importance_settings_off" msgid="8208165412614935229">"Өшірулі"</string>
<string name="power_notification_controls_description" msgid="4372459941671353358">"Қуат хабарландыруының басқару элементтерімен қолданбаның хабарландырулары үшін 0-ден бастап 5-ке дейін маңыздылық деңгейін орнатуға болады. \n\n"<b>"5-деңгей"</b>" \n- Хабарландыру тізімінің ең басында көрсету \n- Толық экранға ашылуын рұқсат ету \n- Әрдайым қалқымалы хабарландыру түрінде көрсету \n\n"<b>"4-деңгей"</b>" \n- Толық экранға шығармау \n- Әрдайым қалқымалы хабарландыру түрінде көрсету \n\n"<b>"3-деңгей"</b>" \n- Толық экранға шығармау \n- Ешқашан қалқымалы хабарландыру түрінде көрсетпеу \n\n"<b>"2-деңгей"</b>" \n- Толық экранға шығармау \n- Ешқашан қалқымалы хабарландыру түрінде көрсетпеу \n- Ешқашан дыбыс және діріл шығармау \n\n"<b>"1-деңгей"</b>" \n- Толық экранға шығармау \n- Ешқашан қалқымалы хабарландыру түрінде көрсетпеу \n- Ешқашан дыбыс немесе діріл шығармау \n- Құлыпталған экраннан және күйін көрсету жолағынан жасыру \n- Хабарландыру тізімінің ең астында көрсету \n\n"<b>"0-деңгей"</b>" \n- Қолданбадағы барлық хабарландыруларға тыйым салу"</string>
<string name="notification_header_default_channel" msgid="7506845022070889909">"Хабарландырулар"</string>
- <string name="notification_channel_disabled" msgid="2139193533791840539">"Енді сізге бұл хабарландырулар жіберілмейді"</string>
- <string name="notification_num_channels" msgid="2048144408999179471">"<xliff:g id="NUMBER">%d</xliff:g> хабарландыру санаттары"</string>
- <string name="notification_default_channel_desc" msgid="2506053815870808359">"Бұл қолданбада хабарландыру санаттары жоқ"</string>
- <string name="notification_unblockable_desc" msgid="3561016061737896906">"Бұл қолданбаның хабарландырулары өшірілмейді"</string>
- <plurals name="notification_num_channels_desc" formatted="false" msgid="5492793452274077663">
- <item quantity="other">Осы қолданбадан <xliff:g id="NUMBER_1">%s</xliff:g> ішінен 1 хабарландыру санаты</item>
- <item quantity="one">Осы қолданбадан <xliff:g id="NUMBER_0">%s</xliff:g> ішінен 1 хабарландыру санаты</item>
- </plurals>
- <string name="notification_channels_list_desc_2" msgid="6214732715833946441">"<xliff:g id="CHANNEL_NAME_1">%1$s</xliff:g>, <xliff:g id="CHANNEL_NAME_2">%2$s</xliff:g>"</string>
- <plurals name="notification_channels_list_desc_2_and_others" formatted="false" msgid="2747813553355336157">
- <item quantity="other"><xliff:g id="CHANNEL_NAME_1_3">%1$s</xliff:g>, <xliff:g id="CHANNEL_NAME_2_4">%2$s</xliff:g> және тағы <xliff:g id="NUMBER_5">%3$d</xliff:g></item>
- <item quantity="one"><xliff:g id="CHANNEL_NAME_1_0">%1$s</xliff:g>, <xliff:g id="CHANNEL_NAME_2_1">%2$s</xliff:g> және тағы <xliff:g id="NUMBER_2">%3$d</xliff:g></item>
- </plurals>
+ <string name="notification_channel_disabled" msgid="344536703863700565">"Хабарландырулар бұдан былай көрсетілмейді"</string>
+ <string name="inline_keep_showing" msgid="8945102997083836858">"Хабарландырулар көрсетілсін бе?"</string>
+ <string name="inline_stop_button" msgid="4172980096860941033">"Хабарландыруларға тыйым салу"</string>
+ <string name="inline_keep_button" msgid="6665940297019018232">"Көрсету"</string>
+ <string name="inline_keep_showing_app" msgid="1723113469580031041">"Осы қолданбаның хабарландырулары көрсетілсін бе?"</string>
+ <string name="notification_unblockable_desc" msgid="1037434112919403708">"Хабарландыруларды өшіру мүмкін емес"</string>
<string name="notification_channel_controls_opened_accessibility" msgid="6553950422055908113">"<xliff:g id="APP_NAME">%1$s</xliff:g> хабарландыруларын басқару элементтері ашылды"</string>
<string name="notification_channel_controls_closed_accessibility" msgid="7521619812603693144">"<xliff:g id="APP_NAME">%1$s</xliff:g> хабарландыруларын басқару элементтері жабылды"</string>
<string name="notification_channel_switch_accessibility" msgid="3420796005601900717">"Осы арнадан келетін хабарландыруларға рұқсат беру"</string>
- <string name="notification_all_categories" msgid="5407190218055113282">"Барлық санаттар"</string>
<string name="notification_more_settings" msgid="816306283396553571">"Қосымша параметрлер"</string>
- <string name="notification_app_settings" msgid="3743278649182392015">"Реттеу: <xliff:g id="SUB_CATEGORY">%1$s</xliff:g>"</string>
+ <string name="notification_app_settings" msgid="420348114670768449">"Реттеу"</string>
<string name="notification_done" msgid="5279426047273930175">"Дайын"</string>
+ <string name="inline_undo" msgid="558916737624706010">"Қайтару"</string>
<string name="notification_menu_accessibility" msgid="2046162834248888553">"<xliff:g id="APP_NAME">%1$s</xliff:g> <xliff:g id="MENU_DESCRIPTION">%2$s</xliff:g>"</string>
<string name="notification_menu_gear_description" msgid="2204480013726775108">"хабарландыруларды басқару элементтері"</string>
<string name="notification_menu_snooze_description" msgid="3653669438131034525">"хабарландыруды кідірту опциялары"</string>
@@ -731,8 +728,7 @@
<string name="pip_phone_expand" msgid="5889780005575693909">"Жаю"</string>
<string name="pip_phone_minimize" msgid="1079119422589131792">"Кішірейту"</string>
<string name="pip_phone_close" msgid="8416647892889710330">"Жабу"</string>
- <!-- no translation found for pip_phone_settings (8080777499521528521) -->
- <skip />
+ <string name="pip_phone_settings" msgid="8080777499521528521">"Реттеулер"</string>
<string name="pip_phone_dismiss_hint" msgid="6351678169095923899">"Жабу үшін төмен қарай сүйреңіз"</string>
<string name="pip_menu_title" msgid="4707292089961887657">"Mәзір"</string>
<string name="pip_notification_title" msgid="3204024940158161322">"<xliff:g id="NAME">%s</xliff:g> \"сурет ішіндегі сурет\" режимінде"</string>
diff --git a/packages/SystemUI/res/values-km/strings.xml b/packages/SystemUI/res/values-km/strings.xml
index 12733f1c9e0e..175e10cc1649 100644
--- a/packages/SystemUI/res/values-km/strings.xml
+++ b/packages/SystemUI/res/values-km/strings.xml
@@ -33,7 +33,10 @@
<string name="status_bar_ongoing_events_title" msgid="1682504513316879202">"បន្ត"</string>
<string name="status_bar_latest_events_title" msgid="6594767438577593172">"ការ​ជូន​ដំណឹង"</string>
<string name="battery_low_title" msgid="6456385927409742437">"ជិត​អស់​ថ្ម​ហើយ"</string>
+ <string name="battery_low_title_hybrid" msgid="6268991275887381595">"កម្រិត​ថ្ម​នៅ​សល់​តិច។ សូមបើក​កម្មវិធីសន្សំថ្ម"</string>
<string name="battery_low_percent_format" msgid="2900940511201380775">"នៅ​សល់ <xliff:g id="PERCENTAGE">%s</xliff:g>"</string>
+ <string name="battery_low_percent_format_hybrid" msgid="6838677459286775617">"នៅសល់ <xliff:g id="PERCENTAGE">%s</xliff:g> អាច​ប្រើ​បាន​ប្រហែល <xliff:g id="TIME">%s</xliff:g> ទៀត​ផ្អែកលើ​ការប្រើប្រាស់​របស់អ្នក"</string>
+ <string name="battery_low_percent_format_hybrid_short" msgid="9025795469949145586">"នៅសល់ <xliff:g id="PERCENTAGE">%s</xliff:g> អាច​ប្រើ​បាន​ប្រហែល <xliff:g id="TIME">%s</xliff:g> ទៀត"</string>
<string name="battery_low_percent_format_saver_started" msgid="7879389868952879166">"នៅ​សល់ <xliff:g id="PERCENTAGE">%s</xliff:g> ។ កម្មវិធី​សន្សំ​ថ្ម​បានបើក។"</string>
<string name="invalid_charger" msgid="4549105996740522523">"មិន​គាំទ្រ​ការ​បញ្ចូល​តាម​យូអេសប៊ី។\nប្រើ​តែ​ឧបករណ៍​បញ្ចូល​ថ្ម​ដែល​បាន​ផ្ដល់។"</string>
<string name="invalid_charger_title" msgid="3515740382572798460">"មិន​គាំទ្រ​ការ​បញ្ចូល​ថ្ម​តាម​យូអេសប៊ី​ទេ។"</string>
@@ -67,14 +70,15 @@
<string name="usb_debugging_secondary_user_message" msgid="6067122453571699801">"អ្នកប្រើ​ដែលបច្ចុប្បន្ន​បានចូលគណនី​នៅលើឧបករណ៍នេះ​មិនអាចបើកការកែកំហុស USB បានទេ។ ដើម្បីប្រើមុខងារនេះ សូមប្តូរទៅអ្នកប្រើចម្បង។"</string>
<string name="compat_mode_on" msgid="6623839244840638213">"ពង្រីក​​ដើម្បី​ឲ្យ​ពេញ​អេក្រង់"</string>
<string name="compat_mode_off" msgid="4434467572461327898">"ទាញ​ដើម្បី​ឲ្យ​ពេញ​អេក្រង់"</string>
+ <string name="global_action_screenshot" msgid="8329831278085426283">"រូបថតអេក្រង់"</string>
<string name="screenshot_saving_ticker" msgid="7403652894056693515">"កំពុង​រក្សាទុក​រូបថត​អេក្រង់…"</string>
<string name="screenshot_saving_title" msgid="8242282144535555697">"កំពុង​រក្សាទុក​រូបថត​អេក្រង់..."</string>
- <string name="screenshot_saving_text" msgid="2419718443411738818">"រូបថត​អេក្រង់​កំពុង​ត្រូវ​បាន​រក្សាទុក។"</string>
- <string name="screenshot_saved_title" msgid="6461865960961414961">"បាន​ចាប់​យក​រូបថត​អេក្រង់។​"</string>
- <string name="screenshot_saved_text" msgid="2685605830386712477">"ប៉ះដើម្បីមើលរូបថតអេក្រង់របស់អ្នក"</string>
- <string name="screenshot_failed_title" msgid="705781116746922771">"មិន​អាច​ចាប់​យក​រូប​ថត​អេក្រង់​។"</string>
- <string name="screenshot_failed_to_save_unknown_text" msgid="7887826345701753830">"បានជួបប្រទះបញ្ហាខណៈពេលរក្សាទុកការថតអេក្រង់"</string>
- <string name="screenshot_failed_to_save_text" msgid="2592658083866306296">"មិនអាចរក្សាទុករូបថតអេក្រង់បានទេដោយសារទំហំផ្ទុកមានកម្រិត។"</string>
+ <string name="screenshot_saving_text" msgid="2545047868936087248">"​កំពុង​​រក្សាទុករូបថត​អេក្រង់"</string>
+ <string name="screenshot_saved_title" msgid="5637073968117370753">"បានរក្សាទុក​រូបថតអេក្រង់"</string>
+ <string name="screenshot_saved_text" msgid="7574667448002050363">"ចុច​ដើម្បីមើល​រូបថតអេក្រង់​របស់អ្នក"</string>
+ <string name="screenshot_failed_title" msgid="9096484883063264803">"មិន​អាច​​ថត​រូប​អេក្រង់​​បាន​ទេ"</string>
+ <string name="screenshot_failed_to_save_unknown_text" msgid="8844781948876286488">"បានជួប​បញ្ហា​ពេល​កំពុង​​រក្សាទុក​រូបថតអេក្រង់"</string>
+ <string name="screenshot_failed_to_save_text" msgid="3041612585107107310">"មិនអាច​រក្សាទុក​រូបថតអេក្រង់​បានទេ ​ដោយសារ​ទំហំផ្ទុក​មានកម្រិតទាប"</string>
<string name="screenshot_failed_to_capture_text" msgid="173674476457581486">"ការថត​រូបអេក្រង់​មិនត្រូវ​បាន​អនុញ្ញាត​ដោយ​កម្មវិធី​នេះ ឬ​ស្ថាប័ន​របស់អ្នក"</string>
<string name="usb_preference_title" msgid="6551050377388882787">"ជម្រើស​ផ្ទេរ​ឯកសារ​តាម​យូអេសប៊ី"</string>
<string name="use_mtp_button_title" msgid="4333504413563023626">"ភ្ជាប់​ជា​កម្មវិធី​ចាក់​មេឌៀ (MTP)"</string>
@@ -557,26 +561,19 @@
<string name="tuner_full_importance_settings_off" msgid="8208165412614935229">"បិទ"</string>
<string name="power_notification_controls_description" msgid="4372459941671353358">"ជាមួយអង្គគ្រប់គ្រងការជូនដំណឹងថាមពល អ្នកអាចកំណត់កម្រិតសំខាន់ពី 0 ទៅ 5 សម្រាប់ការជូនដំណឹងរបស់កម្មវិធី។ \n\n"<b>"កម្រិត 5"</b>" \n- បង្ហាញនៅផ្នែកខាងលើបញ្ជីជូនដំណឹង \n- អនុញ្ញាតការរំខានលើអេក្រង់ពេញ \n- លោតឡើងជានិច្ច \n\n"<b>"កម្រិត 4"</b>" \n- រារាំងការរំខានលើអេក្រង់ពេញ \n- លោតឡើងជានិច្ច \n\n"<b>"កម្រិត 3"</b>" \n- រារាំងការរំខានលើអេក្រង់ពេញ \n- លោតឡើងជានិច្ច \n\n"<b>"កម្រិត 2"</b>" \n- រារាំងការរំខានលើអេក្រង់ពេញ \n- លោតឡើងជានិច្ច \n- មិនបន្លឺសំឡេង ឬញ័រ \n\n"<b>"កម្រិត 1"</b>" \n- រារាំងការរំខានលើអេក្រង់ពេញ \n- លោតឡើងជានិច្ច \n- មិនបន្លឺសំឡេង ឬញ័រ \n- លាក់ពីអេក្រង់ចាក់សោ និងរបារស្ថានភាព \n- បង្ហាញនៅផ្នែកខាងក្រោមបញ្ជីជូនដំណឹង \n\n"<b>"កម្រិត 0"</b>" \n- រារាំងការជូនដំណឹងទាំងអស់ពីកម្មវិធី"</string>
<string name="notification_header_default_channel" msgid="7506845022070889909">"ការ​ជូនដំណឹង"</string>
- <string name="notification_channel_disabled" msgid="2139193533791840539">"អ្នក​នឹង​មិន​ទទួល​បានការ​ជូនដំណឹង​ទាំងនេះ​ទៀត​ទេ"</string>
- <string name="notification_num_channels" msgid="2048144408999179471">"ប្រភេទនៃការជូនដំណឹងចំនួន <xliff:g id="NUMBER">%d</xliff:g>"</string>
- <string name="notification_default_channel_desc" msgid="2506053815870808359">"កម្មវិធីនេះ​មិនមាន​ប្រភេទនៃ​ការជូនដំណឹង​ទេ"</string>
- <string name="notification_unblockable_desc" msgid="3561016061737896906">"ការជូនដំណឹងពី​កម្មវិធីនេះមិនអាចបិទបានទេ"</string>
- <plurals name="notification_num_channels_desc" formatted="false" msgid="5492793452274077663">
- <item quantity="other">ប្រភេទនៃការ​ជូនដំណឹង 1 ក្នុង​ចំណោម <xliff:g id="NUMBER_1">%s</xliff:g> ដែលបានពី​កម្មវិធី​នេះ</item>
- <item quantity="one">ប្រភេទនៃការ​ជូនដំណឹង 1 ក្នុង​ចំណោម <xliff:g id="NUMBER_0">%s</xliff:g> ដែលបានពី​កម្មវិធី​នេះ</item>
- </plurals>
- <string name="notification_channels_list_desc_2" msgid="6214732715833946441">"<xliff:g id="CHANNEL_NAME_1">%1$s</xliff:g>, <xliff:g id="CHANNEL_NAME_2">%2$s</xliff:g>"</string>
- <plurals name="notification_channels_list_desc_2_and_others" formatted="false" msgid="2747813553355336157">
- <item quantity="other"><xliff:g id="CHANNEL_NAME_1_3">%1$s</xliff:g>, <xliff:g id="CHANNEL_NAME_2_4">%2$s</xliff:g>, និង <xliff:g id="NUMBER_5">%3$d</xliff:g> ផ្សេងទៀត</item>
- <item quantity="one"><xliff:g id="CHANNEL_NAME_1_0">%1$s</xliff:g>, <xliff:g id="CHANNEL_NAME_2_1">%2$s</xliff:g>, និង <xliff:g id="NUMBER_2">%3$d</xliff:g> ផ្សេងទៀត</item>
- </plurals>
+ <string name="notification_channel_disabled" msgid="344536703863700565">"អ្នក​នឹង​មិនឃើញ​ការជូនដំណឹង​ទាំងនេះ​ទៀតទេ"</string>
+ <string name="inline_keep_showing" msgid="8945102997083836858">"បន្ត​បង្ហាញ​ការជូនដំណឹង​ទាំងនេះ?"</string>
+ <string name="inline_stop_button" msgid="4172980096860941033">"បញ្ឈប់​ការជូនដំណឹង"</string>
+ <string name="inline_keep_button" msgid="6665940297019018232">"បន្ត​បង្ហាញ"</string>
+ <string name="inline_keep_showing_app" msgid="1723113469580031041">"បន្ត​បង្ហាញ​ការជូនដំណឹង​សម្រាប់​កម្មវិធីនេះ?"</string>
+ <string name="notification_unblockable_desc" msgid="1037434112919403708">"​មិនអាច​បិទការជូនដំណឹង​ទាំងនេះបានទេ"</string>
<string name="notification_channel_controls_opened_accessibility" msgid="6553950422055908113">"ការគ្រប់គ្រងការជូនដំណឹងសម្រាប់ <xliff:g id="APP_NAME">%1$s</xliff:g> បានបើក"</string>
<string name="notification_channel_controls_closed_accessibility" msgid="7521619812603693144">"ការគ្រប់គ្រងការជូនដំណឹងសម្រាប់ <xliff:g id="APP_NAME">%1$s</xliff:g> បានបិទ"</string>
<string name="notification_channel_switch_accessibility" msgid="3420796005601900717">"អនុញ្ញាតឲ្យមានការជូនដំណឹងពីប៉ុស្តិ៍នេះ"</string>
- <string name="notification_all_categories" msgid="5407190218055113282">"ប្រភេទ​ទាំងអស់"</string>
<string name="notification_more_settings" msgid="816306283396553571">"ការកំណត់ច្រើនទៀត"</string>
- <string name="notification_app_settings" msgid="3743278649182392015">"ប្ដូរ​តាម​បំណង៖ <xliff:g id="SUB_CATEGORY">%1$s</xliff:g>"</string>
+ <string name="notification_app_settings" msgid="420348114670768449">"ប្ដូរតាមបំណង"</string>
<string name="notification_done" msgid="5279426047273930175">"រួចរាល់"</string>
+ <string name="inline_undo" msgid="558916737624706010">"ត្រឡប់វិញ"</string>
<string name="notification_menu_accessibility" msgid="2046162834248888553">"<xliff:g id="APP_NAME">%1$s</xliff:g> <xliff:g id="MENU_DESCRIPTION">%2$s</xliff:g>"</string>
<string name="notification_menu_gear_description" msgid="2204480013726775108">"ការគ្រប់គ្រង​ការជូន​ដំណឹង"</string>
<string name="notification_menu_snooze_description" msgid="3653669438131034525">"ជម្រើស​ផ្អាកការ​ជូនដំណឹង"</string>
@@ -731,8 +728,7 @@
<string name="pip_phone_expand" msgid="5889780005575693909">"ពង្រីក"</string>
<string name="pip_phone_minimize" msgid="1079119422589131792">"បង្រួម"</string>
<string name="pip_phone_close" msgid="8416647892889710330">"បិទ"</string>
- <!-- no translation found for pip_phone_settings (8080777499521528521) -->
- <skip />
+ <string name="pip_phone_settings" msgid="8080777499521528521">"ការកំណត់"</string>
<string name="pip_phone_dismiss_hint" msgid="6351678169095923899">"អូស​ចុះក្រោម​ដើម្បី​បដិសេធ"</string>
<string name="pip_menu_title" msgid="4707292089961887657">"ម៉ឺនុយ"</string>
<string name="pip_notification_title" msgid="3204024940158161322">"<xliff:g id="NAME">%s</xliff:g> ស្ថិតក្នុងមុខងាររូបក្នុងរូប"</string>
diff --git a/packages/SystemUI/res/values-ko/strings.xml b/packages/SystemUI/res/values-ko/strings.xml
index 7fa87ed56d48..285c56970ebe 100644
--- a/packages/SystemUI/res/values-ko/strings.xml
+++ b/packages/SystemUI/res/values-ko/strings.xml
@@ -33,7 +33,10 @@
<string name="status_bar_ongoing_events_title" msgid="1682504513316879202">"진행 중"</string>
<string name="status_bar_latest_events_title" msgid="6594767438577593172">"알림"</string>
<string name="battery_low_title" msgid="6456385927409742437">"배터리 부족"</string>
+ <string name="battery_low_title_hybrid" msgid="6268991275887381595">"배터리가 부족합니다. 배터리 세이버를 사용 설정하세요"</string>
<string name="battery_low_percent_format" msgid="2900940511201380775">"<xliff:g id="PERCENTAGE">%s</xliff:g> 남았습니다."</string>
+ <string name="battery_low_percent_format_hybrid" msgid="6838677459286775617">"<xliff:g id="PERCENTAGE">%s</xliff:g> 남음, 내 사용량을 기준으로 약 <xliff:g id="TIME">%s</xliff:g> 남음"</string>
+ <string name="battery_low_percent_format_hybrid_short" msgid="9025795469949145586">"<xliff:g id="PERCENTAGE">%s</xliff:g> 남음, 약 <xliff:g id="TIME">%s</xliff:g> 남음"</string>
<string name="battery_low_percent_format_saver_started" msgid="7879389868952879166">"<xliff:g id="PERCENTAGE">%s</xliff:g> 남았습니다. 배터리 세이버를 사용 중입니다."</string>
<string name="invalid_charger" msgid="4549105996740522523">"USB 충전이 지원되지 않습니다.\n제공된 충전기만 사용하세요."</string>
<string name="invalid_charger_title" msgid="3515740382572798460">"USB 충전은 지원되지 않습니다."</string>
@@ -67,14 +70,15 @@
<string name="usb_debugging_secondary_user_message" msgid="6067122453571699801">"현재 이 기기에 로그인한 사용자는 USB 디버깅을 사용 설정할 수 없습니다. 이 기능을 사용하려면 기본 사용자로 전환하세요."</string>
<string name="compat_mode_on" msgid="6623839244840638213">"전체화면 모드로 확대"</string>
<string name="compat_mode_off" msgid="4434467572461327898">"전체화면 모드로 확대"</string>
+ <string name="global_action_screenshot" msgid="8329831278085426283">"스크린샷"</string>
<string name="screenshot_saving_ticker" msgid="7403652894056693515">"캡쳐화면 저장 중..."</string>
<string name="screenshot_saving_title" msgid="8242282144535555697">"캡쳐화면 저장 중..."</string>
- <string name="screenshot_saving_text" msgid="2419718443411738818">"캡쳐화면을 저장하는 중입니다."</string>
- <string name="screenshot_saved_title" msgid="6461865960961414961">"캡쳐화면 저장됨"</string>
- <string name="screenshot_saved_text" msgid="2685605830386712477">"스크린샷을 확인하려면 탭하세요."</string>
- <string name="screenshot_failed_title" msgid="705781116746922771">"캡쳐화면을 캡쳐하지 못했습니다."</string>
- <string name="screenshot_failed_to_save_unknown_text" msgid="7887826345701753830">"스크린샷을 저장하는 중 문제가 발생했습니다."</string>
- <string name="screenshot_failed_to_save_text" msgid="2592658083866306296">"저장용량이 부족하여 스크린샷을 저장할 수 없습니다."</string>
+ <string name="screenshot_saving_text" msgid="2545047868936087248">"스크린샷을 저장하는 중입니다"</string>
+ <string name="screenshot_saved_title" msgid="5637073968117370753">"스크린샷 저장됨"</string>
+ <string name="screenshot_saved_text" msgid="7574667448002050363">"스크린샷을 확인하려면 탭하세요"</string>
+ <string name="screenshot_failed_title" msgid="9096484883063264803">"스크린샷을 캡쳐하지 못함"</string>
+ <string name="screenshot_failed_to_save_unknown_text" msgid="8844781948876286488">"스크린샷을 저장하는 중 문제가 발생했습니다"</string>
+ <string name="screenshot_failed_to_save_text" msgid="3041612585107107310">"저장용량이 부족하여 스크린샷을 저장할 수 없습니다"</string>
<string name="screenshot_failed_to_capture_text" msgid="173674476457581486">"앱이나 조직에서 스크린샷 촬영을 허용하지 않습니다."</string>
<string name="usb_preference_title" msgid="6551050377388882787">"USB 파일 전송 옵션"</string>
<string name="use_mtp_button_title" msgid="4333504413563023626">"미디어 플레이어로 마운트(MTP)"</string>
@@ -559,26 +563,19 @@
<string name="tuner_full_importance_settings_off" msgid="8208165412614935229">"사용 안함"</string>
<string name="power_notification_controls_description" msgid="4372459941671353358">"전원 알림 컨트롤을 사용하면 앱 알림 관련 중요도를 0부터 5까지로 설정할 수 있습니다. \n\n"<b>"레벨 5"</b>" \n- 알림 목록 상단에 표시 \n- 전체 화면일 경우 알림 표시 허용 \n- 항상 엿보기 표시 \n\n"<b>"레벨 4"</b>" \n- 전체 화면에 알림 표시 금지 \n- 항상 엿보기 표시 \n\n"<b>"레벨 3"</b>" \n- 전체 화면에 알림 표시 금지 \n- 엿보기 표시 안함 \n\n"<b>"레벨 2"</b>" \n- 전체 화면에 알림 표시 금지 \n- 엿보기 표시 안함 \n- 소리나 진동으로 알리지 않음 \n\n"<b>"레벨 1"</b>" \n- 전체 화면에 알림 표시 금지 \n- 엿보기 표시 안함 \n- 소리나 진동으로 알리지 않음 \n- 잠금 화면 및 상태 표시줄에서 숨김 \n- 알림 목록 하단에 표시 \n\n"<b>"레벨 0"</b>" \n- 앱의 모든 알림 차단"</string>
<string name="notification_header_default_channel" msgid="7506845022070889909">"알림"</string>
- <string name="notification_channel_disabled" msgid="2139193533791840539">"더 이상 다음의 알림을 받지 않습니다."</string>
- <string name="notification_num_channels" msgid="2048144408999179471">"알림 카테고리 <xliff:g id="NUMBER">%d</xliff:g>개"</string>
- <string name="notification_default_channel_desc" msgid="2506053815870808359">"이 앱에는 알림 카테고리가 없습니다."</string>
- <string name="notification_unblockable_desc" msgid="3561016061737896906">"이 앱의 알림을 사용 중지할 수 없습니다."</string>
- <plurals name="notification_num_channels_desc" formatted="false" msgid="5492793452274077663">
- <item quantity="other">이 앱에서 <xliff:g id="NUMBER_1">%s</xliff:g>개의 알림 카테고리 중 1개가 정의됨</item>
- <item quantity="one">이 앱에서 <xliff:g id="NUMBER_0">%s</xliff:g>개의 알림 카테고리 중 1개가 정의됨</item>
- </plurals>
- <string name="notification_channels_list_desc_2" msgid="6214732715833946441">"<xliff:g id="CHANNEL_NAME_1">%1$s</xliff:g>, <xliff:g id="CHANNEL_NAME_2">%2$s</xliff:g>"</string>
- <plurals name="notification_channels_list_desc_2_and_others" formatted="false" msgid="2747813553355336157">
- <item quantity="other"><xliff:g id="CHANNEL_NAME_1_3">%1$s</xliff:g>, <xliff:g id="CHANNEL_NAME_2_4">%2$s</xliff:g> 외 <xliff:g id="NUMBER_5">%3$d</xliff:g>개</item>
- <item quantity="one"><xliff:g id="CHANNEL_NAME_1_0">%1$s</xliff:g>, <xliff:g id="CHANNEL_NAME_2_1">%2$s</xliff:g> 외 <xliff:g id="NUMBER_2">%3$d</xliff:g>개</item>
- </plurals>
+ <string name="notification_channel_disabled" msgid="344536703863700565">"더 이상 다음의 알림을 받지 않습니다"</string>
+ <string name="inline_keep_showing" msgid="8945102997083836858">"이 알림을 계속 표시하시겠습니까?"</string>
+ <string name="inline_stop_button" msgid="4172980096860941033">"알림 중지"</string>
+ <string name="inline_keep_button" msgid="6665940297019018232">"계속 표시하기"</string>
+ <string name="inline_keep_showing_app" msgid="1723113469580031041">"이 앱의 알림을 계속 표시하시겠습니까?"</string>
+ <string name="notification_unblockable_desc" msgid="1037434112919403708">"이 알림은 끌 수 없습니다"</string>
<string name="notification_channel_controls_opened_accessibility" msgid="6553950422055908113">"<xliff:g id="APP_NAME">%1$s</xliff:g> 알림 컨트롤을 열었습니다."</string>
<string name="notification_channel_controls_closed_accessibility" msgid="7521619812603693144">"<xliff:g id="APP_NAME">%1$s</xliff:g> 알림 컨트롤을 닫았습니다."</string>
<string name="notification_channel_switch_accessibility" msgid="3420796005601900717">"이 채널의 알림을 허용합니다."</string>
- <string name="notification_all_categories" msgid="5407190218055113282">"전체 카테고리"</string>
<string name="notification_more_settings" msgid="816306283396553571">"설정 더보기"</string>
- <string name="notification_app_settings" msgid="3743278649182392015">"맞춤설정: <xliff:g id="SUB_CATEGORY">%1$s</xliff:g>"</string>
+ <string name="notification_app_settings" msgid="420348114670768449">"맞춤설정"</string>
<string name="notification_done" msgid="5279426047273930175">"완료"</string>
+ <string name="inline_undo" msgid="558916737624706010">"실행취소"</string>
<string name="notification_menu_accessibility" msgid="2046162834248888553">"<xliff:g id="APP_NAME">%1$s</xliff:g> <xliff:g id="MENU_DESCRIPTION">%2$s</xliff:g>"</string>
<string name="notification_menu_gear_description" msgid="2204480013726775108">"알림 관리"</string>
<string name="notification_menu_snooze_description" msgid="3653669438131034525">"알림 일시 중지 옵션"</string>
@@ -733,8 +730,7 @@
<string name="pip_phone_expand" msgid="5889780005575693909">"펼치기"</string>
<string name="pip_phone_minimize" msgid="1079119422589131792">"최소화"</string>
<string name="pip_phone_close" msgid="8416647892889710330">"닫기"</string>
- <!-- no translation found for pip_phone_settings (8080777499521528521) -->
- <skip />
+ <string name="pip_phone_settings" msgid="8080777499521528521">"설정"</string>
<string name="pip_phone_dismiss_hint" msgid="6351678169095923899">"아래로 드래그하여 닫기"</string>
<string name="pip_menu_title" msgid="4707292089961887657">"메뉴"</string>
<string name="pip_notification_title" msgid="3204024940158161322">"<xliff:g id="NAME">%s</xliff:g>에서 PIP 사용 중"</string>
diff --git a/packages/SystemUI/res/values-ky/strings.xml b/packages/SystemUI/res/values-ky/strings.xml
index e3f1fa3eaa82..0687c2d30c97 100644
--- a/packages/SystemUI/res/values-ky/strings.xml
+++ b/packages/SystemUI/res/values-ky/strings.xml
@@ -33,7 +33,10 @@
<string name="status_bar_ongoing_events_title" msgid="1682504513316879202">"Учурдагы"</string>
<string name="status_bar_latest_events_title" msgid="6594767438577593172">"Эскертмелер"</string>
<string name="battery_low_title" msgid="6456385927409742437">"Батареянын кубаты аз"</string>
+ <string name="battery_low_title_hybrid" msgid="6268991275887381595">"Батарея аз калды. Батареяны үнөмдөгүчтү күйгүзүңүз"</string>
<string name="battery_low_percent_format" msgid="2900940511201380775">"<xliff:g id="PERCENTAGE">%s</xliff:g> калды"</string>
+ <string name="battery_low_percent_format_hybrid" msgid="6838677459286775617">"<xliff:g id="PERCENTAGE">%s</xliff:g> калды, колдонушуңузга караганда болжол менен дагы <xliff:g id="TIME">%s</xliff:g> бар"</string>
+ <string name="battery_low_percent_format_hybrid_short" msgid="9025795469949145586">"<xliff:g id="PERCENTAGE">%s</xliff:g> калды, болжол менен дагы <xliff:g id="TIME">%s</xliff:g> бар"</string>
<string name="battery_low_percent_format_saver_started" msgid="7879389868952879166">"<xliff:g id="PERCENTAGE">%s</xliff:g> калды. Батареяны үнөмдөгүч режими күйүк."</string>
<string name="invalid_charger" msgid="4549105996740522523">"USB менен кубаттоо колдоого алынбайт.\nБерилген заряддагычты гана колдонуңуз."</string>
<string name="invalid_charger_title" msgid="3515740382572798460">"USB аркылуу кубаттоого болбойт."</string>
@@ -67,14 +70,15 @@
<string name="usb_debugging_secondary_user_message" msgid="6067122453571699801">"Учурда бул түзмөккө каттоо эсеби менен кирген колдонуучу USB мүчүлүштүктөрүн оңдоо функциясын күйгүзө албай жатат. Бул функцияны колдонуу үчүн негизги колдонуучунун каттоо эсебине которулуңуз."</string>
<string name="compat_mode_on" msgid="6623839244840638213">"Экрнд тлтр ү. чен өлч өзг"</string>
<string name="compat_mode_off" msgid="4434467572461327898">"Экранды толтуруу ү-н чоюу"</string>
+ <string name="global_action_screenshot" msgid="8329831278085426283">"Скриншот"</string>
<string name="screenshot_saving_ticker" msgid="7403652894056693515">"Скриншот сакталууда…"</string>
<string name="screenshot_saving_title" msgid="8242282144535555697">"Скриншот сакталууда..."</string>
- <string name="screenshot_saving_text" msgid="2419718443411738818">"Скриншот сакталууда."</string>
- <string name="screenshot_saved_title" msgid="6461865960961414961">"Скриншот тартылды."</string>
- <string name="screenshot_saved_text" msgid="2685605830386712477">"Скриншотуңузду көрүү үчүн таптап коюңуз."</string>
- <string name="screenshot_failed_title" msgid="705781116746922771">"Скриншот кылынбай жатат."</string>
- <string name="screenshot_failed_to_save_unknown_text" msgid="7887826345701753830">"Скриншотту сактоо учурунда көйгөй пайда болду."</string>
- <string name="screenshot_failed_to_save_text" msgid="2592658083866306296">"Сактагычта бош орун аз болгондуктан скриншот сакталбай жатат."</string>
+ <string name="screenshot_saving_text" msgid="2545047868936087248">"Скриншот сакталууда"</string>
+ <string name="screenshot_saved_title" msgid="5637073968117370753">"Скриншот сакталды"</string>
+ <string name="screenshot_saved_text" msgid="7574667448002050363">"Скриншотуңузду көрүү үчүн таптап коюңуз"</string>
+ <string name="screenshot_failed_title" msgid="9096484883063264803">"Скриншот тартылбай жатат"</string>
+ <string name="screenshot_failed_to_save_unknown_text" msgid="8844781948876286488">"Скриншотту сактоо учурунда көйгөй пайда болду"</string>
+ <string name="screenshot_failed_to_save_text" msgid="3041612585107107310">"Сактагычта бош орун аз болгондуктан скриншот сакталбай жатат"</string>
<string name="screenshot_failed_to_capture_text" msgid="173674476457581486">"Скриншот тартууга колдонмо же ишканаңыз тыюу салган."</string>
<string name="usb_preference_title" msgid="6551050377388882787">"USB менен файл өткөрүү мүмкүнчүлүктөрү"</string>
<string name="use_mtp_button_title" msgid="4333504413563023626">"Медиа ойноткуч катары кошуу (MTP)"</string>
@@ -557,26 +561,19 @@
<string name="tuner_full_importance_settings_off" msgid="8208165412614935229">"Өчүк"</string>
<string name="power_notification_controls_description" msgid="4372459941671353358">"Бул функциянын жардамы менен ар бир колдонмо үчүн эскертменин маанилүүлүк деңгээлин 0дон 5ке чейин койсоңуз болот. \n\n"<b>"5-деңгээл"</b>" \n- Эскертмелер тизмесинин башында көрсөтүлсүн \n- Эскертмелер толук экранда көрсөтүлсүн \n- Калкып чыгуучу эскертмелерге уруксат берилсин \n\n"<b>"4-деңгээл"</b>" \n- Эскертмелер толук экранда көрсөтүлбөсүн \n- Калкып чыгуучу эскертмелерге уруксат берилсин \n\n"<b>"3-деңгээл"</b>" \n- Эскертмелер толук экранда көрсөтүлбөсүн \n- Калкып чыгуучу эскертмелерге тыюу салынсын \n\n"<b>"2-деңгээл"</b>" \n- Эскертмелер толук экранда көрсөтүлбөсүн \n- Калкып чыгуучу эскертмелерге тыюу салынсын \n- Эч качан добуш чыгып же дирилдебесин \n\n"<b>"1-деңгээл"</b>" \n- Эскертмелер толук экранда көрсөтүлбөсүн \n- Калкып чыгуучу эскертмелерге тыюу салынсын \n- Эч качан добуш чыгып же дирилдебесин \n- Кулпуланган экрандан жана абал тилкесинен жашырылсын \n- Эскертмелер тизмесинин аягында көрсөтүлсүн \n\n"<b>"0-деңгээл"</b>" \n- Колдонмодон алынган бардык эскертмелер бөгөттөлсүн"</string>
<string name="notification_header_default_channel" msgid="7506845022070889909">"Эскертмелер"</string>
- <string name="notification_channel_disabled" msgid="2139193533791840539">"Мындан ары бул эскертмелер сизге жөнөтүлбөйт"</string>
- <string name="notification_num_channels" msgid="2048144408999179471">"Эскертмелердин <xliff:g id="NUMBER">%d</xliff:g> категориясы"</string>
- <string name="notification_default_channel_desc" msgid="2506053815870808359">"Бул колдонмонун эскертме категориялары жок"</string>
- <string name="notification_unblockable_desc" msgid="3561016061737896906">"Бул колдонмонун эскертмелерин өчүрүүгө болбойт"</string>
- <plurals name="notification_num_channels_desc" formatted="false" msgid="5492793452274077663">
- <item quantity="other">Бул колдонмодогу <xliff:g id="NUMBER_1">%s</xliff:g> эскертме категориянын ичинен 1 категория</item>
- <item quantity="one">Бул колдонмодогу <xliff:g id="NUMBER_0">%s</xliff:g> эскертме категориянын ичинен 1 категория</item>
- </plurals>
- <string name="notification_channels_list_desc_2" msgid="6214732715833946441">"<xliff:g id="CHANNEL_NAME_1">%1$s</xliff:g>, <xliff:g id="CHANNEL_NAME_2">%2$s</xliff:g>"</string>
- <plurals name="notification_channels_list_desc_2_and_others" formatted="false" msgid="2747813553355336157">
- <item quantity="other"><xliff:g id="CHANNEL_NAME_1_3">%1$s</xliff:g>, <xliff:g id="CHANNEL_NAME_2_4">%2$s</xliff:g> жана дагы <xliff:g id="NUMBER_5">%3$d</xliff:g></item>
- <item quantity="one"><xliff:g id="CHANNEL_NAME_1_0">%1$s</xliff:g>, <xliff:g id="CHANNEL_NAME_2_1">%2$s</xliff:g> жана дагы <xliff:g id="NUMBER_2">%3$d</xliff:g></item>
- </plurals>
+ <string name="notification_channel_disabled" msgid="344536703863700565">"Мындан ары бул эскертмелер сизге көрсөтүлбөйт"</string>
+ <string name="inline_keep_showing" msgid="8945102997083836858">"Бул эскертмелер көрсөтүлө берсинби?"</string>
+ <string name="inline_stop_button" msgid="4172980096860941033">"Эскертмелерди токтотуу"</string>
+ <string name="inline_keep_button" msgid="6665940297019018232">"Көрсөтүлө берсин"</string>
+ <string name="inline_keep_showing_app" msgid="1723113469580031041">"Бул колдонмонун эскертмелери көрсөтүлө берсинби?"</string>
+ <string name="notification_unblockable_desc" msgid="1037434112919403708">"Бул эскертмелерди өчүрүүгө болбойт"</string>
<string name="notification_channel_controls_opened_accessibility" msgid="6553950422055908113">"<xliff:g id="APP_NAME">%1$s</xliff:g> колдонмосу үчүн эскертмени көзөмөлдөө функциялары ачылды"</string>
<string name="notification_channel_controls_closed_accessibility" msgid="7521619812603693144">"<xliff:g id="APP_NAME">%1$s</xliff:g> колдонмосу үчүн эскертмени көзөмөлдөө функциялары жабылды"</string>
<string name="notification_channel_switch_accessibility" msgid="3420796005601900717">"Бул каналдан келген эскертмелерге уруксат берүү"</string>
- <string name="notification_all_categories" msgid="5407190218055113282">"Бардык категориялар"</string>
<string name="notification_more_settings" msgid="816306283396553571">"Дагы жөндөөлөр"</string>
- <string name="notification_app_settings" msgid="3743278649182392015">"Ыңгайлаштыруу: <xliff:g id="SUB_CATEGORY">%1$s</xliff:g>"</string>
+ <string name="notification_app_settings" msgid="420348114670768449">"Ыңгайлаштыруу"</string>
<string name="notification_done" msgid="5279426047273930175">"Бүттү"</string>
+ <string name="inline_undo" msgid="558916737624706010">"Кайтаруу"</string>
<string name="notification_menu_accessibility" msgid="2046162834248888553">"<xliff:g id="APP_NAME">%1$s</xliff:g> <xliff:g id="MENU_DESCRIPTION">%2$s</xliff:g>"</string>
<string name="notification_menu_gear_description" msgid="2204480013726775108">"эскертмелерди башкаруу каражаттары"</string>
<string name="notification_menu_snooze_description" msgid="3653669438131034525">"эскертмени тындыруу опциялары"</string>
@@ -731,8 +728,7 @@
<string name="pip_phone_expand" msgid="5889780005575693909">"Жайып көрсөтүү"</string>
<string name="pip_phone_minimize" msgid="1079119422589131792">"Кичирейтүү"</string>
<string name="pip_phone_close" msgid="8416647892889710330">"Жабуу"</string>
- <!-- no translation found for pip_phone_settings (8080777499521528521) -->
- <skip />
+ <string name="pip_phone_settings" msgid="8080777499521528521">"Жөндөөлөр"</string>
<string name="pip_phone_dismiss_hint" msgid="6351678169095923899">"Четке кагуу үчүн төмөн сүйрөңүз"</string>
<string name="pip_menu_title" msgid="4707292089961887657">"Меню"</string>
<string name="pip_notification_title" msgid="3204024940158161322">"<xliff:g id="NAME">%s</xliff:g> – сүрөт ичиндеги сүрөт"</string>
diff --git a/packages/SystemUI/res/values-lo/strings.xml b/packages/SystemUI/res/values-lo/strings.xml
index fe262ee053a3..587686fa5046 100644
--- a/packages/SystemUI/res/values-lo/strings.xml
+++ b/packages/SystemUI/res/values-lo/strings.xml
@@ -33,7 +33,10 @@
<string name="status_bar_ongoing_events_title" msgid="1682504513316879202">"ດຳເນີນຢູ່"</string>
<string name="status_bar_latest_events_title" msgid="6594767438577593172">"ການແຈ້ງເຕືອນ"</string>
<string name="battery_low_title" msgid="6456385927409742437">"ແບັດເຕີຣີ​ເຫຼືອ​ໜ້ອຍ"</string>
+ <string name="battery_low_title_hybrid" msgid="6268991275887381595">"ແບັດເຕີຣີເຫຼືອໜ້ອຍ. ກະລຸນາເປີດໃຊ້ຕົວປະຢັດແບັດເຕີຣີ"</string>
<string name="battery_low_percent_format" msgid="2900940511201380775">"ຍັງ​ເຫຼືອ <xliff:g id="PERCENTAGE">%s</xliff:g>"</string>
+ <string name="battery_low_percent_format_hybrid" msgid="6838677459286775617">"ຍັງເຫຼືອ <xliff:g id="PERCENTAGE">%s</xliff:g>, ປະມານ <xliff:g id="TIME">%s</xliff:g> ໂດຍອ້າງອີງຈາກການນຳໃຊ້ຂອງທ່ານ"</string>
+ <string name="battery_low_percent_format_hybrid_short" msgid="9025795469949145586">"ຍັງເຫຼືອ <xliff:g id="PERCENTAGE">%s</xliff:g>, ປະມານ <xliff:g id="TIME">%s</xliff:g>"</string>
<string name="battery_low_percent_format_saver_started" msgid="7879389868952879166">"ຍັງເຫຼືອ <xliff:g id="PERCENTAGE">%s</xliff:g>. ເປີດໃຊ້ຕົວປະຢັດແບັດເຕີຣີແລ້ວ."</string>
<string name="invalid_charger" msgid="4549105996740522523">"ບໍ່ຮອງຮັບການສາກໄຟດ້ວຍ USB.\nຕ້ອງໃຊ້ສະເພາະເຄື່ອງສາກທີ່ແຖມມານຳເທົ່ານັ້ນ."</string>
<string name="invalid_charger_title" msgid="3515740382572798460">"ບໍ່​ຮອງຮັບ​ການ​ສາກ​ຜ່ານ USB."</string>
@@ -67,14 +70,15 @@
<string name="usb_debugging_secondary_user_message" msgid="6067122453571699801">"ຜູ້ໃຊ້ທີ່ກຳລັງເຂົ້າສູ່ລະບົບອຸປະກອນຢູ່ໃນຕອນນີ້ບໍ່ສາມາດເປີດໃຊ້ການດີບັກ USB ໄດ້. ເພື່ອໃຊ້ຄຸນສົມບັດນີ້, ໃຫ້ສະຫຼັບໄປໃຊ້ຜູ້ໃຊ້ຫຼັກ."</string>
<string name="compat_mode_on" msgid="6623839244840638213">"ຊູມໃຫ້ເຕັມໜ້າຈໍ"</string>
<string name="compat_mode_off" msgid="4434467572461327898">"ປັບໃຫ້ເຕັມໜ້າຈໍ"</string>
+ <string name="global_action_screenshot" msgid="8329831278085426283">"ພາບໜ້າຈໍ"</string>
<string name="screenshot_saving_ticker" msgid="7403652894056693515">"ກຳລັງບັນທຶກຮູບໜ້າຈໍ"</string>
<string name="screenshot_saving_title" msgid="8242282144535555697">"ກຳລັງບັນທຶກພາບໜ້າຈໍ..."</string>
- <string name="screenshot_saving_text" msgid="2419718443411738818">"ກຳລັງບັນທຶກພາບໜ້າຈໍ."</string>
- <string name="screenshot_saved_title" msgid="6461865960961414961">"ຖ່າຍຮູບໜ້າຈໍແລ້ວ"</string>
- <string name="screenshot_saved_text" msgid="2685605830386712477">"ແຕະເພື່ອເບິ່ງພາບຖ່າຍໜ້າຈໍຂອງທ່ານ."</string>
- <string name="screenshot_failed_title" msgid="705781116746922771">"ບໍ່ສາມາດຖ່າຍຮູບໜ້າຈໍໄດ້"</string>
- <string name="screenshot_failed_to_save_unknown_text" msgid="7887826345701753830">"ເກີດບັນຫາໃນການບັນທຶກພາບໜ້າຈໍຂອງທ່ານ."</string>
- <string name="screenshot_failed_to_save_text" msgid="2592658083866306296">"ບໍ່ສາມາດຖ່າຍຮູບໜ້າຈໍໄດ້ເນື່ອງຈາກພື້ນທີ່ຈັດເກັບຂໍ້ມູນມີຈຳກັດ."</string>
+ <string name="screenshot_saving_text" msgid="2545047868936087248">"ກຳລັງບັນທຶກພາບໜ້າຈໍ"</string>
+ <string name="screenshot_saved_title" msgid="5637073968117370753">"ບັນທຶກຮູບໜ້າຈໍໄວ້ແລ້ວ"</string>
+ <string name="screenshot_saved_text" msgid="7574667448002050363">"ແຕະເພື່ອເບິ່ງພາບຖ່າຍໜ້າຈໍຂອງທ່ານ"</string>
+ <string name="screenshot_failed_title" msgid="9096484883063264803">"ບໍ່ສາມາດຖ່າຍຮູບໜ້າຈໍໄດ້"</string>
+ <string name="screenshot_failed_to_save_unknown_text" msgid="8844781948876286488">"ເກີດບັນຫາໃນການບັນທຶກພາບໜ້າຈໍຂອງທ່ານ"</string>
+ <string name="screenshot_failed_to_save_text" msgid="3041612585107107310">"ບໍ່ສາມາດຖ່າຍຮູບໜ້າຈໍໄດ້ເນື່ອງຈາກພື້ນທີ່ຈັດເກັບຂໍ້ມູນມີຈຳກັດ"</string>
<string name="screenshot_failed_to_capture_text" msgid="173674476457581486">"ແອັບ ຫຼື ອົງກອນຂອງທ່ານບໍ່ອະນຸຍາດໃຫ້ຖ່າຍຮູບໜ້າຈໍ"</string>
<string name="usb_preference_title" msgid="6551050377388882787">"USB ໂຕເລືອກການຍ້າຍໄຟລ໌"</string>
<string name="use_mtp_button_title" msgid="4333504413563023626">"ເຊື່ອມຕໍ່ເປັນ media player (MTP)"</string>
@@ -557,26 +561,19 @@
<string name="tuner_full_importance_settings_off" msgid="8208165412614935229">"ປິດ"</string>
<string name="power_notification_controls_description" msgid="4372459941671353358">"ດ້ວຍການຄວບຄຸມການແຈ້ງເຕືອນ, ທ່ານສາມາດຕັ້ງລະດັບຄວາມສຳຄັນຈາກ 0 ຮອດ 5 ໃຫ້ກັບການແຈ້ງເຕືອນແອັບໃດໜຶ່ງໄດ້. \n\n"<b>"ລະດັບ 5"</b>" \n- ສະແດງຢູ່ເທິງສຸດຂອງລາຍການແຈ້ງເຕືອນ \n- ອະນຸຍາດໃຫ້ຂັດຈັງຫວະຕອນເປີດເຕັມຈໍ \n- ແນມເບິ່ງທຸກເທື່ອ \n\n"<b>"ລະດັບ 4"</b>" \n- ກັນບໍ່ໃຫ້ຂັດຈັງຫວະຕອນເປີດເຕັມຈໍ \n- ແນມເບິ່ງທຸກເທື່ອ \n\n"<b>"ລະດັບ 3"</b>" \n- ກັນບໍ່ໃຫ້ຂັດຈັງຫວະຕອນເປີດເຕັມຈໍ \n- ບໍ່ແນມເບິ່ງ \n\n"<b>"ລະດັບ 2"</b>" \n- ກັນບໍ່ໃຫ້ຂັດຈັງຫວະຕອນເປີດເຕັມຈໍ \n- ບໍ່ແນມເບິ່ງ \n- ບໍ່ມີສຽງ ແລະ ບໍ່ມີການສັ່ນເຕືອນ \n\n"<b>"ລະດັບ 1"</b>" \n- ກັນບໍ່ໃຫ້ຂັດຈັງຫວະຕອນເປີດເຕັມຈໍ \n- ບໍ່ແນມເບິ່ງ \n- ບໍ່ມີສຽງ ແລະ ບໍ່ມີການສັ່ນເຕືອນ \n- ເຊື່ອງຈາກໜ້າຈໍລັອກ ແລະ ແຖບສະຖານະ \n- ສະແດງຢູ່ລຸ່ມສຸດຂອງລາຍການແຈ້ງເຕືອນ \n\n"<b>"ລະດັບ 0"</b>" \n- ປິດກັ້ນການແຈ້ງເຕືອນທັງໝົດຈາກແອັບ"</string>
<string name="notification_header_default_channel" msgid="7506845022070889909">"ການແຈ້ງເຕືອນ"</string>
- <string name="notification_channel_disabled" msgid="2139193533791840539">"ທ່ານຈະບໍ່ໄດ້ຮັບການແຈ້ງເຕືອນເຫຼົ່ານີ້ອີກຕໍ່ໄປ"</string>
- <string name="notification_num_channels" msgid="2048144408999179471">"<xliff:g id="NUMBER">%d</xliff:g> ໝວດໝູ່ການແຈ້ງເຕືອນ"</string>
- <string name="notification_default_channel_desc" msgid="2506053815870808359">"ແອັບນີ້ບໍ່ມີໝວດໝູ່ການແຈ້ງເຕືອນ"</string>
- <string name="notification_unblockable_desc" msgid="3561016061737896906">"ການແຈ້ງເຕືອນຈາກແອັບນີ້ບໍ່ສາມາດປິດໄວ້ໄດ້"</string>
- <plurals name="notification_num_channels_desc" formatted="false" msgid="5492793452274077663">
- <item quantity="other">1 ຈາກທັງໝົດ <xliff:g id="NUMBER_1">%s</xliff:g> ໝວດໝູ່ການແຈ້ງເຕືອນຈາກແອັບນີ້</item>
- <item quantity="one">1 ຈາກທັງໝົດ <xliff:g id="NUMBER_0">%s</xliff:g> ໝວດໝູ່ການແຈ້ງເຕືອນຈາກແອັບນີ້</item>
- </plurals>
- <string name="notification_channels_list_desc_2" msgid="6214732715833946441">"<xliff:g id="CHANNEL_NAME_1">%1$s</xliff:g>, <xliff:g id="CHANNEL_NAME_2">%2$s</xliff:g>"</string>
- <plurals name="notification_channels_list_desc_2_and_others" formatted="false" msgid="2747813553355336157">
- <item quantity="other"><xliff:g id="CHANNEL_NAME_1_3">%1$s</xliff:g>, <xliff:g id="CHANNEL_NAME_2_4">%2$s</xliff:g> ແລະ ອີກ <xliff:g id="NUMBER_5">%3$d</xliff:g> ຊ່ອງອື່ນໆ</item>
- <item quantity="one"><xliff:g id="CHANNEL_NAME_1_0">%1$s</xliff:g>, <xliff:g id="CHANNEL_NAME_2_1">%2$s</xliff:g> ແລະ ອີກ <xliff:g id="NUMBER_2">%3$d</xliff:g> ຊ່ອງອື່ນໆ</item>
- </plurals>
+ <string name="notification_channel_disabled" msgid="344536703863700565">"ທ່ານຈະບໍ່ໄດ້ຮັບການແຈ້ງເຕືອນເຫຼົ່ານີ້ອີກຕໍ່ໄປ"</string>
+ <string name="inline_keep_showing" msgid="8945102997083836858">"ສະແດງການແຈ້ງເຕືອນເຫຼົ່ານີ້ຕໍ່ໄປບໍ?"</string>
+ <string name="inline_stop_button" msgid="4172980096860941033">"ຢຸດການແຈ້ງເຕືອນ"</string>
+ <string name="inline_keep_button" msgid="6665940297019018232">"ສະແດງຕໍ່ໄປ"</string>
+ <string name="inline_keep_showing_app" msgid="1723113469580031041">"ສະແດງການແຈ້ງເຕືອນຈາກແອັບນີ້ຕໍ່ໄປບໍ?"</string>
+ <string name="notification_unblockable_desc" msgid="1037434112919403708">"ບໍ່ສາມາດປິດການແຈ້ງເຕືອນເຫຼົ່ານີ້ໄດ້"</string>
<string name="notification_channel_controls_opened_accessibility" msgid="6553950422055908113">"ເປີດຕົວຄວບຄຸມການແຈ້ງເຕືອນສຳລັບ <xliff:g id="APP_NAME">%1$s</xliff:g> ແລ້ວ"</string>
<string name="notification_channel_controls_closed_accessibility" msgid="7521619812603693144">"ປິດຕົວຄວບຄຸມການແຈ້ງເຕືອນສຳລັບ <xliff:g id="APP_NAME">%1$s</xliff:g> ແລ້ວ"</string>
<string name="notification_channel_switch_accessibility" msgid="3420796005601900717">"ອະນຸຍາດການແຈ້ງເຕືອນຈາກຊ່ອງນີ້"</string>
- <string name="notification_all_categories" msgid="5407190218055113282">"ທຸກໝວດໝູ່"</string>
<string name="notification_more_settings" msgid="816306283396553571">"​ການ​ຕັ້ງ​ຄ່າ​ເພີ່ມ​ເຕີມ"</string>
- <string name="notification_app_settings" msgid="3743278649182392015">"ປັບແຕ່ງ: <xliff:g id="SUB_CATEGORY">%1$s</xliff:g>"</string>
+ <string name="notification_app_settings" msgid="420348114670768449">"ປັບແຕ່ງ"</string>
<string name="notification_done" msgid="5279426047273930175">"ສຳເລັດແລ້ວ"</string>
+ <string name="inline_undo" msgid="558916737624706010">"ຍົກເລີກ"</string>
<string name="notification_menu_accessibility" msgid="2046162834248888553">"<xliff:g id="APP_NAME">%1$s</xliff:g> <xliff:g id="MENU_DESCRIPTION">%2$s</xliff:g>"</string>
<string name="notification_menu_gear_description" msgid="2204480013726775108">"ການຄວບຄຸມການແຈ້ງເຕືອນ"</string>
<string name="notification_menu_snooze_description" msgid="3653669438131034525">"ຕົວເລືອກການເລື່ອນການແຈ້ງເຕືອນ"</string>
@@ -731,8 +728,7 @@
<string name="pip_phone_expand" msgid="5889780005575693909">"ຂະຫຍາຍ"</string>
<string name="pip_phone_minimize" msgid="1079119422589131792">"ຫຍໍ້"</string>
<string name="pip_phone_close" msgid="8416647892889710330">"ປິດ"</string>
- <!-- no translation found for pip_phone_settings (8080777499521528521) -->
- <skip />
+ <string name="pip_phone_settings" msgid="8080777499521528521">"ການຕັ້ງຄ່າ"</string>
<string name="pip_phone_dismiss_hint" msgid="6351678169095923899">"ລາກລົງເພື່ອປິດໄວ້"</string>
<string name="pip_menu_title" msgid="4707292089961887657">"ເມນູ"</string>
<string name="pip_notification_title" msgid="3204024940158161322">"<xliff:g id="NAME">%s</xliff:g> ແມ່ນເປັນການສະແດງຜົນຫຼາຍຢ່າງພ້ອມກັນ"</string>
diff --git a/packages/SystemUI/res/values-lv/strings.xml b/packages/SystemUI/res/values-lv/strings.xml
index 574d898e311c..a02a20bcda5b 100644
--- a/packages/SystemUI/res/values-lv/strings.xml
+++ b/packages/SystemUI/res/values-lv/strings.xml
@@ -34,7 +34,10 @@
<string name="status_bar_ongoing_events_title" msgid="1682504513316879202">"Notiekošs"</string>
<string name="status_bar_latest_events_title" msgid="6594767438577593172">"Paziņojumi"</string>
<string name="battery_low_title" msgid="6456385927409742437">"Zems akumulatora enerģijas līmenis"</string>
+ <string name="battery_low_title_hybrid" msgid="6268991275887381595">"Akumulatora uzlādes līmenis ir zems. Ieslēdziet akumulatora jaudas taupīšanas režīmu."</string>
<string name="battery_low_percent_format" msgid="2900940511201380775">"Atlikuši <xliff:g id="PERCENTAGE">%s</xliff:g>"</string>
+ <string name="battery_low_percent_format_hybrid" msgid="6838677459286775617">"Atlikušais laiks: <xliff:g id="PERCENTAGE">%s</xliff:g> — aptuveni <xliff:g id="TIME">%s</xliff:g> (ņemot vērā lietojumu)"</string>
+ <string name="battery_low_percent_format_hybrid_short" msgid="9025795469949145586">"Atlikušais laiks: <xliff:g id="PERCENTAGE">%s</xliff:g> — aptuveni <xliff:g id="TIME">%s</xliff:g>"</string>
<string name="battery_low_percent_format_saver_started" msgid="7879389868952879166">"Atlikuši <xliff:g id="PERCENTAGE">%s</xliff:g>. Ir ieslēgts akumulatora jaudas taupīšanas režīms."</string>
<string name="invalid_charger" msgid="4549105996740522523">"USB lādēšana netiek atbalstīta.\nIzmantojiet tikai komplektā iekļauto lādētāju."</string>
<string name="invalid_charger_title" msgid="3515740382572798460">"USB uzlāde netiek atbalstīta."</string>
@@ -68,14 +71,15 @@
<string name="usb_debugging_secondary_user_message" msgid="6067122453571699801">"Lietotājs, kurš pašlaik ir pierakstījies šajā ierīcē, nevar iespējot USB atkļūdošanu. Lai izmantotu šo funkciju, pārslēdzieties uz galveno lietotāju."</string>
<string name="compat_mode_on" msgid="6623839244840638213">"Tālumm., lai aizp. ekr."</string>
<string name="compat_mode_off" msgid="4434467572461327898">"Stiepiet, lai aizp. ekr."</string>
+ <string name="global_action_screenshot" msgid="8329831278085426283">"Ekrānuzņēmums"</string>
<string name="screenshot_saving_ticker" msgid="7403652894056693515">"Saglabā ekrānuzņēmumu…"</string>
<string name="screenshot_saving_title" msgid="8242282144535555697">"Notiek ekrānuzņēmuma saglabāšana..."</string>
- <string name="screenshot_saving_text" msgid="2419718443411738818">"Notiek ekrānuzņēmuma saglabāšana."</string>
- <string name="screenshot_saved_title" msgid="6461865960961414961">"Ekrānuzņēmums ir uzņemts."</string>
- <string name="screenshot_saved_text" msgid="2685605830386712477">"Pieskarieties, lai skatītu ekrānuzņēmumu."</string>
- <string name="screenshot_failed_title" msgid="705781116746922771">"Nevarēja uzņemt ekrānuzņēmumu."</string>
- <string name="screenshot_failed_to_save_unknown_text" msgid="7887826345701753830">"Saglabājot ekrānuzņēmumu, radās problēma."</string>
- <string name="screenshot_failed_to_save_text" msgid="2592658083866306296">"Nevar saglabāt ekrānuzņēmumu, jo krātuvē nepietiek vietas."</string>
+ <string name="screenshot_saving_text" msgid="2545047868936087248">"Notiek ekrānuzņēmuma saglabāšana."</string>
+ <string name="screenshot_saved_title" msgid="5637073968117370753">"Ekrānuzņēmums saglabāts"</string>
+ <string name="screenshot_saved_text" msgid="7574667448002050363">"Pieskarieties, lai skatītu ekrānuzņēmumu."</string>
+ <string name="screenshot_failed_title" msgid="9096484883063264803">"Nevarēja uzņemt ekrānuzņēmumu"</string>
+ <string name="screenshot_failed_to_save_unknown_text" msgid="8844781948876286488">"Saglabājot ekrānuzņēmumu, radās problēma."</string>
+ <string name="screenshot_failed_to_save_text" msgid="3041612585107107310">"Nevar saglabāt ekrānuzņēmumu, jo krātuvē nepietiek vietas."</string>
<string name="screenshot_failed_to_capture_text" msgid="173674476457581486">"Lietotne vai jūsu organizācija neatļauj veikt ekrānuzņēmumus."</string>
<string name="usb_preference_title" msgid="6551050377388882787">"USB failu pārsūtīšanas opcijas"</string>
<string name="use_mtp_button_title" msgid="4333504413563023626">"Pievienot kā multivides atskaņotāju (MTP)"</string>
@@ -559,28 +563,19 @@
<string name="tuner_full_importance_settings_off" msgid="8208165412614935229">"Izslēgts"</string>
<string name="power_notification_controls_description" msgid="4372459941671353358">"Izmantojot barošanas paziņojumu vadīklas, varat lietotnes paziņojumiem iestatīt svarīguma līmeni (no 0 līdz 5). \n\n"<b>"5. līmenis"</b>" \n- Tiek rādīts paziņojumu saraksta augšdaļā \n- Tiek atļauta pilnekrāna režīma pārtraukšana \n- Ieskats vienmēr atļauts \n\n"<b>"4. līmenis"</b>" \n- Tiek novērsta pilnekrāna režīma pārtraukšana \n- Ieskats vienmēr atļauts \n\n"<b>"3. līmenis"</b>" \n- Tiek novērsta pilnekrāna režīma pārtraukšana \n- Ieskats nav atļauts \n\n"<b>"2. līmenis"</b>" \n- Tiek novērsta pilnekrāna režīma pārtraukšana \n- Ieskats nav atļauts \n- Nav atļautas skaņas un vibrosignāls \n\n"<b>"1. līmenis"</b>" \n- Tiek novērsta pilnekrāna režīma pārtraukšana \n- Ieskats nav atļauts \n- Nav atļautas skaņas un vibrosignāls \n- Paziņojumi tiek paslēpti bloķēšanas ekrānā un statusa joslā \n- Paziņojumi tiek rādīti paziņojumu saraksta apakšdaļā \n\n"<b>"0. līmenis"</b>" \n- Visi lietotnes paziņojumi tiek bloķēti"</string>
<string name="notification_header_default_channel" msgid="7506845022070889909">"Paziņojumi"</string>
- <string name="notification_channel_disabled" msgid="2139193533791840539">"Jūs vairs nesaņemsiet šos paziņojumus"</string>
- <string name="notification_num_channels" msgid="2048144408999179471">"<xliff:g id="NUMBER">%d</xliff:g> paziņojumu kategorijas"</string>
- <string name="notification_default_channel_desc" msgid="2506053815870808359">"Paziņojumu kategorijas šajā lietotnē nav pieejamas."</string>
- <string name="notification_unblockable_desc" msgid="3561016061737896906">"Paziņojumus no šīs lietotnes nevar izslēgt"</string>
- <plurals name="notification_num_channels_desc" formatted="false" msgid="5492793452274077663">
- <item quantity="zero">1 no <xliff:g id="NUMBER_1">%s</xliff:g> šīs lietotnes paziņojumu kategorijām.</item>
- <item quantity="one">1 no <xliff:g id="NUMBER_1">%s</xliff:g> šīs lietotnes paziņojumu kategorijas.</item>
- <item quantity="other">1 no <xliff:g id="NUMBER_1">%s</xliff:g> šīs lietotnes paziņojumu kategorijām.</item>
- </plurals>
- <string name="notification_channels_list_desc_2" msgid="6214732715833946441">"<xliff:g id="CHANNEL_NAME_1">%1$s</xliff:g>, <xliff:g id="CHANNEL_NAME_2">%2$s</xliff:g>"</string>
- <plurals name="notification_channels_list_desc_2_and_others" formatted="false" msgid="2747813553355336157">
- <item quantity="zero"><xliff:g id="CHANNEL_NAME_1_3">%1$s</xliff:g>, <xliff:g id="CHANNEL_NAME_2_4">%2$s</xliff:g> un vēl <xliff:g id="NUMBER_5">%3$d</xliff:g></item>
- <item quantity="one"><xliff:g id="CHANNEL_NAME_1_3">%1$s</xliff:g>, <xliff:g id="CHANNEL_NAME_2_4">%2$s</xliff:g> un vēl <xliff:g id="NUMBER_5">%3$d</xliff:g></item>
- <item quantity="other"><xliff:g id="CHANNEL_NAME_1_3">%1$s</xliff:g>, <xliff:g id="CHANNEL_NAME_2_4">%2$s</xliff:g> un vēl <xliff:g id="NUMBER_5">%3$d</xliff:g></item>
- </plurals>
+ <string name="notification_channel_disabled" msgid="344536703863700565">"Jūs vairs neredzēsiet šos paziņojumus."</string>
+ <string name="inline_keep_showing" msgid="8945102997083836858">"Vai turpināt rādīt šos paziņojumus?"</string>
+ <string name="inline_stop_button" msgid="4172980096860941033">"Apturēt paziņojumu rādīšanu"</string>
+ <string name="inline_keep_button" msgid="6665940297019018232">"Turpināt rādīt"</string>
+ <string name="inline_keep_showing_app" msgid="1723113469580031041">"Vai turpināt rādīt paziņojumus no šīs lietotnes?"</string>
+ <string name="notification_unblockable_desc" msgid="1037434112919403708">"Šos paziņojumus nevar izslēgt."</string>
<string name="notification_channel_controls_opened_accessibility" msgid="6553950422055908113">"Lietotnes <xliff:g id="APP_NAME">%1$s</xliff:g> paziņojumu vadīklas ir atvērtas"</string>
<string name="notification_channel_controls_closed_accessibility" msgid="7521619812603693144">"Lietotnes <xliff:g id="APP_NAME">%1$s</xliff:g> paziņojumu vadīklas ir aizvērtas"</string>
<string name="notification_channel_switch_accessibility" msgid="3420796005601900717">"Atļaut paziņojumus no šī kanāla"</string>
- <string name="notification_all_categories" msgid="5407190218055113282">"Visas kategorijas"</string>
<string name="notification_more_settings" msgid="816306283396553571">"Citi iestatījumi"</string>
- <string name="notification_app_settings" msgid="3743278649182392015">"Pielāgot: <xliff:g id="SUB_CATEGORY">%1$s</xliff:g>"</string>
+ <string name="notification_app_settings" msgid="420348114670768449">"Pielāgot"</string>
<string name="notification_done" msgid="5279426047273930175">"Gatavs"</string>
+ <string name="inline_undo" msgid="558916737624706010">"Atsaukt"</string>
<string name="notification_menu_accessibility" msgid="2046162834248888553">"<xliff:g id="APP_NAME">%1$s</xliff:g> <xliff:g id="MENU_DESCRIPTION">%2$s</xliff:g>"</string>
<string name="notification_menu_gear_description" msgid="2204480013726775108">"paziņojumu vadīklas"</string>
<string name="notification_menu_snooze_description" msgid="3653669438131034525">"paziņojumu atlikšanas opcijas"</string>
@@ -737,8 +732,7 @@
<string name="pip_phone_expand" msgid="5889780005575693909">"Izvērst"</string>
<string name="pip_phone_minimize" msgid="1079119422589131792">"Minimizēt"</string>
<string name="pip_phone_close" msgid="8416647892889710330">"Aizvērt"</string>
- <!-- no translation found for pip_phone_settings (8080777499521528521) -->
- <skip />
+ <string name="pip_phone_settings" msgid="8080777499521528521">"Iestatījumi"</string>
<string name="pip_phone_dismiss_hint" msgid="6351678169095923899">"Velciet lejup, lai noraidītu"</string>
<string name="pip_menu_title" msgid="4707292089961887657">"Izvēlne"</string>
<string name="pip_notification_title" msgid="3204024940158161322">"<xliff:g id="NAME">%s</xliff:g> ir attēlā attēlā"</string>
diff --git a/packages/SystemUI/res/values-mk/strings.xml b/packages/SystemUI/res/values-mk/strings.xml
index b64217dc2774..886e083044b1 100644
--- a/packages/SystemUI/res/values-mk/strings.xml
+++ b/packages/SystemUI/res/values-mk/strings.xml
@@ -33,7 +33,10 @@
<string name="status_bar_ongoing_events_title" msgid="1682504513316879202">"Во тек"</string>
<string name="status_bar_latest_events_title" msgid="6594767438577593172">"Известувања"</string>
<string name="battery_low_title" msgid="6456385927409742437">"Батеријата е слаба"</string>
+ <string name="battery_low_title_hybrid" msgid="6268991275887381595">"Батеријата е слаба. Вклучете го штедачот на батерија"</string>
<string name="battery_low_percent_format" msgid="2900940511201380775">"Преостануваат <xliff:g id="PERCENTAGE">%s</xliff:g>"</string>
+ <string name="battery_low_percent_format_hybrid" msgid="6838677459286775617">"Преостануваат <xliff:g id="PERCENTAGE">%s</xliff:g>, уште околу <xliff:g id="TIME">%s</xliff:g> според користењето"</string>
+ <string name="battery_low_percent_format_hybrid_short" msgid="9025795469949145586">"Преостануваат <xliff:g id="PERCENTAGE">%s</xliff:g>, уште околу <xliff:g id="TIME">%s</xliff:g>"</string>
<string name="battery_low_percent_format_saver_started" msgid="7879389868952879166">"Преостануваат <xliff:g id="PERCENTAGE">%s</xliff:g>. Штедачот на батерија е вклучен."</string>
<string name="invalid_charger" msgid="4549105996740522523">"Полначот на USB меморијата не е поддржан.\nКористете го само полначот доставен со уредот."</string>
<string name="invalid_charger_title" msgid="3515740382572798460">"Полнењето преку USB не е поддржано."</string>
@@ -67,14 +70,15 @@
<string name="usb_debugging_secondary_user_message" msgid="6067122453571699801">"Корисникот што моментално е најавен на уредов не може да вклучи отстранување грешки на USB. За да ја користите функцијава, префрлете се на примарниот корисник."</string>
<string name="compat_mode_on" msgid="6623839244840638213">"Зумирај да се исполни екранот"</string>
<string name="compat_mode_off" msgid="4434467572461327898">"Растегни да се исполни екранот"</string>
+ <string name="global_action_screenshot" msgid="8329831278085426283">"Слика од екранот"</string>
<string name="screenshot_saving_ticker" msgid="7403652894056693515">"Сликата на екранот се зачувува..."</string>
<string name="screenshot_saving_title" msgid="8242282144535555697">"Сликата на екранот се зачувува..."</string>
- <string name="screenshot_saving_text" msgid="2419718443411738818">"Сликата на екранот се зачувува."</string>
- <string name="screenshot_saved_title" msgid="6461865960961414961">"Сликата на екранот е снимена."</string>
- <string name="screenshot_saved_text" msgid="2685605830386712477">"Допрете за да ја видите сликата на екранот."</string>
- <string name="screenshot_failed_title" msgid="705781116746922771">"Сликата на екранот не можеше да се сними."</string>
- <string name="screenshot_failed_to_save_unknown_text" msgid="7887826345701753830">"Се појави проблем при зачувување на сликата од екранот."</string>
- <string name="screenshot_failed_to_save_text" msgid="2592658083866306296">"Сликата од екранот не може да се зачува поради ограничена меморија."</string>
+ <string name="screenshot_saving_text" msgid="2545047868936087248">"Сликата од екранот се зачувува"</string>
+ <string name="screenshot_saved_title" msgid="5637073968117370753">"Сликата од екранот е зачувана"</string>
+ <string name="screenshot_saved_text" msgid="7574667448002050363">"Допрете за да ја видите сликата од екранот"</string>
+ <string name="screenshot_failed_title" msgid="9096484883063264803">"Сликата од екранот не можеше да се сними"</string>
+ <string name="screenshot_failed_to_save_unknown_text" msgid="8844781948876286488">"Проблем при зачувувањето слика од екранот"</string>
+ <string name="screenshot_failed_to_save_text" msgid="3041612585107107310">"Сликата од екранот не може да се зачува поради ограничена меморија"</string>
<string name="screenshot_failed_to_capture_text" msgid="173674476457581486">"Апликацијата или вашата организација не дозволува снимање слики од екранот"</string>
<string name="usb_preference_title" msgid="6551050377388882787">"Пренос на датотека со USB"</string>
<string name="use_mtp_button_title" msgid="4333504413563023626">"Монтирај како мултимедијален плеер (MTP)"</string>
@@ -557,26 +561,19 @@
<string name="tuner_full_importance_settings_off" msgid="8208165412614935229">"Исклучено"</string>
<string name="power_notification_controls_description" msgid="4372459941671353358">"Со контролите за известувањата за напојување, може да поставите ниво на важност од 0 до 5 за известувањата на која било апликација. \n\n"<b>"Ниво 5"</b>" \n- Прикажувај на врвот на списокот со известувања \n- Дозволи прекин во цел екран \n- Секогаш користи појавување \n\n"<b>"Ниво 4"</b>" \n- Спречи прекин во цел екран \n- Секогаш користи појавување \n\n"<b>"Ниво 3"</b>" \n- Спречи прекин во цел екран \n- Без појавување \n\n"<b>"Ниво 2"</b>" \n- Спречи прекин во цел екран \n- Без појавување \n- Без звук и вибрации \n\n"<b>"Ниво 1"</b>" \n- Спречи прекин во цел екран \n- Без појавување \n- Без звук и вибрации \n- Сокриј од заклучен екран и статусна лента \n- Прикажувај на дното на списокот со известувања \n\n"<b>"Ниво 0"</b>" \n- Блокирај ги сите известувања од апликацијата"</string>
<string name="notification_header_default_channel" msgid="7506845022070889909">"Известувања"</string>
- <string name="notification_channel_disabled" msgid="2139193533791840539">"Веќе нема да ги добивате овие известувања"</string>
- <string name="notification_num_channels" msgid="2048144408999179471">"<xliff:g id="NUMBER">%d</xliff:g> категории известувања"</string>
- <string name="notification_default_channel_desc" msgid="2506053815870808359">"Апликацијава нема катерии известувања"</string>
- <string name="notification_unblockable_desc" msgid="3561016061737896906">"Известувањата од апликацијава не може да се исклучат"</string>
- <plurals name="notification_num_channels_desc" formatted="false" msgid="5492793452274077663">
- <item quantity="one">1 од <xliff:g id="NUMBER_1">%s</xliff:g> категорија известувања од апликацијава</item>
- <item quantity="other">1 од <xliff:g id="NUMBER_1">%s</xliff:g> категории известувања од апликацијава</item>
- </plurals>
- <string name="notification_channels_list_desc_2" msgid="6214732715833946441">"<xliff:g id="CHANNEL_NAME_1">%1$s</xliff:g>, <xliff:g id="CHANNEL_NAME_2">%2$s</xliff:g>"</string>
- <plurals name="notification_channels_list_desc_2_and_others" formatted="false" msgid="2747813553355336157">
- <item quantity="one"><xliff:g id="CHANNEL_NAME_1_3">%1$s</xliff:g>, <xliff:g id="CHANNEL_NAME_2_4">%2$s</xliff:g> и уште <xliff:g id="NUMBER_5">%3$d</xliff:g></item>
- <item quantity="other"><xliff:g id="CHANNEL_NAME_1_3">%1$s</xliff:g>, <xliff:g id="CHANNEL_NAME_2_4">%2$s</xliff:g> и уште <xliff:g id="NUMBER_5">%3$d</xliff:g></item>
- </plurals>
+ <string name="notification_channel_disabled" msgid="344536703863700565">"Веќе нема да ги гледате овие известувања"</string>
+ <string name="inline_keep_showing" msgid="8945102997083836858">"Дали да продолжат да се прикажуваат известувањава?"</string>
+ <string name="inline_stop_button" msgid="4172980096860941033">"Запри ги известувањата"</string>
+ <string name="inline_keep_button" msgid="6665940297019018232">"Продолжи да ги прикажуваш"</string>
+ <string name="inline_keep_showing_app" msgid="1723113469580031041">"Дали да продолжат да се прикажуваат известувања од апликацијава?"</string>
+ <string name="notification_unblockable_desc" msgid="1037434112919403708">"Известувањава не може да се исклучат"</string>
<string name="notification_channel_controls_opened_accessibility" msgid="6553950422055908113">"Контролите за известувањата за <xliff:g id="APP_NAME">%1$s</xliff:g> се отворија"</string>
<string name="notification_channel_controls_closed_accessibility" msgid="7521619812603693144">"Контролите за известувањата за <xliff:g id="APP_NAME">%1$s</xliff:g> се затворија"</string>
<string name="notification_channel_switch_accessibility" msgid="3420796005601900717">"Дозволете известувања од овој канал"</string>
- <string name="notification_all_categories" msgid="5407190218055113282">"Сите категории"</string>
<string name="notification_more_settings" msgid="816306283396553571">"Повеќе поставки"</string>
- <string name="notification_app_settings" msgid="3743278649182392015">"Приспособи: <xliff:g id="SUB_CATEGORY">%1$s</xliff:g>"</string>
+ <string name="notification_app_settings" msgid="420348114670768449">"Приспособете"</string>
<string name="notification_done" msgid="5279426047273930175">"Готово"</string>
+ <string name="inline_undo" msgid="558916737624706010">"Врати"</string>
<string name="notification_menu_accessibility" msgid="2046162834248888553">"<xliff:g id="APP_NAME">%1$s</xliff:g> <xliff:g id="MENU_DESCRIPTION">%2$s</xliff:g>"</string>
<string name="notification_menu_gear_description" msgid="2204480013726775108">"контроли за известувањето"</string>
<string name="notification_menu_snooze_description" msgid="3653669438131034525">"опции за одложување на известувањето"</string>
@@ -731,8 +728,7 @@
<string name="pip_phone_expand" msgid="5889780005575693909">"Проширете"</string>
<string name="pip_phone_minimize" msgid="1079119422589131792">"Минимизирај"</string>
<string name="pip_phone_close" msgid="8416647892889710330">"Затвори"</string>
- <!-- no translation found for pip_phone_settings (8080777499521528521) -->
- <skip />
+ <string name="pip_phone_settings" msgid="8080777499521528521">"Поставки"</string>
<string name="pip_phone_dismiss_hint" msgid="6351678169095923899">"Повлечете надолу за да отфрлите"</string>
<string name="pip_menu_title" msgid="4707292089961887657">"Мени"</string>
<string name="pip_notification_title" msgid="3204024940158161322">"<xliff:g id="NAME">%s</xliff:g> е во слика во слика"</string>
diff --git a/packages/SystemUI/res/values-mn/strings.xml b/packages/SystemUI/res/values-mn/strings.xml
index 42bd38b7271c..c8aba01b79e8 100644
--- a/packages/SystemUI/res/values-mn/strings.xml
+++ b/packages/SystemUI/res/values-mn/strings.xml
@@ -31,7 +31,10 @@
<string name="status_bar_ongoing_events_title" msgid="1682504513316879202">"Гарсан"</string>
<string name="status_bar_latest_events_title" msgid="6594767438577593172">"Мэдэгдэл"</string>
<string name="battery_low_title" msgid="6456385927409742437">"Батерей дуусаж байна"</string>
+ <string name="battery_low_title_hybrid" msgid="6268991275887381595">"Батерей бага байна. Тэжээл хэмнэгчийг асаана уу"</string>
<string name="battery_low_percent_format" msgid="2900940511201380775">"<xliff:g id="PERCENTAGE">%s</xliff:g> үлдсэн"</string>
+ <string name="battery_low_percent_format_hybrid" msgid="6838677459286775617">"<xliff:g id="PERCENTAGE">%s</xliff:g> үлдсэн байна. Таны хэрэглээнд тулгуурлан ойролцоогоор <xliff:g id="TIME">%s</xliff:g>-н хугацаа үлдсэн"</string>
+ <string name="battery_low_percent_format_hybrid_short" msgid="9025795469949145586">"<xliff:g id="PERCENTAGE">%s</xliff:g> үлдсэн байна. Ойролцоогоор <xliff:g id="TIME">%s</xliff:g>-н хугацаа үлдсэн"</string>
<string name="battery_low_percent_format_saver_started" msgid="7879389868952879166">"<xliff:g id="PERCENTAGE">%s</xliff:g> үлдсэн. Тэжээл хэмнэгч асаалттай байна."</string>
<string name="invalid_charger" msgid="4549105996740522523">"USB цэнэглэлт дэмжигдэхгүй байна.\nЗөвхөн нийлүүлэгдсэн цэнэглэгчийг ашиглана уу."</string>
<string name="invalid_charger_title" msgid="3515740382572798460">"USB-р цэнэглэх дэмжигддэггүй."</string>
@@ -65,14 +68,15 @@
<string name="usb_debugging_secondary_user_message" msgid="6067122453571699801">"Энэ төхөөрөмжид нэвтэрсэн хэрэглэгч USB дебаг хийх онцлогийг асаах боломжгүй байна. Энэ онцлогийг ашиглахын тулд үндсэн хэрэглэгч рүү сэлгэнэ үү."</string>
<string name="compat_mode_on" msgid="6623839244840638213">"Дэлгэц дүүргэх бол өсгөнө үү"</string>
<string name="compat_mode_off" msgid="4434467572461327898">"Дэлгэц дүүргэх бол татна уу"</string>
+ <string name="global_action_screenshot" msgid="8329831278085426283">"Дэлгэцийн зураг дарах"</string>
<string name="screenshot_saving_ticker" msgid="7403652894056693515">"Дэлгэцийн агшинг хадгалж байна…"</string>
<string name="screenshot_saving_title" msgid="8242282144535555697">"Дэлгэцийн агшинг хадгалж байна…"</string>
- <string name="screenshot_saving_text" msgid="2419718443411738818">"Дэлгэцийн агшин хадгалагдав."</string>
- <string name="screenshot_saved_title" msgid="6461865960961414961">"Дэлгэцийн агшинг авсан."</string>
- <string name="screenshot_saved_text" msgid="2685605830386712477">"Дэлгэцийн агшингаа харахын тулд дарна уу."</string>
- <string name="screenshot_failed_title" msgid="705781116746922771">"Дэлгэцийн агшинг авч чадсангүй."</string>
- <string name="screenshot_failed_to_save_unknown_text" msgid="7887826345701753830">"Дэлгэцийн агшинг хадгалахад алдаа гарлаа."</string>
- <string name="screenshot_failed_to_save_text" msgid="2592658083866306296">"Хадгалах сангийн багтаамж бага байгаа тул дэлгэцийн авсан зургийг хадгалах боломжгүй байна."</string>
+ <string name="screenshot_saving_text" msgid="2545047868936087248">"Дэлгэцээс дарсан зургийг хадгалж байна"</string>
+ <string name="screenshot_saved_title" msgid="5637073968117370753">"Дэлгэцээс дарсан зургийг хадгалсан"</string>
+ <string name="screenshot_saved_text" msgid="7574667448002050363">"Дэлгэцээс дарсан зургийг харах бол товшино уу"</string>
+ <string name="screenshot_failed_title" msgid="9096484883063264803">"Дэлгэцийн зургийг дарж чадсангүй"</string>
+ <string name="screenshot_failed_to_save_unknown_text" msgid="8844781948876286488">"Дэлгэцээс дарсан зургийг хадгалахад алдаа гарлаа"</string>
+ <string name="screenshot_failed_to_save_text" msgid="3041612585107107310">"Сангийн багтаамж бага байгаа тул дэлгэцээс дарсан зургийг хадгалах боломжгүй байна"</string>
<string name="screenshot_failed_to_capture_text" msgid="173674476457581486">"Таны апп, байгууллагад дэлгэцийн зураг авахыг зөвшөөрдөггүй"</string>
<string name="usb_preference_title" msgid="6551050377388882787">"USB файл шилжүүлэх сонголт"</string>
<string name="use_mtp_button_title" msgid="4333504413563023626">"Медиа тоглуулагч(MTP) болгон залгах"</string>
@@ -557,26 +561,19 @@
<string name="tuner_full_importance_settings_off" msgid="8208165412614935229">"Идэвхгүй"</string>
<string name="power_notification_controls_description" msgid="4372459941671353358">"Тэжээлийн мэдэгдлийн удирдлагын тусламжтайгаар та апп-н мэдэгдэлд 0-5 хүртэлх ач холбогдлын түвшин тогтоох боломжтой. \n\n"<b>"5-р түвшин"</b>" \n- Мэдэгдлийн жагсаалтын хамгийн дээр харуулна \n- Бүтэн дэлгэцэд саад болно \n- Дэлгэцэд тогтмол гарч ирнэ \n\n"<b>"4-р түвшин"</b>" \n- Бүтэн дэлгэцэд саад болохоос сэргийлнэ \n- Дэлгэцэд тогтмол гарч ирнэ \n\n"<b>"3-р түвшин"</b>" \n- Бүтэн дэлгэцэд саад болохоос сэргийлнэ \n- Дэлгэцэд хэзээ ч гарч ирэхгүй \n\n"<b>"2-р түвшин"</b>" \n- Бүтэн дэлгэцэд саад болохоос сэргийлнэ \n- Дэлгэцэд хэзээ ч гарч ирэхгүй \n- Дуу болон чичиргээ хэзээ ч гаргахгүй \n\n"<b>"1-р түвшин"</b>" \n- Бүтэн дэлгэцэд саад болохоос сэргийлнэ \n- Дэлгэцэд хэзээ ч гарч ирэхгүй \n- Дуу болон чичиргээ хэзээ ч гаргахгүй \n- Түгжигдсэн дэлгэц болон статусын самбараас нууна \n- Мэдэгдлийн жагсаалтын доор харуулна \n\n"<b>"0-р түвшин"</b>" \n- Энэ апп-н бүх мэдэгдлийг блоклоно"</string>
<string name="notification_header_default_channel" msgid="7506845022070889909">"Мэдэгдэл"</string>
- <string name="notification_channel_disabled" msgid="2139193533791840539">"Ta цаашид эдгээр мэдэгдлийг авахгүй"</string>
- <string name="notification_num_channels" msgid="2048144408999179471">"<xliff:g id="NUMBER">%d</xliff:g> мэдэгдлийн ангилал"</string>
- <string name="notification_default_channel_desc" msgid="2506053815870808359">"Энэ апп-д мэдэгдлийн категори алга"</string>
- <string name="notification_unblockable_desc" msgid="3561016061737896906">"Энэ аппын мэдэгдлийг унтраах боломжгүй"</string>
- <plurals name="notification_num_channels_desc" formatted="false" msgid="5492793452274077663">
- <item quantity="other">Энэ аппын <xliff:g id="NUMBER_1">%s</xliff:g> мэдэгдлийн категорийн 1</item>
- <item quantity="one">Энэ аппын <xliff:g id="NUMBER_0">%s</xliff:g> мэдэгдлийн категорийн 1</item>
- </plurals>
- <string name="notification_channels_list_desc_2" msgid="6214732715833946441">"<xliff:g id="CHANNEL_NAME_1">%1$s</xliff:g>, <xliff:g id="CHANNEL_NAME_2">%2$s</xliff:g>"</string>
- <plurals name="notification_channels_list_desc_2_and_others" formatted="false" msgid="2747813553355336157">
- <item quantity="other"><xliff:g id="CHANNEL_NAME_1_3">%1$s</xliff:g>, <xliff:g id="CHANNEL_NAME_2_4">%2$s</xliff:g>, бусад <xliff:g id="NUMBER_5">%3$d</xliff:g></item>
- <item quantity="one"><xliff:g id="CHANNEL_NAME_1_0">%1$s</xliff:g>, <xliff:g id="CHANNEL_NAME_2_1">%2$s</xliff:g>, бусад <xliff:g id="NUMBER_2">%3$d</xliff:g></item>
- </plurals>
+ <string name="notification_channel_disabled" msgid="344536703863700565">"Та эдгээр мэдэгдлийг цаашид харахгүй"</string>
+ <string name="inline_keep_showing" msgid="8945102997083836858">"Эдгээр мэдэгдлийг харуулсан хэвээр байх уу?"</string>
+ <string name="inline_stop_button" msgid="4172980096860941033">"Мэдэгдлийг зогсоох"</string>
+ <string name="inline_keep_button" msgid="6665940297019018232">"Харуулсан хэвээр байх"</string>
+ <string name="inline_keep_showing_app" msgid="1723113469580031041">"Энэ аппаас мэдэгдэл харуулсан хэвээр байх уу?"</string>
+ <string name="notification_unblockable_desc" msgid="1037434112919403708">"Эдгээр мэдэгдлийг унтраах боломжгүй"</string>
<string name="notification_channel_controls_opened_accessibility" msgid="6553950422055908113">"<xliff:g id="APP_NAME">%1$s</xliff:g>-н мэдэгдлийн хяналтыг нээсэн"</string>
<string name="notification_channel_controls_closed_accessibility" msgid="7521619812603693144">"<xliff:g id="APP_NAME">%1$s</xliff:g>-н мэдэгдлийн хяналтыг хаасан"</string>
<string name="notification_channel_switch_accessibility" msgid="3420796005601900717">"Энэ сувгийн мэдэгдлийг зөвшөөрөх"</string>
- <string name="notification_all_categories" msgid="5407190218055113282">"Бүх ангилал"</string>
<string name="notification_more_settings" msgid="816306283396553571">"Бусад тохиргоо"</string>
- <string name="notification_app_settings" msgid="3743278649182392015">"Өөрчлөх: <xliff:g id="SUB_CATEGORY">%1$s</xliff:g>"</string>
+ <string name="notification_app_settings" msgid="420348114670768449">"Тохируулах"</string>
<string name="notification_done" msgid="5279426047273930175">"Дууссан"</string>
+ <string name="inline_undo" msgid="558916737624706010">"Болих"</string>
<string name="notification_menu_accessibility" msgid="2046162834248888553">"<xliff:g id="APP_NAME">%1$s</xliff:g> <xliff:g id="MENU_DESCRIPTION">%2$s</xliff:g>"</string>
<string name="notification_menu_gear_description" msgid="2204480013726775108">"мэдэгдлийн удирдлага"</string>
<string name="notification_menu_snooze_description" msgid="3653669438131034525">"мэдэгдэл түр хойшлуулагчийн сонголт"</string>
@@ -731,8 +728,7 @@
<string name="pip_phone_expand" msgid="5889780005575693909">"Дэлгэх"</string>
<string name="pip_phone_minimize" msgid="1079119422589131792">"Багасгах"</string>
<string name="pip_phone_close" msgid="8416647892889710330">"Хаах"</string>
- <!-- no translation found for pip_phone_settings (8080777499521528521) -->
- <skip />
+ <string name="pip_phone_settings" msgid="8080777499521528521">"Тохиргоо"</string>
<string name="pip_phone_dismiss_hint" msgid="6351678169095923899">"Хаахын тулд доош чирэх"</string>
<string name="pip_menu_title" msgid="4707292089961887657">"Цэс"</string>
<string name="pip_notification_title" msgid="3204024940158161322">"<xliff:g id="NAME">%s</xliff:g> дэлгэцэн доторх дэлгэцэд байна"</string>
diff --git a/packages/SystemUI/res/values-ms/strings.xml b/packages/SystemUI/res/values-ms/strings.xml
index 118d2c7174b0..399be8b298a1 100644
--- a/packages/SystemUI/res/values-ms/strings.xml
+++ b/packages/SystemUI/res/values-ms/strings.xml
@@ -33,7 +33,10 @@
<string name="status_bar_ongoing_events_title" msgid="1682504513316879202">"Sedang berlangsung"</string>
<string name="status_bar_latest_events_title" msgid="6594767438577593172">"Pemberitahuan"</string>
<string name="battery_low_title" msgid="6456385927409742437">"Bateri lemah"</string>
+ <string name="battery_low_title_hybrid" msgid="6268991275887381595">"Bateri lemah. Hidupkan Penjimat Bateri"</string>
<string name="battery_low_percent_format" msgid="2900940511201380775">"<xliff:g id="PERCENTAGE">%s</xliff:g> yang tinggal"</string>
+ <string name="battery_low_percent_format_hybrid" msgid="6838677459286775617">"Tinggal <xliff:g id="PERCENTAGE">%s</xliff:g>, kira-kira <xliff:g id="TIME">%s</xliff:g> lagi berdasarkan penggunaan anda"</string>
+ <string name="battery_low_percent_format_hybrid_short" msgid="9025795469949145586">"Tinggal <xliff:g id="PERCENTAGE">%s</xliff:g>, kira-kira <xliff:g id="TIME">%s</xliff:g> lagi"</string>
<string name="battery_low_percent_format_saver_started" msgid="7879389868952879166">"Tinggal <xliff:g id="PERCENTAGE">%s</xliff:g>. Penjimat Bateri dihidupkan."</string>
<string name="invalid_charger" msgid="4549105996740522523">"Pengecasan USB tidak disokong.\nGunakan hanya pengecas yang dibekalkan."</string>
<string name="invalid_charger_title" msgid="3515740382572798460">"Pengecasan USB tidak disokong."</string>
@@ -67,14 +70,15 @@
<string name="usb_debugging_secondary_user_message" msgid="6067122453571699801">"Pengguna yang log masuk ke peranti ini pada masa ini tidak boleh menghidupkan penyahpepijatan USB. Untuk menggunakan ciri ini, tukar kepada pengguna utama."</string>
<string name="compat_mode_on" msgid="6623839244840638213">"Zum untuk memenuhi skrin"</string>
<string name="compat_mode_off" msgid="4434467572461327898">"Regang utk memenuhi skrin"</string>
+ <string name="global_action_screenshot" msgid="8329831278085426283">"Tangkapan skrin"</string>
<string name="screenshot_saving_ticker" msgid="7403652894056693515">"Menyimpan tangkapan skrin..."</string>
<string name="screenshot_saving_title" msgid="8242282144535555697">"Menyimpan tangkapan skrin..."</string>
- <string name="screenshot_saving_text" msgid="2419718443411738818">"Tangkapan skrin sedang disimpan."</string>
- <string name="screenshot_saved_title" msgid="6461865960961414961">"Tangkapan skrin ditangkap."</string>
- <string name="screenshot_saved_text" msgid="2685605830386712477">"Ketik untuk melihat tangkapan skrin anda."</string>
- <string name="screenshot_failed_title" msgid="705781116746922771">"Tidak dapat menangkap tangkapan skrin."</string>
- <string name="screenshot_failed_to_save_unknown_text" msgid="7887826345701753830">"Berlaku masalah semasa menyimpan tangkapan skrin."</string>
- <string name="screenshot_failed_to_save_text" msgid="2592658083866306296">"Tidak dapat menyimpan tangkapan skrin kerana ruang storan terhad."</string>
+ <string name="screenshot_saving_text" msgid="2545047868936087248">"Tangkapan skrin sedang disimpan"</string>
+ <string name="screenshot_saved_title" msgid="5637073968117370753">"Tangkapan skrin disimpan"</string>
+ <string name="screenshot_saved_text" msgid="7574667448002050363">"Ketik untuk melihat tangkapan skrin anda"</string>
+ <string name="screenshot_failed_title" msgid="9096484883063264803">"Tidak dapat menangkap tangkapan skrin"</string>
+ <string name="screenshot_failed_to_save_unknown_text" msgid="8844781948876286488">"Masalah berlaku semasa menyimpan tangkapan skrin"</string>
+ <string name="screenshot_failed_to_save_text" msgid="3041612585107107310">"Tidak dapat menyimpan tangkapan skrin kerana ruang storan terhad"</string>
<string name="screenshot_failed_to_capture_text" msgid="173674476457581486">"Pengambilan tangkapan skrin tidak dibenarkan oleh apl atau organisasi anda"</string>
<string name="usb_preference_title" msgid="6551050377388882787">"Pilihan pemindahan fail USB"</string>
<string name="use_mtp_button_title" msgid="4333504413563023626">"Lekapkan sebagai pemain media (MTP)"</string>
@@ -557,26 +561,19 @@
<string name="tuner_full_importance_settings_off" msgid="8208165412614935229">"Mati"</string>
<string name="power_notification_controls_description" msgid="4372459941671353358">"Dengan kawalan pemberitahuan berkuasa, anda boleh menetapkan tahap kepentingan dari 0 hingga 5 untuk pemberitahuan apl. \n\n"<b>"Tahap 5"</b>" \n- Tunjukkan pada bahagian atas senarai pemberitahuan \n- Benarkan gangguan skrin penuh \n- Sentiasa intai \n\n"<b>"Tahap 4"</b>" \n- Halang gangguan skrin penuh \n- Sentiasa intai \n\n"<b>"Tahap 3"</b>" \n- Halang gangguan skrin penuh \n- Jangan intai \n\n"<b>"Tahap 2"</b>" \n- Halang gangguan skrin penuh \n- Jangan intai \n- Jangan berbunyi dan bergetar \n\n"<b>"Tahap 1"</b>" \n- Halang gangguan skrin penuh \n- Jangan intai \n- Jangan berbunyi atau bergetar \n- Sembunyikan daripada skrin kunci dan bar status \n- Tunjukkan di bahagian bawah senarai pemberitahuan \n\n"<b>"Tahap 0"</b>" \n- Sekat semua pemberitahuan daripada apl"</string>
<string name="notification_header_default_channel" msgid="7506845022070889909">"Pemberitahuan"</string>
- <string name="notification_channel_disabled" msgid="2139193533791840539">"Anda tidak akan menerima pemberitahuan ini lagi"</string>
- <string name="notification_num_channels" msgid="2048144408999179471">"<xliff:g id="NUMBER">%d</xliff:g> kategori pemberitahuan"</string>
- <string name="notification_default_channel_desc" msgid="2506053815870808359">"Apl ini tiada kategori pemberitahuan"</string>
- <string name="notification_unblockable_desc" msgid="3561016061737896906">"Pemberitahuan daripada apl ini tidak boleh dimatikan"</string>
- <plurals name="notification_num_channels_desc" formatted="false" msgid="5492793452274077663">
- <item quantity="other">1 daripada <xliff:g id="NUMBER_1">%s</xliff:g> kategori pemberitahuan daripada apl ini</item>
- <item quantity="one">1 daripada <xliff:g id="NUMBER_0">%s</xliff:g> kategori pemberitahuan daripada apl ini</item>
- </plurals>
- <string name="notification_channels_list_desc_2" msgid="6214732715833946441">"<xliff:g id="CHANNEL_NAME_1">%1$s</xliff:g>, <xliff:g id="CHANNEL_NAME_2">%2$s</xliff:g>"</string>
- <plurals name="notification_channels_list_desc_2_and_others" formatted="false" msgid="2747813553355336157">
- <item quantity="other"><xliff:g id="CHANNEL_NAME_1_3">%1$s</xliff:g>, <xliff:g id="CHANNEL_NAME_2_4">%2$s</xliff:g> dan <xliff:g id="NUMBER_5">%3$d</xliff:g> yang lain</item>
- <item quantity="one"><xliff:g id="CHANNEL_NAME_1_0">%1$s</xliff:g>, <xliff:g id="CHANNEL_NAME_2_1">%2$s</xliff:g> dan <xliff:g id="NUMBER_2">%3$d</xliff:g> yang lain</item>
- </plurals>
+ <string name="notification_channel_disabled" msgid="344536703863700565">"Anda tidak akan melihat pemberitahuan ini lagi"</string>
+ <string name="inline_keep_showing" msgid="8945102997083836858">"Terus tunjukkan pemberitahuan ini?"</string>
+ <string name="inline_stop_button" msgid="4172980096860941033">"Hentikan pemberitahuan"</string>
+ <string name="inline_keep_button" msgid="6665940297019018232">"Terus tunjukkan"</string>
+ <string name="inline_keep_showing_app" msgid="1723113469580031041">"Terus tunjukkan pemberitahuan daripada apl ini?"</string>
+ <string name="notification_unblockable_desc" msgid="1037434112919403708">"Pemberitahuan ini tidak boleh dimatikan"</string>
<string name="notification_channel_controls_opened_accessibility" msgid="6553950422055908113">"Kawalan pemberitahuan untuk <xliff:g id="APP_NAME">%1$s</xliff:g> dibuka"</string>
<string name="notification_channel_controls_closed_accessibility" msgid="7521619812603693144">"Kawalan pemberitahuan untuk <xliff:g id="APP_NAME">%1$s</xliff:g> ditutup"</string>
<string name="notification_channel_switch_accessibility" msgid="3420796005601900717">"Benarkan pemberitahuan daripada saluran ini"</string>
- <string name="notification_all_categories" msgid="5407190218055113282">"Semua Kategori"</string>
<string name="notification_more_settings" msgid="816306283396553571">"Lagi tetapan"</string>
- <string name="notification_app_settings" msgid="3743278649182392015">"Sesuaikan: <xliff:g id="SUB_CATEGORY">%1$s</xliff:g>"</string>
+ <string name="notification_app_settings" msgid="420348114670768449">"Sesuaikan"</string>
<string name="notification_done" msgid="5279426047273930175">"Selesai"</string>
+ <string name="inline_undo" msgid="558916737624706010">"Buat asal"</string>
<string name="notification_menu_accessibility" msgid="2046162834248888553">"<xliff:g id="APP_NAME">%1$s</xliff:g> <xliff:g id="MENU_DESCRIPTION">%2$s</xliff:g>"</string>
<string name="notification_menu_gear_description" msgid="2204480013726775108">"kawalan pemberitahuan"</string>
<string name="notification_menu_snooze_description" msgid="3653669438131034525">"pilihan tunda pemberitahuan"</string>
@@ -731,8 +728,7 @@
<string name="pip_phone_expand" msgid="5889780005575693909">"Kembangkan"</string>
<string name="pip_phone_minimize" msgid="1079119422589131792">"Minimumkan"</string>
<string name="pip_phone_close" msgid="8416647892889710330">"Tutup"</string>
- <!-- no translation found for pip_phone_settings (8080777499521528521) -->
- <skip />
+ <string name="pip_phone_settings" msgid="8080777499521528521">"Tetapan"</string>
<string name="pip_phone_dismiss_hint" msgid="6351678169095923899">"Seret ke bawah untuk mengetepikan"</string>
<string name="pip_menu_title" msgid="4707292089961887657">"Menu"</string>
<string name="pip_notification_title" msgid="3204024940158161322">"<xliff:g id="NAME">%s</xliff:g> terdapat dalam gambar dalam gambar"</string>
diff --git a/packages/SystemUI/res/values-nb/strings.xml b/packages/SystemUI/res/values-nb/strings.xml
index 1afd6353211d..0e7447aa8f25 100644
--- a/packages/SystemUI/res/values-nb/strings.xml
+++ b/packages/SystemUI/res/values-nb/strings.xml
@@ -33,13 +33,10 @@
<string name="status_bar_ongoing_events_title" msgid="1682504513316879202">"Aktiviteter"</string>
<string name="status_bar_latest_events_title" msgid="6594767438577593172">"Varsler"</string>
<string name="battery_low_title" msgid="6456385927409742437">"Batterikapasiteten er lav"</string>
- <!-- no translation found for battery_low_title_hybrid (6268991275887381595) -->
- <skip />
+ <string name="battery_low_title_hybrid" msgid="6268991275887381595">"Du har lite batteri. Slå på batterisparing"</string>
<string name="battery_low_percent_format" msgid="2900940511201380775">"<xliff:g id="PERCENTAGE">%s</xliff:g> gjenstår"</string>
- <!-- no translation found for battery_low_percent_format_hybrid (6838677459286775617) -->
- <skip />
- <!-- no translation found for battery_low_percent_format_hybrid_short (9025795469949145586) -->
- <skip />
+ <string name="battery_low_percent_format_hybrid" msgid="6838677459286775617">"<xliff:g id="PERCENTAGE">%s</xliff:g> gjenstår, omtrent <xliff:g id="TIME">%s</xliff:g> igjen basert på bruken din"</string>
+ <string name="battery_low_percent_format_hybrid_short" msgid="9025795469949145586">"<xliff:g id="PERCENTAGE">%s</xliff:g> gjenstår, omtrent <xliff:g id="TIME">%s</xliff:g> igjen"</string>
<string name="battery_low_percent_format_saver_started" msgid="7879389868952879166">"<xliff:g id="PERCENTAGE">%s</xliff:g> gjenstår. Batterisparing er på."</string>
<string name="invalid_charger" msgid="4549105996740522523">"USB-lading støttes ikke.\nBruk kun den medfølgende laderen."</string>
<string name="invalid_charger_title" msgid="3515740382572798460">"Lading via USB støttes ikke."</string>
@@ -73,22 +70,15 @@
<string name="usb_debugging_secondary_user_message" msgid="6067122453571699801">"Brukeren som for øyeblikket er logget på denne enheten, kan ikke slå på USB-feilsøking. For å bruke denne funksjonen, bytt til hovedbrukeren."</string>
<string name="compat_mode_on" msgid="6623839244840638213">"Zoom for å fylle skjermen"</string>
<string name="compat_mode_off" msgid="4434467572461327898">"Strekk for å fylle skjerm"</string>
- <!-- no translation found for global_action_screenshot (8329831278085426283) -->
- <skip />
+ <string name="global_action_screenshot" msgid="8329831278085426283">"Skjermdump"</string>
<string name="screenshot_saving_ticker" msgid="7403652894056693515">"Lagrer skjermdumpen …"</string>
<string name="screenshot_saving_title" msgid="8242282144535555697">"Lagrer skjermdumpen …"</string>
- <!-- no translation found for screenshot_saving_text (2545047868936087248) -->
- <skip />
- <!-- no translation found for screenshot_saved_title (5637073968117370753) -->
- <skip />
- <!-- no translation found for screenshot_saved_text (7574667448002050363) -->
- <skip />
- <!-- no translation found for screenshot_failed_title (9096484883063264803) -->
- <skip />
- <!-- no translation found for screenshot_failed_to_save_unknown_text (8844781948876286488) -->
- <skip />
- <!-- no translation found for screenshot_failed_to_save_text (3041612585107107310) -->
- <skip />
+ <string name="screenshot_saving_text" msgid="2545047868936087248">"Skjermdumpen lagres"</string>
+ <string name="screenshot_saved_title" msgid="5637073968117370753">"Skjermdumpen er lagret"</string>
+ <string name="screenshot_saved_text" msgid="7574667448002050363">"Trykk for å se skjermdumpen"</string>
+ <string name="screenshot_failed_title" msgid="9096484883063264803">"Kan ikke lagre skjermdumpen"</string>
+ <string name="screenshot_failed_to_save_unknown_text" msgid="8844781948876286488">"Det oppsto et problem under lagring av skjermdumpen"</string>
+ <string name="screenshot_failed_to_save_text" msgid="3041612585107107310">"Kan ikke lagre skjermdumpen på grunn av begrenset lagringsplass"</string>
<string name="screenshot_failed_to_capture_text" msgid="173674476457581486">"Appen eller organisasjonen din tillater ikke at du tar skjermdumper"</string>
<string name="usb_preference_title" msgid="6551050377388882787">"Altern. for USB-filoverføring"</string>
<string name="use_mtp_button_title" msgid="4333504413563023626">"Sett inn som mediespiller (MTP)"</string>
@@ -571,27 +561,19 @@
<string name="tuner_full_importance_settings_off" msgid="8208165412614935229">"Av"</string>
<string name="power_notification_controls_description" msgid="4372459941671353358">"Med effektive varselinnstillinger kan du angi viktighetsnivåer fra 0 til 5 for appvarsler. \n\n"<b>"Nivå 5"</b>" \n– Vis øverst på varsellisten \n– Tillat forstyrrelser ved fullskjermmodus \n– Vis alltid raskt \n\n"<b>"Nivå 4"</b>" \n– Forhindre forstyrrelser ved fullskjermmodus \n– Vis alltid raskt \n\n"<b>"Nivå 3"</b>" \n– Forhindre forstyrrelser ved fullskjermmodus \n– Vis aldri raskt \n\n"<b>"Nivå 2"</b>" \n– Forhindre forstyrrelser ved fullskjermmodus \n– Vis aldri fort \n– Tillat aldri lyder eller vibrering \n\n"<b>"Nivå 1"</b>" \n– Forhindre forstyrrelser ved fullskjermmodus \n– Vis aldri raskt \n– Tillat aldri lyder eller vibrering \n– Skjul fra låseskjermen og statusfeltet \n– Vis nederst på varsellisten \n\n"<b>"Nivå 0"</b>" \n– Blokkér alle varsler fra appen"</string>
<string name="notification_header_default_channel" msgid="7506845022070889909">"Varsler"</string>
- <!-- no translation found for notification_channel_disabled (344536703863700565) -->
- <skip />
- <!-- no translation found for inline_keep_showing (8945102997083836858) -->
- <skip />
- <!-- no translation found for inline_stop_button (4172980096860941033) -->
- <skip />
- <!-- no translation found for inline_keep_button (6665940297019018232) -->
- <skip />
- <!-- no translation found for inline_keep_showing_app (1723113469580031041) -->
- <skip />
- <!-- no translation found for notification_unblockable_desc (1037434112919403708) -->
- <skip />
+ <string name="notification_channel_disabled" msgid="344536703863700565">"Du ser ikke disse varslene lenger"</string>
+ <string name="inline_keep_showing" msgid="8945102997083836858">"Vil du fortsette å vise disse varslene?"</string>
+ <string name="inline_stop_button" msgid="4172980096860941033">"Stopp varsler"</string>
+ <string name="inline_keep_button" msgid="6665940297019018232">"Fortsett å vise"</string>
+ <string name="inline_keep_showing_app" msgid="1723113469580031041">"Vil du fortsette å vise varsler fra denne appen?"</string>
+ <string name="notification_unblockable_desc" msgid="1037434112919403708">"Du kan ikke slå av disse varslene"</string>
<string name="notification_channel_controls_opened_accessibility" msgid="6553950422055908113">"Varselinnstillingene for <xliff:g id="APP_NAME">%1$s</xliff:g> er åpnet"</string>
<string name="notification_channel_controls_closed_accessibility" msgid="7521619812603693144">"Varselinnstillingene for <xliff:g id="APP_NAME">%1$s</xliff:g> er lukket"</string>
<string name="notification_channel_switch_accessibility" msgid="3420796005601900717">"Tillat varsler fra denne kanalen"</string>
<string name="notification_more_settings" msgid="816306283396553571">"Flere innstillinger"</string>
- <!-- no translation found for notification_app_settings (420348114670768449) -->
- <skip />
+ <string name="notification_app_settings" msgid="420348114670768449">"Tilpass"</string>
<string name="notification_done" msgid="5279426047273930175">"Ferdig"</string>
- <!-- no translation found for inline_undo (558916737624706010) -->
- <skip />
+ <string name="inline_undo" msgid="558916737624706010">"Angre"</string>
<string name="notification_menu_accessibility" msgid="2046162834248888553">"<xliff:g id="APP_NAME">%1$s</xliff:g> <xliff:g id="MENU_DESCRIPTION">%2$s</xliff:g>"</string>
<string name="notification_menu_gear_description" msgid="2204480013726775108">"varselinnstillinger"</string>
<string name="notification_menu_snooze_description" msgid="3653669438131034525">"slumrealternativer for varsler"</string>
diff --git a/packages/SystemUI/res/values-ne/strings.xml b/packages/SystemUI/res/values-ne/strings.xml
index a5c13f1b5854..5814542d6841 100644
--- a/packages/SystemUI/res/values-ne/strings.xml
+++ b/packages/SystemUI/res/values-ne/strings.xml
@@ -33,13 +33,10 @@
<string name="status_bar_ongoing_events_title" msgid="1682504513316879202">"चलिरहेको"</string>
<string name="status_bar_latest_events_title" msgid="6594767438577593172">"सूचनाहरू"</string>
<string name="battery_low_title" msgid="6456385927409742437">"ब्याट्री कम छ"</string>
- <!-- no translation found for battery_low_title_hybrid (6268991275887381595) -->
- <skip />
+ <string name="battery_low_title_hybrid" msgid="6268991275887381595">"ब्याट्रीको स्तर न्यून छ। ब्याट्री सेभर सक्रिय गर्नुहोस्"</string>
<string name="battery_low_percent_format" msgid="2900940511201380775">"<xliff:g id="PERCENTAGE">%s</xliff:g> बाँकी"</string>
- <!-- no translation found for battery_low_percent_format_hybrid (6838677459286775617) -->
- <skip />
- <!-- no translation found for battery_low_percent_format_hybrid_short (9025795469949145586) -->
- <skip />
+ <string name="battery_low_percent_format_hybrid" msgid="6838677459286775617">"<xliff:g id="PERCENTAGE">%s</xliff:g> बाँकी, तपाईंको प्रयोगका आधारमा करिब <xliff:g id="TIME">%s</xliff:g> बाँकी छ"</string>
+ <string name="battery_low_percent_format_hybrid_short" msgid="9025795469949145586">"<xliff:g id="PERCENTAGE">%s</xliff:g> बाँकी, करिब <xliff:g id="TIME">%s</xliff:g> बाँकी छ"</string>
<string name="battery_low_percent_format_saver_started" msgid="7879389868952879166">"<xliff:g id="PERCENTAGE">%s</xliff:g> बाँकी। ब्याट्री सेभर सक्रिय छ।"</string>
<string name="invalid_charger" msgid="4549105996740522523">"USB चार्ज गर्न समर्थित छैन।\n आपूर्ति गरिएको चार्जर मात्र प्रयोग गर्नुहोस्।"</string>
<string name="invalid_charger_title" msgid="3515740382572798460">"USB चार्ज समर्थित छैन।"</string>
@@ -73,22 +70,15 @@
<string name="usb_debugging_secondary_user_message" msgid="6067122453571699801">"हाल यस यन्त्रमा साइन इन हुनुभएको प्रयोगकर्ताले USB डिबग सक्रिय गर्न सक्नुहुन्न। यो सुविधाको प्रयोग गर्न प्राथमिक प्रयोगकर्तामा बदल्नुहोस्‌।"</string>
<string name="compat_mode_on" msgid="6623839244840638213">"स्क्रिन भर्न जुम गर्नुहोस्"</string>
<string name="compat_mode_off" msgid="4434467572461327898">"स्क्रिन भर्न तन्काउनुहोस्"</string>
- <!-- no translation found for global_action_screenshot (8329831278085426283) -->
- <skip />
+ <string name="global_action_screenshot" msgid="8329831278085426283">"स्क्रिनसट"</string>
<string name="screenshot_saving_ticker" msgid="7403652894056693515">"स्क्रिनसट बचत गर्दै…"</string>
<string name="screenshot_saving_title" msgid="8242282144535555697">"स्क्रिनसट बचत गर्दै…"</string>
- <!-- no translation found for screenshot_saving_text (2545047868936087248) -->
- <skip />
- <!-- no translation found for screenshot_saved_title (5637073968117370753) -->
- <skip />
- <!-- no translation found for screenshot_saved_text (7574667448002050363) -->
- <skip />
- <!-- no translation found for screenshot_failed_title (9096484883063264803) -->
- <skip />
- <!-- no translation found for screenshot_failed_to_save_unknown_text (8844781948876286488) -->
- <skip />
- <!-- no translation found for screenshot_failed_to_save_text (3041612585107107310) -->
- <skip />
+ <string name="screenshot_saving_text" msgid="2545047868936087248">"स्क्रिनसट सुरक्षित गरिँदै छ"</string>
+ <string name="screenshot_saved_title" msgid="5637073968117370753">"स्क्रिनसट सुरक्षित गरियो"</string>
+ <string name="screenshot_saved_text" msgid="7574667448002050363">"आफ्नो स्क्रिनसट हेर्न ट्याप गर्नुहोस्"</string>
+ <string name="screenshot_failed_title" msgid="9096484883063264803">"स्क्रिनसट खिच्न सकिएन"</string>
+ <string name="screenshot_failed_to_save_unknown_text" msgid="8844781948876286488">"स्क्रिनसट सुरक्षित गर्ने क्रममा समस्या आइपर्‍यो"</string>
+ <string name="screenshot_failed_to_save_text" msgid="3041612585107107310">"भण्डारण ठाउँ सीमित भएका कारण स्क्रिनसट सुरक्षित गर्न सकिएन"</string>
<string name="screenshot_failed_to_capture_text" msgid="173674476457581486">"उक्त अनुप्रयोग वा तपाईंको संगठनले स्क्रिनसटहरू लिन दिँदैन"</string>
<string name="usb_preference_title" msgid="6551050377388882787">"USB फाइल सार्ने विकल्पहरू"</string>
<string name="use_mtp_button_title" msgid="4333504413563023626">"मिडिया प्लेयर(MTP)को रूपमा माउन्ट गर्नुहोस्"</string>
@@ -571,27 +561,19 @@
<string name="tuner_full_importance_settings_off" msgid="8208165412614935229">"निष्क्रिय"</string>
<string name="power_notification_controls_description" msgid="4372459941671353358">"सशक्त सूचना नियन्त्रणहरू मार्फत तपाईं अनुप्रयाेगका सूचनाहरूका लागि ० देखि ५ सम्मको महत्व सम्बन्धी स्तर सेट गर्न सक्नुहुन्छ। \n\n"<b>"स्तर ५"</b>" \n- सूचनाको सूचीको माथिल्लो भागमा देखाउने \n- पूर्ण स्क्रिनमा अवरोधका लागि अनुमति दिने \n- सधैँ चियाउने \n\n"<b>"स्तर ४"</b>" \n- पूर्ण स्क्रिनमा अवरोधलाई रोक्ने \n- सधैँ चियाउने \n\n"<b>"स्तर ३"</b>" \n- पूर्ण स्क्रिनमा अवरोधलाई रोक्ने \n- कहिल्यै नचियाउने \n\n"<b>"स्तर २"</b>" \n- पूर्ण स्क्रिनमा अवरोधलाई रोक्ने \n- कहिल्यै नचियाउने \n- कहिल्यै पनि आवाज ननिकाल्ने र कम्पन नगर्ने \n\n"<b>"स्तर १"</b>" \n- पूर्ण स्क्रिनमा अवरोध रोक्ने \n- कहिल्यै नचियाउने \n- कहिल्यै पनि आवाज ननिकाल्ने वा कम्पन नगर्ने \n- लक स्क्रिन र वस्तुस्थिति पट्टीबाट लुकाउने \n- सूचनाको सूचीको तल्लो भागमा देखाउने \n\n"<b>"स्तर ०"</b>" \n- अनुप्रयोगका सबै सूचनाहरूलाई रोक्ने"</string>
<string name="notification_header_default_channel" msgid="7506845022070889909">"सूचनाहरू"</string>
- <!-- no translation found for notification_channel_disabled (344536703863700565) -->
- <skip />
- <!-- no translation found for inline_keep_showing (8945102997083836858) -->
- <skip />
- <!-- no translation found for inline_stop_button (4172980096860941033) -->
- <skip />
- <!-- no translation found for inline_keep_button (6665940297019018232) -->
- <skip />
- <!-- no translation found for inline_keep_showing_app (1723113469580031041) -->
- <skip />
- <!-- no translation found for notification_unblockable_desc (1037434112919403708) -->
- <skip />
+ <string name="notification_channel_disabled" msgid="344536703863700565">"तपाईं अब उप्रान्त यी सूचनाहरू देख्नु हुने छैन"</string>
+ <string name="inline_keep_showing" msgid="8945102997083836858">"यी सूचनाहरू देखाउने क्रम जारी राख्ने हो?"</string>
+ <string name="inline_stop_button" msgid="4172980096860941033">"सूचनाहरू देखाउन छाड्नुहोस्"</string>
+ <string name="inline_keep_button" msgid="6665940297019018232">"देखाउने क्रम जारी राख्नुहोस्"</string>
+ <string name="inline_keep_showing_app" msgid="1723113469580031041">"यो अनुप्रयोगका सूचनाहरू देखाउने क्रम जारी राख्ने हो?"</string>
+ <string name="notification_unblockable_desc" msgid="1037434112919403708">"यी सूचनाहरूलाई निष्क्रिय पार्न सकिँदैन"</string>
<string name="notification_channel_controls_opened_accessibility" msgid="6553950422055908113">"<xliff:g id="APP_NAME">%1$s</xliff:g> का सूचना सम्बन्धी नियन्त्रणहरूलाई खोलियो"</string>
<string name="notification_channel_controls_closed_accessibility" msgid="7521619812603693144">"<xliff:g id="APP_NAME">%1$s</xliff:g> का सूचना सम्बन्धी नियन्त्रणहरूलाई बन्द गरियो"</string>
<string name="notification_channel_switch_accessibility" msgid="3420796005601900717">"यो च्यानलका सूचनाहरूलाई अनुमति दिनुहोस्"</string>
<string name="notification_more_settings" msgid="816306283396553571">"थप सेटिङहरू"</string>
- <!-- no translation found for notification_app_settings (420348114670768449) -->
- <skip />
+ <string name="notification_app_settings" msgid="420348114670768449">"आफू अनुकूल पार्नुहोस्"</string>
<string name="notification_done" msgid="5279426047273930175">"सम्पन्‍न भयो"</string>
- <!-- no translation found for inline_undo (558916737624706010) -->
- <skip />
+ <string name="inline_undo" msgid="558916737624706010">"अन्डू गर्नुहोस्"</string>
<string name="notification_menu_accessibility" msgid="2046162834248888553">"<xliff:g id="APP_NAME">%1$s</xliff:g> <xliff:g id="MENU_DESCRIPTION">%2$s</xliff:g>"</string>
<string name="notification_menu_gear_description" msgid="2204480013726775108">"सूचना सम्बन्धी नियन्त्रणहरू"</string>
<string name="notification_menu_snooze_description" msgid="3653669438131034525">"सूचना स्नुज गर्ने विकल्पहरू"</string>
diff --git a/packages/SystemUI/res/values-nl/strings.xml b/packages/SystemUI/res/values-nl/strings.xml
index 7139a635413a..55a6cb88510e 100644
--- a/packages/SystemUI/res/values-nl/strings.xml
+++ b/packages/SystemUI/res/values-nl/strings.xml
@@ -33,7 +33,10 @@
<string name="status_bar_ongoing_events_title" msgid="1682504513316879202">"Actief"</string>
<string name="status_bar_latest_events_title" msgid="6594767438577593172">"Meldingen"</string>
<string name="battery_low_title" msgid="6456385927409742437">"Batterij is bijna leeg"</string>
+ <string name="battery_low_title_hybrid" msgid="6268991275887381595">"De batterij is bijna leeg. Schakel Batterijbesparing in."</string>
<string name="battery_low_percent_format" msgid="2900940511201380775">"<xliff:g id="PERCENTAGE">%s</xliff:g> resterend"</string>
+ <string name="battery_low_percent_format_hybrid" msgid="6838677459286775617">"<xliff:g id="PERCENTAGE">%s</xliff:g> resterend, nog ongeveer <xliff:g id="TIME">%s</xliff:g> over op basis van je gebruik"</string>
+ <string name="battery_low_percent_format_hybrid_short" msgid="9025795469949145586">"<xliff:g id="PERCENTAGE">%s</xliff:g> resterend, nog ongeveer <xliff:g id="TIME">%s</xliff:g> over"</string>
<string name="battery_low_percent_format_saver_started" msgid="7879389868952879166">"<xliff:g id="PERCENTAGE">%s</xliff:g> resterend. Batterijbesparing is ingeschakeld."</string>
<string name="invalid_charger" msgid="4549105996740522523">"Opladen via USB niet ondersteund.\nGebruik alleen de bijgeleverde oplader."</string>
<string name="invalid_charger_title" msgid="3515740382572798460">"Opladen via USB wordt niet ondersteund."</string>
@@ -67,14 +70,15 @@
<string name="usb_debugging_secondary_user_message" msgid="6067122453571699801">"De gebruiker die momenteel is ingelogd op dit apparaat, kan USB-foutopsporing niet inschakelen. Als je deze functie wilt gebruiken, schakel je naar de primaire gebruiker."</string>
<string name="compat_mode_on" msgid="6623839244840638213">"Zoom om scherm te vullen"</string>
<string name="compat_mode_off" msgid="4434467572461327898">"Rek uit v. schermvulling"</string>
+ <string name="global_action_screenshot" msgid="8329831278085426283">"Screenshot"</string>
<string name="screenshot_saving_ticker" msgid="7403652894056693515">"Screenshot opslaan..."</string>
<string name="screenshot_saving_title" msgid="8242282144535555697">"Screenshot opslaan..."</string>
- <string name="screenshot_saving_text" msgid="2419718443411738818">"Screenshot wordt opgeslagen."</string>
- <string name="screenshot_saved_title" msgid="6461865960961414961">"Screenshot gemaakt."</string>
- <string name="screenshot_saved_text" msgid="2685605830386712477">"Tik om je screenshot te bekijken."</string>
- <string name="screenshot_failed_title" msgid="705781116746922771">"Screenshot is niet gemaakt."</string>
- <string name="screenshot_failed_to_save_unknown_text" msgid="7887826345701753830">"Er is een probleem opgetreden bij het opslaan van het screenshot."</string>
- <string name="screenshot_failed_to_save_text" msgid="2592658083866306296">"Kan screenshot niet opslaan vanwege beperkte opslagruimte."</string>
+ <string name="screenshot_saving_text" msgid="2545047868936087248">"Screenshot wordt opgeslagen"</string>
+ <string name="screenshot_saved_title" msgid="5637073968117370753">"Screenshot opgeslagen"</string>
+ <string name="screenshot_saved_text" msgid="7574667448002050363">"Tik om je screenshot te bekijken"</string>
+ <string name="screenshot_failed_title" msgid="9096484883063264803">"Kan geen screenshot maken"</string>
+ <string name="screenshot_failed_to_save_unknown_text" msgid="8844781948876286488">"Er is een probleem opgetreden bij het opslaan van het screenshot"</string>
+ <string name="screenshot_failed_to_save_text" msgid="3041612585107107310">"Kan screenshot niet opslaan vanwege beperkte opslagruimte"</string>
<string name="screenshot_failed_to_capture_text" msgid="173674476457581486">"Het maken van screenshots wordt niet toegestaan door de app of je organisatie"</string>
<string name="usb_preference_title" msgid="6551050377388882787">"Opties voor USB-bestandsoverdracht"</string>
<string name="use_mtp_button_title" msgid="4333504413563023626">"Koppelen als mediaspeler (MTP)"</string>
@@ -557,26 +561,19 @@
<string name="tuner_full_importance_settings_off" msgid="8208165412614935229">"Uit"</string>
<string name="power_notification_controls_description" msgid="4372459941671353358">"Met beheeropties voor meldingen met betrekking tot stroomverbruik kun je een belangrijkheidsniveau van 0 tot 5 instellen voor de meldingen van een app. \n\n"<b>"Niveau 5"</b>" \n- Boven aan de lijst met meldingen weergeven \n- Onderbreking op volledig scherm toestaan \n- Altijd korte weergave \n\n"<b>"Niveau 4"</b>" \n- Geen onderbreking op volledig scherm \n- Altijd korte weergave \n\n"<b>"Niveau 3"</b>" \n- Geen onderbreking op volledig scherm \n- Nooit korte weergave \n\n"<b>"Niveau 2"</b>" \n- Geen onderbreking op volledig scherm \n- Nooit korte weergave \n- Nooit geluid laten horen of trillen \n\n"<b>"Niveau 1"</b>" \n- Geen onderbreking op volledig scherm \n- Nooit korte weergave \n- Nooit geluid laten horen of trillen \n- Verbergen op vergrendelingsscherm en statusbalk \n- Onder aan de lijst met meldingen weergeven \n\n"<b>"Niveau 0"</b>" \n- Alle meldingen van de app blokkeren"</string>
<string name="notification_header_default_channel" msgid="7506845022070889909">"Meldingen"</string>
- <string name="notification_channel_disabled" msgid="2139193533791840539">"Je ontvangt deze meldingen niet meer"</string>
- <string name="notification_num_channels" msgid="2048144408999179471">"<xliff:g id="NUMBER">%d</xliff:g> meldingscategorieën"</string>
- <string name="notification_default_channel_desc" msgid="2506053815870808359">"Deze app heeft geen meldingscategorieën"</string>
- <string name="notification_unblockable_desc" msgid="3561016061737896906">"Meldingen van deze app kunnen niet worden uitgeschakeld"</string>
- <plurals name="notification_num_channels_desc" formatted="false" msgid="5492793452274077663">
- <item quantity="other">1 van <xliff:g id="NUMBER_1">%s</xliff:g> meldingscategorieën van deze app</item>
- <item quantity="one">1 van <xliff:g id="NUMBER_0">%s</xliff:g> meldingscategorie van deze app</item>
- </plurals>
- <string name="notification_channels_list_desc_2" msgid="6214732715833946441">"<xliff:g id="CHANNEL_NAME_1">%1$s</xliff:g>, <xliff:g id="CHANNEL_NAME_2">%2$s</xliff:g>"</string>
- <plurals name="notification_channels_list_desc_2_and_others" formatted="false" msgid="2747813553355336157">
- <item quantity="other"><xliff:g id="CHANNEL_NAME_1_3">%1$s</xliff:g>, <xliff:g id="CHANNEL_NAME_2_4">%2$s</xliff:g> en <xliff:g id="NUMBER_5">%3$d</xliff:g> andere</item>
- <item quantity="one"><xliff:g id="CHANNEL_NAME_1_0">%1$s</xliff:g>, <xliff:g id="CHANNEL_NAME_2_1">%2$s</xliff:g> en <xliff:g id="NUMBER_2">%3$d</xliff:g> andere</item>
- </plurals>
+ <string name="notification_channel_disabled" msgid="344536703863700565">"Deze meldingen worden niet meer weergegeven"</string>
+ <string name="inline_keep_showing" msgid="8945102997083836858">"Deze meldingen blijven weergeven?"</string>
+ <string name="inline_stop_button" msgid="4172980096860941033">"Meldingen stoppen"</string>
+ <string name="inline_keep_button" msgid="6665940297019018232">"Blijven weergeven"</string>
+ <string name="inline_keep_showing_app" msgid="1723113469580031041">"Meldingen van deze app blijven weergeven?"</string>
+ <string name="notification_unblockable_desc" msgid="1037434112919403708">"Deze meldingen kunnen niet worden uitgeschakeld"</string>
<string name="notification_channel_controls_opened_accessibility" msgid="6553950422055908113">"Beheeropties voor meldingen voor <xliff:g id="APP_NAME">%1$s</xliff:g> geopend"</string>
<string name="notification_channel_controls_closed_accessibility" msgid="7521619812603693144">"Beheeropties voor meldingen voor <xliff:g id="APP_NAME">%1$s</xliff:g> gesloten"</string>
<string name="notification_channel_switch_accessibility" msgid="3420796005601900717">"Meldingen van dit kanaal toestaan"</string>
- <string name="notification_all_categories" msgid="5407190218055113282">"Alle categorieën"</string>
<string name="notification_more_settings" msgid="816306283396553571">"Meer instellingen"</string>
- <string name="notification_app_settings" msgid="3743278649182392015">"Aanpassen: <xliff:g id="SUB_CATEGORY">%1$s</xliff:g>"</string>
+ <string name="notification_app_settings" msgid="420348114670768449">"Aanpassen"</string>
<string name="notification_done" msgid="5279426047273930175">"Gereed"</string>
+ <string name="inline_undo" msgid="558916737624706010">"Ongedaan maken"</string>
<string name="notification_menu_accessibility" msgid="2046162834248888553">"<xliff:g id="APP_NAME">%1$s</xliff:g> <xliff:g id="MENU_DESCRIPTION">%2$s</xliff:g>"</string>
<string name="notification_menu_gear_description" msgid="2204480013726775108">"beheeropties voor meldingen"</string>
<string name="notification_menu_snooze_description" msgid="3653669438131034525">"snooze-opties voor meldingen"</string>
@@ -731,8 +728,7 @@
<string name="pip_phone_expand" msgid="5889780005575693909">"Uitvouwen"</string>
<string name="pip_phone_minimize" msgid="1079119422589131792">"Minimaliseren"</string>
<string name="pip_phone_close" msgid="8416647892889710330">"Sluiten"</string>
- <!-- no translation found for pip_phone_settings (8080777499521528521) -->
- <skip />
+ <string name="pip_phone_settings" msgid="8080777499521528521">"Instellingen"</string>
<string name="pip_phone_dismiss_hint" msgid="6351678169095923899">"Sleep omlaag om te sluiten"</string>
<string name="pip_menu_title" msgid="4707292089961887657">"Menu"</string>
<string name="pip_notification_title" msgid="3204024940158161322">"<xliff:g id="NAME">%s</xliff:g> is in scherm-in-scherm"</string>
diff --git a/packages/SystemUI/res/values-pl/strings.xml b/packages/SystemUI/res/values-pl/strings.xml
index 4c385b7235f0..0c4b71eafc3f 100644
--- a/packages/SystemUI/res/values-pl/strings.xml
+++ b/packages/SystemUI/res/values-pl/strings.xml
@@ -35,7 +35,10 @@
<string name="status_bar_ongoing_events_title" msgid="1682504513316879202">"Bieżące"</string>
<string name="status_bar_latest_events_title" msgid="6594767438577593172">"Powiadomienia"</string>
<string name="battery_low_title" msgid="6456385927409742437">"Niski poziom baterii"</string>
+ <string name="battery_low_title_hybrid" msgid="6268991275887381595">"Niski poziom naładowania baterii. Włącz Oszczędzanie baterii"</string>
<string name="battery_low_percent_format" msgid="2900940511201380775">"Pozostało <xliff:g id="PERCENTAGE">%s</xliff:g>"</string>
+ <string name="battery_low_percent_format_hybrid" msgid="6838677459286775617">"Pozostało <xliff:g id="PERCENTAGE">%s</xliff:g>, jeszcze około <xliff:g id="TIME">%s</xliff:g> (na podstawie Twojego sposobu korzystania)"</string>
+ <string name="battery_low_percent_format_hybrid_short" msgid="9025795469949145586">"Pozostało <xliff:g id="PERCENTAGE">%s</xliff:g>, jeszcze około <xliff:g id="TIME">%s</xliff:g>"</string>
<string name="battery_low_percent_format_saver_started" msgid="7879389868952879166">"Pozostało <xliff:g id="PERCENTAGE">%s</xliff:g>. Oszczędzanie baterii jest włączone."</string>
<string name="invalid_charger" msgid="4549105996740522523">"Ładowanie przy użyciu złącza USB nie jest obsługiwane.\nNależy używać tylko dołączonej ładowarki."</string>
<string name="invalid_charger_title" msgid="3515740382572798460">"Ładowanie przez USB nie jest obsługiwane."</string>
@@ -69,14 +72,15 @@
<string name="usb_debugging_secondary_user_message" msgid="6067122453571699801">"Użytkownik obecnie zalogowany na tym urządzeniu nie może włączyć debugowania USB. Aby użyć tej funkcji, przełącz się na użytkownika głównego."</string>
<string name="compat_mode_on" msgid="6623839244840638213">"Powiększ, aby wypełnić ekran"</string>
<string name="compat_mode_off" msgid="4434467572461327898">"Rozciągnij, aby wypełnić ekran"</string>
+ <string name="global_action_screenshot" msgid="8329831278085426283">"Zrzut ekranu"</string>
<string name="screenshot_saving_ticker" msgid="7403652894056693515">"Zapisywanie zrzutu ekranu..."</string>
<string name="screenshot_saving_title" msgid="8242282144535555697">"Zapisywanie zrzutu ekranu..."</string>
- <string name="screenshot_saving_text" msgid="2419718443411738818">"Zapisywanie zrzutu ekranu."</string>
- <string name="screenshot_saved_title" msgid="6461865960961414961">"Wykonano zrzut ekranu."</string>
- <string name="screenshot_saved_text" msgid="2685605830386712477">"Kliknij, by zobaczyć zrzut ekranu."</string>
- <string name="screenshot_failed_title" msgid="705781116746922771">"Nie udało się wykonać zrzutu ekranu."</string>
- <string name="screenshot_failed_to_save_unknown_text" msgid="7887826345701753830">"Podczas zapisywania zrzutu ekranu wystąpił błąd."</string>
- <string name="screenshot_failed_to_save_text" msgid="2592658083866306296">"Nie można zapisać zrzutu ekranu, bo brakuje miejsca w pamięci."</string>
+ <string name="screenshot_saving_text" msgid="2545047868936087248">"Zapisywanie zrzutu ekranu"</string>
+ <string name="screenshot_saved_title" msgid="5637073968117370753">"Zrzut ekranu został zapisany"</string>
+ <string name="screenshot_saved_text" msgid="7574667448002050363">"Kliknij, by zobaczyć zrzut ekranu"</string>
+ <string name="screenshot_failed_title" msgid="9096484883063264803">"Nie udało się wykonać zrzutu ekranu"</string>
+ <string name="screenshot_failed_to_save_unknown_text" msgid="8844781948876286488">"Podczas zapisywania zrzutu ekranu wystąpił błąd"</string>
+ <string name="screenshot_failed_to_save_text" msgid="3041612585107107310">"Nie można zapisać zrzutu ekranu, bo brakuje miejsca w pamięci"</string>
<string name="screenshot_failed_to_capture_text" msgid="173674476457581486">"Nie możesz wykonać zrzutu ekranu, bo nie zezwala na to aplikacja lub Twoja organizacja."</string>
<string name="usb_preference_title" msgid="6551050377388882787">"USB – opcje przesyłania plików"</string>
<string name="use_mtp_button_title" msgid="4333504413563023626">"Podłącz jako odtwarzacz multimedialny (MTP)"</string>
@@ -561,30 +565,19 @@
<string name="tuner_full_importance_settings_off" msgid="8208165412614935229">"Wył."</string>
<string name="power_notification_controls_description" msgid="4372459941671353358">"Dzięki zaawansowanym ustawieniom możesz określić poziom ważności powiadomień z aplikacji w skali od 0 do 5. \n\n"<b>"Poziom 5"</b>" \n– Pokazuj u góry listy powiadomień \n– Zezwalaj na powiadomienia na pełnym ekranie \n– Zawsze pokazuj podgląd \n\n"<b>"Poziom 4"</b>" \n– Wyłącz powiadomienia na pełnym ekranie \n– Zawsze pokazuj podgląd \n\n"<b>"Poziom 3"</b>" \n– Wyłącz powiadomienia na pełnym ekranie \n– Nigdy nie pokazuj podglądu \n\n"<b>"Poziom 2"</b>" \n– Wyłącz powiadomienia na pełnym ekranie \n– Nigdy nie pokazuj podglądu \n– NIgdy nie powiadamiaj dźwiękiem ani wibracjami \n\n"<b>"Poziom 1"</b>" \n– Wyłącz powiadomienia na pełnym ekranie \n– Nigdy nie pokazuj podglądu \n– NIgdy nie powiadamiaj dźwiękiem ani wibracjami \n– Ukrywaj na ekranie blokady i pasku stanu \n– Pokazuj u dołu listy powiadomień \n\n"<b>"Poziom 0"</b>" \n– Blokuj wszystkie powiadomienia aplikacji"</string>
<string name="notification_header_default_channel" msgid="7506845022070889909">"Powiadomienia"</string>
- <string name="notification_channel_disabled" msgid="2139193533791840539">"Nie będziesz już otrzymywać tych powiadomień"</string>
- <string name="notification_num_channels" msgid="2048144408999179471">"Kategorie powiadomień: <xliff:g id="NUMBER">%d</xliff:g>"</string>
- <string name="notification_default_channel_desc" msgid="2506053815870808359">"Ta aplikacja nie ma kategorii powiadomień"</string>
- <string name="notification_unblockable_desc" msgid="3561016061737896906">"Powiadomień z tej aplikacji nie można wyłączyć"</string>
- <plurals name="notification_num_channels_desc" formatted="false" msgid="5492793452274077663">
- <item quantity="few">1 z <xliff:g id="NUMBER_1">%s</xliff:g> kategorii powiadomień z tej aplikacji</item>
- <item quantity="many">1 z <xliff:g id="NUMBER_1">%s</xliff:g> kategorii powiadomień z tej aplikacji</item>
- <item quantity="other">1 z <xliff:g id="NUMBER_1">%s</xliff:g> kategorii powiadomień z tej aplikacji</item>
- <item quantity="one">1 z <xliff:g id="NUMBER_0">%s</xliff:g> kategorii powiadomień z tej aplikacji</item>
- </plurals>
- <string name="notification_channels_list_desc_2" msgid="6214732715833946441">"<xliff:g id="CHANNEL_NAME_1">%1$s</xliff:g>, <xliff:g id="CHANNEL_NAME_2">%2$s</xliff:g>"</string>
- <plurals name="notification_channels_list_desc_2_and_others" formatted="false" msgid="2747813553355336157">
- <item quantity="few"><xliff:g id="CHANNEL_NAME_1_3">%1$s</xliff:g>, <xliff:g id="CHANNEL_NAME_2_4">%2$s</xliff:g> i <xliff:g id="NUMBER_5">%3$d</xliff:g> inne</item>
- <item quantity="many"><xliff:g id="CHANNEL_NAME_1_3">%1$s</xliff:g>, <xliff:g id="CHANNEL_NAME_2_4">%2$s</xliff:g> i <xliff:g id="NUMBER_5">%3$d</xliff:g> innych</item>
- <item quantity="other"><xliff:g id="CHANNEL_NAME_1_3">%1$s</xliff:g>, <xliff:g id="CHANNEL_NAME_2_4">%2$s</xliff:g> i <xliff:g id="NUMBER_5">%3$d</xliff:g> innego</item>
- <item quantity="one"><xliff:g id="CHANNEL_NAME_1_0">%1$s</xliff:g>, <xliff:g id="CHANNEL_NAME_2_1">%2$s</xliff:g> i <xliff:g id="NUMBER_2">%3$d</xliff:g> inny</item>
- </plurals>
+ <string name="notification_channel_disabled" msgid="344536703863700565">"Te powiadomienia nie będą już wyświetlane"</string>
+ <string name="inline_keep_showing" msgid="8945102997083836858">"Nadal pokazywać te powiadomienia?"</string>
+ <string name="inline_stop_button" msgid="4172980096860941033">"Zatrzymaj powiadomienia"</string>
+ <string name="inline_keep_button" msgid="6665940297019018232">"Pokazuj nadal"</string>
+ <string name="inline_keep_showing_app" msgid="1723113469580031041">"Nadal pokazywać powiadomienia z tej aplikacji?"</string>
+ <string name="notification_unblockable_desc" msgid="1037434112919403708">"Tych powiadomień nie można wyłączyć"</string>
<string name="notification_channel_controls_opened_accessibility" msgid="6553950422055908113">"Sterowanie powiadomieniami aplikacji <xliff:g id="APP_NAME">%1$s</xliff:g> otwarte"</string>
<string name="notification_channel_controls_closed_accessibility" msgid="7521619812603693144">"Sterowanie powiadomieniami aplikacji <xliff:g id="APP_NAME">%1$s</xliff:g> zamknięte"</string>
<string name="notification_channel_switch_accessibility" msgid="3420796005601900717">"Zezwól na powiadomienia z tego kanału"</string>
- <string name="notification_all_categories" msgid="5407190218055113282">"Wszystkie kategorie"</string>
<string name="notification_more_settings" msgid="816306283396553571">"Więcej ustawień"</string>
- <string name="notification_app_settings" msgid="3743278649182392015">"Dostosuj: <xliff:g id="SUB_CATEGORY">%1$s</xliff:g>"</string>
+ <string name="notification_app_settings" msgid="420348114670768449">"Dostosuj"</string>
<string name="notification_done" msgid="5279426047273930175">"Gotowe"</string>
+ <string name="inline_undo" msgid="558916737624706010">"Cofnij"</string>
<string name="notification_menu_accessibility" msgid="2046162834248888553">"<xliff:g id="APP_NAME">%1$s</xliff:g> <xliff:g id="MENU_DESCRIPTION">%2$s</xliff:g>"</string>
<string name="notification_menu_gear_description" msgid="2204480013726775108">"sterowanie powiadomieniami"</string>
<string name="notification_menu_snooze_description" msgid="3653669438131034525">"opcje odkładania powiadomień"</string>
@@ -743,8 +736,7 @@
<string name="pip_phone_expand" msgid="5889780005575693909">"Rozwiń"</string>
<string name="pip_phone_minimize" msgid="1079119422589131792">"Minimalizuj"</string>
<string name="pip_phone_close" msgid="8416647892889710330">"Zamknij"</string>
- <!-- no translation found for pip_phone_settings (8080777499521528521) -->
- <skip />
+ <string name="pip_phone_settings" msgid="8080777499521528521">"Ustawienia"</string>
<string name="pip_phone_dismiss_hint" msgid="6351678169095923899">"Przeciągnij w dół, by zamknąć"</string>
<string name="pip_menu_title" msgid="4707292089961887657">"Menu"</string>
<string name="pip_notification_title" msgid="3204024940158161322">"Aplikacja <xliff:g id="NAME">%s</xliff:g> działa w trybie obraz w obrazie"</string>
diff --git a/packages/SystemUI/res/values-sk/strings.xml b/packages/SystemUI/res/values-sk/strings.xml
index 49415a5854ef..618c95013af9 100644
--- a/packages/SystemUI/res/values-sk/strings.xml
+++ b/packages/SystemUI/res/values-sk/strings.xml
@@ -35,7 +35,10 @@
<string name="status_bar_ongoing_events_title" msgid="1682504513316879202">"Prebiehajúce"</string>
<string name="status_bar_latest_events_title" msgid="6594767438577593172">"Upozornenia"</string>
<string name="battery_low_title" msgid="6456385927409742437">"Batéria je takmer vybitá"</string>
+ <string name="battery_low_title_hybrid" msgid="6268991275887381595">"Batéria je takmer vybitá. Zapnite Šetrič batérie."</string>
<string name="battery_low_percent_format" msgid="2900940511201380775">"Zostáva <xliff:g id="PERCENTAGE">%s</xliff:g>"</string>
+ <string name="battery_low_percent_format_hybrid" msgid="6838677459286775617">"Zostáva <xliff:g id="PERCENTAGE">%s</xliff:g>, približne <xliff:g id="TIME">%s</xliff:g> v závislosti od intenzity využitia"</string>
+ <string name="battery_low_percent_format_hybrid_short" msgid="9025795469949145586">"Zostáva <xliff:g id="PERCENTAGE">%s</xliff:g>, približne <xliff:g id="TIME">%s</xliff:g>"</string>
<string name="battery_low_percent_format_saver_started" msgid="7879389868952879166">"Zostáva: <xliff:g id="PERCENTAGE">%s</xliff:g>. Šetrič batérie je zapnutý."</string>
<string name="invalid_charger" msgid="4549105996740522523">"Nabíjanie pomocou rozhrania USB nie je podporované.\nPoužívajte iba nabíjačku, ktorá bola dodaná spolu so zariadením."</string>
<string name="invalid_charger_title" msgid="3515740382572798460">"Nabíjanie prostredníctvom USB nie je podporované."</string>
@@ -69,14 +72,15 @@
<string name="usb_debugging_secondary_user_message" msgid="6067122453571699801">"Používateľ, ktorý je práve prihlásený v tomto zariadení, nemôže zapnúť ladenie USB. Ak chcete použiť túto funkciu, prepnite na hlavného používateľa."</string>
<string name="compat_mode_on" msgid="6623839244840638213">"Priblížiť na celú obrazovku"</string>
<string name="compat_mode_off" msgid="4434467572461327898">"Na celú obrazovku"</string>
+ <string name="global_action_screenshot" msgid="8329831278085426283">"Snímka obrazovky"</string>
<string name="screenshot_saving_ticker" msgid="7403652894056693515">"Prebieha ukladanie snímky obrazovky..."</string>
<string name="screenshot_saving_title" msgid="8242282144535555697">"Prebieha ukladanie snímky obrazovky..."</string>
- <string name="screenshot_saving_text" msgid="2419718443411738818">"Snímka obrazovky sa ukladá."</string>
- <string name="screenshot_saved_title" msgid="6461865960961414961">"Snímka obrazovky bola zaznamenaná."</string>
- <string name="screenshot_saved_text" msgid="2685605830386712477">"Klepnutím zobrazíte snímku obrazovky."</string>
- <string name="screenshot_failed_title" msgid="705781116746922771">"Snímku obrazovky sa nepodarilo zachytiť."</string>
- <string name="screenshot_failed_to_save_unknown_text" msgid="7887826345701753830">"Pri ukladaní snímky obrazovky sa vyskytol problém."</string>
- <string name="screenshot_failed_to_save_text" msgid="2592658083866306296">"Snímku obrazovky nie je možné vytvoriť z dôvodu nedostatku miesta v úložisku."</string>
+ <string name="screenshot_saving_text" msgid="2545047868936087248">"Ukladá sa snímka obrazovky"</string>
+ <string name="screenshot_saved_title" msgid="5637073968117370753">"Snímka obrazovky bola uložená"</string>
+ <string name="screenshot_saved_text" msgid="7574667448002050363">"Klepnutím zobrazíte snímku obrazovky"</string>
+ <string name="screenshot_failed_title" msgid="9096484883063264803">"Snímku obrazovky sa nepodarilo zachytiť"</string>
+ <string name="screenshot_failed_to_save_unknown_text" msgid="8844781948876286488">"Pri ukladaní snímky obrazovky sa vyskytol problém"</string>
+ <string name="screenshot_failed_to_save_text" msgid="3041612585107107310">"Snímka obrazovky sa nedá uložiť z dôvodu nedostatku miesta v úložisku"</string>
<string name="screenshot_failed_to_capture_text" msgid="173674476457581486">"Vytváranie snímok obrazovky je zakázané aplikáciou alebo vašou organizáciou"</string>
<string name="usb_preference_title" msgid="6551050377388882787">"Možnosti prenosu súborov USB"</string>
<string name="use_mtp_button_title" msgid="4333504413563023626">"Pripojiť ako prehrávač médií (MTP)"</string>
@@ -563,30 +567,19 @@
<string name="tuner_full_importance_settings_off" msgid="8208165412614935229">"Vypnuté"</string>
<string name="power_notification_controls_description" msgid="4372459941671353358">"Pomocou ovládacích prvkov zobrazovania upozornení môžete nastaviť pre upozornenia aplikácie úroveň dôležitosti od 0 do 5. \n\n"<b>"Úroveň 5"</b>" \n– Zobrazovať v hornej časti zoznamu upozornení. \n– Povoliť prerušenia na celú obrazovku. \n– Vždy zobrazovať čiastočne. \n\n"<b>"Úroveň 4"</b>" \n– Zabrániť prerušeniam na celú obrazovku. \n– Vždy zobrazovať čiastočne. \n\n"<b>"Úroveň 3"</b>" \n– Zabrániť prerušeniam na celú obrazovku. \n– Nikdy nezobrazovať čiastočne. \n\n"<b>"Úroveň 2"</b>" \n– Zabrániť prerušeniam na celú obrazovku. \n– Nikdy nezobrazovať čiastočne. \n– Nikdy nespúšťať zvuk ani vibrácie. \n\n"<b>"Úroveň 1"</b>" \n– Zabrániť prerušeniam na celú obrazovku. \n– Nikdy nezobrazovať čiastočne. \n– Nikdy nespúšťať zvuk ani vibrácie. \n– Skryť na uzamknutej obrazovke a v stavovom riadku. \n– Zobraziť v dolnej časti zoznamu upozornení. \n\n"<b>"Úroveň 0"</b>" \n– Blokovať všetky upozornenia z aplikácie."</string>
<string name="notification_header_default_channel" msgid="7506845022070889909">"Upozornenia"</string>
- <string name="notification_channel_disabled" msgid="2139193533791840539">"Tieto upozornenia už nebudete dostávať"</string>
- <string name="notification_num_channels" msgid="2048144408999179471">"Počet kategórií upozornení: <xliff:g id="NUMBER">%d</xliff:g>"</string>
- <string name="notification_default_channel_desc" msgid="2506053815870808359">"Táto aplikácia nemá kategórie upozornení"</string>
- <string name="notification_unblockable_desc" msgid="3561016061737896906">"Upozornenia z tejto aplikácie sa nedajú vypnúť"</string>
- <plurals name="notification_num_channels_desc" formatted="false" msgid="5492793452274077663">
- <item quantity="few">1 z <xliff:g id="NUMBER_1">%s</xliff:g> kategórií upozornení z tejto aplikácie</item>
- <item quantity="many">1 z <xliff:g id="NUMBER_1">%s</xliff:g> kategórie upozornení z tejto aplikácie</item>
- <item quantity="other">1 z <xliff:g id="NUMBER_1">%s</xliff:g> kategórií upozornení z tejto aplikácie</item>
- <item quantity="one">1 z <xliff:g id="NUMBER_0">%s</xliff:g> kategórie upozornení z tejto aplikácie</item>
- </plurals>
- <string name="notification_channels_list_desc_2" msgid="6214732715833946441">"<xliff:g id="CHANNEL_NAME_1">%1$s</xliff:g>, <xliff:g id="CHANNEL_NAME_2">%2$s</xliff:g>"</string>
- <plurals name="notification_channels_list_desc_2_and_others" formatted="false" msgid="2747813553355336157">
- <item quantity="few"><xliff:g id="CHANNEL_NAME_1_3">%1$s</xliff:g>, <xliff:g id="CHANNEL_NAME_2_4">%2$s</xliff:g> a <xliff:g id="NUMBER_5">%3$d</xliff:g> ďalšie</item>
- <item quantity="many"><xliff:g id="CHANNEL_NAME_1_3">%1$s</xliff:g>, <xliff:g id="CHANNEL_NAME_2_4">%2$s</xliff:g> a <xliff:g id="NUMBER_5">%3$d</xliff:g> ďalšieho</item>
- <item quantity="other"><xliff:g id="CHANNEL_NAME_1_3">%1$s</xliff:g>, <xliff:g id="CHANNEL_NAME_2_4">%2$s</xliff:g> a <xliff:g id="NUMBER_5">%3$d</xliff:g> ďalších</item>
- <item quantity="one"><xliff:g id="CHANNEL_NAME_1_0">%1$s</xliff:g>, <xliff:g id="CHANNEL_NAME_2_1">%2$s</xliff:g> a <xliff:g id="NUMBER_2">%3$d</xliff:g> ďalší</item>
- </plurals>
+ <string name="notification_channel_disabled" msgid="344536703863700565">"Tieto upozornenia sa už nebudú zobrazovať"</string>
+ <string name="inline_keep_showing" msgid="8945102997083836858">"Majú sa tieto upozornenia naďalej zobrazovať?"</string>
+ <string name="inline_stop_button" msgid="4172980096860941033">"Prestať zobrazovať upozornenia"</string>
+ <string name="inline_keep_button" msgid="6665940297019018232">"Naďalej zobrazovať"</string>
+ <string name="inline_keep_showing_app" msgid="1723113469580031041">"Majú sa upozornenia z tejto aplikácie naďalej zobrazovať?"</string>
+ <string name="notification_unblockable_desc" msgid="1037434112919403708">"Tieto upozornenia sa nedajú vypnúť"</string>
<string name="notification_channel_controls_opened_accessibility" msgid="6553950422055908113">"Ovládanie upozornení pre aplikáciu <xliff:g id="APP_NAME">%1$s</xliff:g> je otvorené"</string>
<string name="notification_channel_controls_closed_accessibility" msgid="7521619812603693144">"Ovládanie upozornení pre aplikáciu <xliff:g id="APP_NAME">%1$s</xliff:g> je zatvorené"</string>
<string name="notification_channel_switch_accessibility" msgid="3420796005601900717">"Povoliť upozornenia z tohto kanála"</string>
- <string name="notification_all_categories" msgid="5407190218055113282">"Všetky kategórie"</string>
<string name="notification_more_settings" msgid="816306283396553571">"Ďalšie nastavenia"</string>
- <string name="notification_app_settings" msgid="3743278649182392015">"Prispôsobiť: <xliff:g id="SUB_CATEGORY">%1$s</xliff:g>"</string>
+ <string name="notification_app_settings" msgid="420348114670768449">"Prispôsobiť"</string>
<string name="notification_done" msgid="5279426047273930175">"Hotovo"</string>
+ <string name="inline_undo" msgid="558916737624706010">"Späť"</string>
<string name="notification_menu_accessibility" msgid="2046162834248888553">"<xliff:g id="APP_NAME">%1$s</xliff:g> <xliff:g id="MENU_DESCRIPTION">%2$s</xliff:g>"</string>
<string name="notification_menu_gear_description" msgid="2204480013726775108">"ovládacie prvky pre upozornenia"</string>
<string name="notification_menu_snooze_description" msgid="3653669438131034525">"možnosti stlmenia upozornení"</string>
@@ -745,8 +738,7 @@
<string name="pip_phone_expand" msgid="5889780005575693909">"Rozbaliť"</string>
<string name="pip_phone_minimize" msgid="1079119422589131792">"Minimalizovať"</string>
<string name="pip_phone_close" msgid="8416647892889710330">"Zavrieť"</string>
- <!-- no translation found for pip_phone_settings (8080777499521528521) -->
- <skip />
+ <string name="pip_phone_settings" msgid="8080777499521528521">"Nastavenia"</string>
<string name="pip_phone_dismiss_hint" msgid="6351678169095923899">"Zrušíte presunutím nadol"</string>
<string name="pip_menu_title" msgid="4707292089961887657">"Ponuka"</string>
<string name="pip_notification_title" msgid="3204024940158161322">"<xliff:g id="NAME">%s</xliff:g> je v režime obraz v obraze"</string>
diff --git a/packages/SystemUI/res/values-sq/strings.xml b/packages/SystemUI/res/values-sq/strings.xml
index 2d1591f0f0ed..61f1c86ccba1 100644
--- a/packages/SystemUI/res/values-sq/strings.xml
+++ b/packages/SystemUI/res/values-sq/strings.xml
@@ -33,7 +33,10 @@
<string name="status_bar_ongoing_events_title" msgid="1682504513316879202">"Në vazhdim"</string>
<string name="status_bar_latest_events_title" msgid="6594767438577593172">"Njoftimet"</string>
<string name="battery_low_title" msgid="6456385927409742437">"Niveli i baterisë është i ulët"</string>
+ <string name="battery_low_title_hybrid" msgid="6268991275887381595">"Niveli i baterisë është i ulët. Aktivizo \"Kursyesin e baterisë\""</string>
<string name="battery_low_percent_format" msgid="2900940511201380775">"Ka mbetur edhe <xliff:g id="PERCENTAGE">%s</xliff:g>"</string>
+ <string name="battery_low_percent_format_hybrid" msgid="6838677459286775617">"<xliff:g id="PERCENTAGE">%s</xliff:g> të mbetura, rreth <xliff:g id="TIME">%s</xliff:g> të mbetura bazuar në përdorimin tënd"</string>
+ <string name="battery_low_percent_format_hybrid_short" msgid="9025795469949145586">"<xliff:g id="PERCENTAGE">%s</xliff:g> të mbetura, rreth <xliff:g id="TIME">%s</xliff:g> të mbetura"</string>
<string name="battery_low_percent_format_saver_started" msgid="7879389868952879166">"Ka mbetur edhe <xliff:g id="PERCENTAGE">%s</xliff:g>. \"Kursyesi i baterisë\" është i aktivizuar."</string>
<string name="invalid_charger" msgid="4549105996740522523">"Ngarkuesi USB nuk mbështetet.\nPërdor vetëm ngarkuesin e dhënë."</string>
<string name="invalid_charger_title" msgid="3515740382572798460">"Ngarkimi i USB-së nuk mbështetet."</string>
@@ -67,14 +70,15 @@
<string name="usb_debugging_secondary_user_message" msgid="6067122453571699801">"Përdoruesi i identifikuar aktualisht në këtë pajisje nuk mund ta aktivizojë korrigjimin e USB-së. Për ta përdorur këtë funksion, kalo te përdoruesi parësor."</string>
<string name="compat_mode_on" msgid="6623839244840638213">"Zmadho për të mbushur ekranin"</string>
<string name="compat_mode_off" msgid="4434467572461327898">"Shtrije për të mbushur ekranin"</string>
+ <string name="global_action_screenshot" msgid="8329831278085426283">"Pamja e ekranit"</string>
<string name="screenshot_saving_ticker" msgid="7403652894056693515">"Po ruan pamjen e ekranit..."</string>
<string name="screenshot_saving_title" msgid="8242282144535555697">"Po ruan pamjen e ekranit…"</string>
- <string name="screenshot_saving_text" msgid="2419718443411738818">"Pamja e ekranit po ruhet."</string>
- <string name="screenshot_saved_title" msgid="6461865960961414961">"Pamja e ekranit u kap."</string>
- <string name="screenshot_saved_text" msgid="2685605830386712477">"Trokit për të parë pamjen e ekranit."</string>
- <string name="screenshot_failed_title" msgid="705781116746922771">"Nuk mundi të kapte pamjen e ekranit."</string>
- <string name="screenshot_failed_to_save_unknown_text" msgid="7887826345701753830">"U has problem gjatë ruajtjes së pamjes së ekranit."</string>
- <string name="screenshot_failed_to_save_text" msgid="2592658083866306296">"Pamja e ekranit nuk mund të ruhet për shkak të hapësirës ruajtëse të kufizuar."</string>
+ <string name="screenshot_saving_text" msgid="2545047868936087248">"Pamja e ekranit po ruhet"</string>
+ <string name="screenshot_saved_title" msgid="5637073968117370753">"Pamja e ekranit u ruajt"</string>
+ <string name="screenshot_saved_text" msgid="7574667448002050363">"Trokit për të parë pamjen e ekranit"</string>
+ <string name="screenshot_failed_title" msgid="9096484883063264803">"Pamja e ekranit nuk mund të regjistrohej"</string>
+ <string name="screenshot_failed_to_save_unknown_text" msgid="8844781948876286488">"U ndesh një problem gjatë ruajtjes së pamjes së ekranit"</string>
+ <string name="screenshot_failed_to_save_text" msgid="3041612585107107310">"Pamja e ekranit nuk mund të ruhet për shkak të hapësirës ruajtëse të kufizuar"</string>
<string name="screenshot_failed_to_capture_text" msgid="173674476457581486">"Nxjerrja e pamjeve të ekranit nuk lejohet nga aplikacioni ose organizata jote."</string>
<string name="usb_preference_title" msgid="6551050377388882787">"Opsionet e transferimit të dosjeve të USB-së"</string>
<string name="use_mtp_button_title" msgid="4333504413563023626">"Lidh si një lexues \"media\" (MTP)"</string>
@@ -557,26 +561,19 @@
<string name="tuner_full_importance_settings_off" msgid="8208165412614935229">"Joaktiv"</string>
<string name="power_notification_controls_description" msgid="4372459941671353358">"Me kontrollet e njoftimit të energjisë, mund të caktosh një nivel rëndësie nga 0 në 5 për njoftimet e një aplikacioni. \n\n"<b>"Niveli 5"</b>" \n- Shfaq në krye të listës së njoftimeve \n- Lejo ndërprerjen e ekranit të plotë \n- Gjithmonë shfaq shpejt \n\n"<b>"Niveli 4"</b>" \n- Parandalo ndërprerjen e ekranit të plotë \n- Gijthmonë shfaq shpejt \n\n"<b>"Niveli 3"</b>" \n- Parandalo ndërprerjen e ekranit të plotë \n- Asnjëherë mos shfaq shpejt \n\n"<b>"Niveli 2"</b>" \n- Parandalo ndërprerjen e ekranit të plotë \n- Asnjëherë mos shfaq shpejt \n- Asnjëherë mos lësho tingull dhe dridhje \n\n"<b>"Niveli 1"</b>" \n- Parandalo ndërprerjen e ekranit të plotë \n- Asnjëherë mos shfaq shpejt \n- Asnjëherë mos lësho tingull ose dridhje \n- Fshih nga ekrani i kyçjes dhe shiriti i statusit \n- Shfaq në fund të listës së njoftimeve \n\n"<b>"Niveli 0"</b>" \n- Blloko të gjitha njoftimet nga aplikacioni"</string>
<string name="notification_header_default_channel" msgid="7506845022070889909">"Njoftime"</string>
- <string name="notification_channel_disabled" msgid="2139193533791840539">"Këto njoftime nuk do t\'i marrësh më"</string>
- <string name="notification_num_channels" msgid="2048144408999179471">"<xliff:g id="NUMBER">%d</xliff:g> kategori njoftimesh"</string>
- <string name="notification_default_channel_desc" msgid="2506053815870808359">"Ky aplikacion nuk ka kategori njoftimesh"</string>
- <string name="notification_unblockable_desc" msgid="3561016061737896906">"Njoftimet nga ky aplikacion nuk mund të çaktivizohen"</string>
- <plurals name="notification_num_channels_desc" formatted="false" msgid="5492793452274077663">
- <item quantity="other">1 nga <xliff:g id="NUMBER_1">%s</xliff:g> kategori njoftimi nga ky aplikacion</item>
- <item quantity="one">1 nga <xliff:g id="NUMBER_0">%s</xliff:g> kategori njoftimi nga ky aplikacion</item>
- </plurals>
- <string name="notification_channels_list_desc_2" msgid="6214732715833946441">"<xliff:g id="CHANNEL_NAME_1">%1$s</xliff:g>, <xliff:g id="CHANNEL_NAME_2">%2$s</xliff:g>"</string>
- <plurals name="notification_channels_list_desc_2_and_others" formatted="false" msgid="2747813553355336157">
- <item quantity="other"><xliff:g id="CHANNEL_NAME_1_3">%1$s</xliff:g>, <xliff:g id="CHANNEL_NAME_2_4">%2$s</xliff:g> dhe <xliff:g id="NUMBER_5">%3$d</xliff:g> të tjerë</item>
- <item quantity="one"><xliff:g id="CHANNEL_NAME_1_0">%1$s</xliff:g>, <xliff:g id="CHANNEL_NAME_2_1">%2$s</xliff:g> dhe <xliff:g id="NUMBER_2">%3$d</xliff:g> të tjerë</item>
- </plurals>
+ <string name="notification_channel_disabled" msgid="344536703863700565">"Nuk do t\'i shikosh më këto njoftime"</string>
+ <string name="inline_keep_showing" msgid="8945102997083836858">"Do të vazhdosh t\'i shfaqësh këto njoftime?"</string>
+ <string name="inline_stop_button" msgid="4172980096860941033">"Ndalo njoftimet"</string>
+ <string name="inline_keep_button" msgid="6665940297019018232">"Vazhdo të shfaqësh"</string>
+ <string name="inline_keep_showing_app" msgid="1723113469580031041">"Do të vazhdosh t\'i shfaqësh njoftimet nga ky aplikacion?"</string>
+ <string name="notification_unblockable_desc" msgid="1037434112919403708">"Këto njoftime nuk mund të çaktivizohen"</string>
<string name="notification_channel_controls_opened_accessibility" msgid="6553950422055908113">"Kontrollet e njoftimeve për <xliff:g id="APP_NAME">%1$s</xliff:g> janë hapur"</string>
<string name="notification_channel_controls_closed_accessibility" msgid="7521619812603693144">"Kontrollet e njoftimeve për <xliff:g id="APP_NAME">%1$s</xliff:g> janë mbyllur"</string>
<string name="notification_channel_switch_accessibility" msgid="3420796005601900717">"Lejo njoftimet nga ky kanal"</string>
- <string name="notification_all_categories" msgid="5407190218055113282">"Të gjitha kategoritë"</string>
<string name="notification_more_settings" msgid="816306283396553571">"Cilësime të tjera"</string>
- <string name="notification_app_settings" msgid="3743278649182392015">"Peresonalizoje: <xliff:g id="SUB_CATEGORY">%1$s</xliff:g>"</string>
+ <string name="notification_app_settings" msgid="420348114670768449">"Personalizo"</string>
<string name="notification_done" msgid="5279426047273930175">"U krye"</string>
+ <string name="inline_undo" msgid="558916737624706010">"Zhbëj"</string>
<string name="notification_menu_accessibility" msgid="2046162834248888553">"<xliff:g id="APP_NAME">%1$s</xliff:g> <xliff:g id="MENU_DESCRIPTION">%2$s</xliff:g>"</string>
<string name="notification_menu_gear_description" msgid="2204480013726775108">"kontrollet e njoftimit"</string>
<string name="notification_menu_snooze_description" msgid="3653669438131034525">"opsionet e shtyrjes së njoftimit"</string>
@@ -731,8 +728,7 @@
<string name="pip_phone_expand" msgid="5889780005575693909">"Zgjero"</string>
<string name="pip_phone_minimize" msgid="1079119422589131792">"Minimizo"</string>
<string name="pip_phone_close" msgid="8416647892889710330">"Mbyll"</string>
- <!-- no translation found for pip_phone_settings (8080777499521528521) -->
- <skip />
+ <string name="pip_phone_settings" msgid="8080777499521528521">"Cilësimet"</string>
<string name="pip_phone_dismiss_hint" msgid="6351678169095923899">"Zvarrit poshtë për të larguar"</string>
<string name="pip_menu_title" msgid="4707292089961887657">"Menyja"</string>
<string name="pip_notification_title" msgid="3204024940158161322">"<xliff:g id="NAME">%s</xliff:g> është në figurë brenda figurës"</string>
diff --git a/packages/SystemUI/res/values-sr/strings.xml b/packages/SystemUI/res/values-sr/strings.xml
index 99d8008fa334..7eb86c2f8d23 100644
--- a/packages/SystemUI/res/values-sr/strings.xml
+++ b/packages/SystemUI/res/values-sr/strings.xml
@@ -34,7 +34,10 @@
<string name="status_bar_ongoing_events_title" msgid="1682504513316879202">"Текуће"</string>
<string name="status_bar_latest_events_title" msgid="6594767438577593172">"Обавештења"</string>
<string name="battery_low_title" msgid="6456385927409742437">"Ниво напуњености батерије је низак"</string>
+ <string name="battery_low_title_hybrid" msgid="6268991275887381595">"Батерија је скоро празна. Укључите Уштеду батерије"</string>
<string name="battery_low_percent_format" msgid="2900940511201380775">"Још <xliff:g id="PERCENTAGE">%s</xliff:g>"</string>
+ <string name="battery_low_percent_format_hybrid" msgid="6838677459286775617">"Још <xliff:g id="PERCENTAGE">%s</xliff:g>, на основу коришћења остало је око <xliff:g id="TIME">%s</xliff:g>"</string>
+ <string name="battery_low_percent_format_hybrid_short" msgid="9025795469949145586">"Још <xliff:g id="PERCENTAGE">%s</xliff:g>, остало је око <xliff:g id="TIME">%s</xliff:g>"</string>
<string name="battery_low_percent_format_saver_started" msgid="7879389868952879166">"Још <xliff:g id="PERCENTAGE">%s</xliff:g>. Уштеда батерије је укључена."</string>
<string name="invalid_charger" msgid="4549105996740522523">"Пуњење преко USB-а није подржано.\nКористите само приложени пуњач."</string>
<string name="invalid_charger_title" msgid="3515740382572798460">"Пуњење преко USB-а није подржано."</string>
@@ -68,14 +71,15 @@
<string name="usb_debugging_secondary_user_message" msgid="6067122453571699801">"Корисник који је тренутно пријављен на овај уређај не може да укључи отклањање грешака на USB-у. Да бисте користили ову функцију, пребаците на примарног корисника."</string>
<string name="compat_mode_on" msgid="6623839244840638213">"Зумирај на целом екрану"</string>
<string name="compat_mode_off" msgid="4434467572461327898">"Развуци на цео екран"</string>
+ <string name="global_action_screenshot" msgid="8329831278085426283">"Снимак екрана"</string>
<string name="screenshot_saving_ticker" msgid="7403652894056693515">"Чување снимка екрана..."</string>
<string name="screenshot_saving_title" msgid="8242282144535555697">"Чување снимка екрана..."</string>
- <string name="screenshot_saving_text" msgid="2419718443411738818">"Снимак екрана се чува."</string>
- <string name="screenshot_saved_title" msgid="6461865960961414961">"Снимак екрана је направљен."</string>
- <string name="screenshot_saved_text" msgid="2685605830386712477">"Додирните да бисте видели снимак екрана."</string>
- <string name="screenshot_failed_title" msgid="705781116746922771">"Није могуће направити снимак екрана."</string>
- <string name="screenshot_failed_to_save_unknown_text" msgid="7887826345701753830">"Дошло је до проблема при чувању снимка екрана."</string>
- <string name="screenshot_failed_to_save_text" msgid="2592658083866306296">"Чување снимка екрана није успело због ограниченог меморијског простора."</string>
+ <string name="screenshot_saving_text" msgid="2545047868936087248">"Снимак екрана се чува"</string>
+ <string name="screenshot_saved_title" msgid="5637073968117370753">"Снимак екрана је сачуван"</string>
+ <string name="screenshot_saved_text" msgid="7574667448002050363">"Додирните да бисте видели снимак екрана"</string>
+ <string name="screenshot_failed_title" msgid="9096484883063264803">"Не можете да направите снимак екрана"</string>
+ <string name="screenshot_failed_to_save_unknown_text" msgid="8844781948876286488">"Дошло је до проблема при чувању снимка екрана"</string>
+ <string name="screenshot_failed_to_save_text" msgid="3041612585107107310">"Чување снимка екрана није успело због ограниченог меморијског простора"</string>
<string name="screenshot_failed_to_capture_text" msgid="173674476457581486">"Апликација или организација не дозвољавају прављење снимака екрана"</string>
<string name="usb_preference_title" msgid="6551050377388882787">"Опције USB преноса датотека"</string>
<string name="use_mtp_button_title" msgid="4333504413563023626">"Прикључи као медија плејер (MTP)"</string>
@@ -559,28 +563,19 @@
<string name="tuner_full_importance_settings_off" msgid="8208165412614935229">"Искључено"</string>
<string name="power_notification_controls_description" msgid="4372459941671353358">"Помоћу напредних контрола за обавештења можете да подесите ниво важности од 0. до 5. за обавештења апликације. \n\n"<b>"5. ниво"</b>" \n– Приказују се у врху листе обавештења \n- Дозволи прекид режима целог екрана \n– Увек завируј \n\n"<b>"4. ниво"</b>" \n– Спречи прекид режима целог екрана \n– Увек завируј \n\n"<b>"3. ниво"</b>" \n– Спречи прекид режима целог екрана \n– Никада не завируј \n\n"<b>"2. ниво"</b>" \n– Спречи прекид режима целог екрана \n– Никада не завируј \n– Никада не производи звук или вибрацију \n\n"<b>"1. ниво"</b>" \n– Спречи прекид режима целог екрана \n– Никада не завируј \n– Никада не производи звук или вибрацију \n– Сакриј на закључаном екрану и статусној траци \n– Приказују се у дну листе обавештења \n\n"<b>"0. ниво"</b>" \n– Блокирај сва обавештења из апликације"</string>
<string name="notification_header_default_channel" msgid="7506845022070889909">"Обавештења"</string>
- <string name="notification_channel_disabled" msgid="2139193533791840539">"Више нећете добијати ова обавештења"</string>
- <string name="notification_num_channels" msgid="2048144408999179471">"Категорија обавештења: <xliff:g id="NUMBER">%d</xliff:g>"</string>
- <string name="notification_default_channel_desc" msgid="2506053815870808359">"Ова апликација нема категорије обавештења"</string>
- <string name="notification_unblockable_desc" msgid="3561016061737896906">"Обавештења из ове апликације не могу да се искључе"</string>
- <plurals name="notification_num_channels_desc" formatted="false" msgid="5492793452274077663">
- <item quantity="one">1 од <xliff:g id="NUMBER_1">%s</xliff:g> категорије обавештења за ову апликацију</item>
- <item quantity="few">1 од <xliff:g id="NUMBER_1">%s</xliff:g> категорије обавештења за ову апликацију</item>
- <item quantity="other">1 од <xliff:g id="NUMBER_1">%s</xliff:g> категорија обавештења за ову апликацију</item>
- </plurals>
- <string name="notification_channels_list_desc_2" msgid="6214732715833946441">"<xliff:g id="CHANNEL_NAME_1">%1$s</xliff:g>, <xliff:g id="CHANNEL_NAME_2">%2$s</xliff:g>"</string>
- <plurals name="notification_channels_list_desc_2_and_others" formatted="false" msgid="2747813553355336157">
- <item quantity="one"><xliff:g id="CHANNEL_NAME_1_3">%1$s</xliff:g>, <xliff:g id="CHANNEL_NAME_2_4">%2$s</xliff:g> и још <xliff:g id="NUMBER_5">%3$d</xliff:g></item>
- <item quantity="few"><xliff:g id="CHANNEL_NAME_1_3">%1$s</xliff:g>, <xliff:g id="CHANNEL_NAME_2_4">%2$s</xliff:g> и још <xliff:g id="NUMBER_5">%3$d</xliff:g></item>
- <item quantity="other"><xliff:g id="CHANNEL_NAME_1_3">%1$s</xliff:g>, <xliff:g id="CHANNEL_NAME_2_4">%2$s</xliff:g> и још <xliff:g id="NUMBER_5">%3$d</xliff:g></item>
- </plurals>
+ <string name="notification_channel_disabled" msgid="344536703863700565">"Више нећете видети ова обавештења"</string>
+ <string name="inline_keep_showing" msgid="8945102997083836858">"Желите ли да се ова обавештења и даље приказују?"</string>
+ <string name="inline_stop_button" msgid="4172980096860941033">"Престани да приказујеш обавештења"</string>
+ <string name="inline_keep_button" msgid="6665940297019018232">"Настави да приказујеш"</string>
+ <string name="inline_keep_showing_app" msgid="1723113469580031041">"Желите ли да се обавештења из ове апликације и даље приказују?"</string>
+ <string name="notification_unblockable_desc" msgid="1037434112919403708">"Не можете да искључите ова обавештења"</string>
<string name="notification_channel_controls_opened_accessibility" msgid="6553950422055908113">"Контроле обавештења за отварање апликације <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
<string name="notification_channel_controls_closed_accessibility" msgid="7521619812603693144">"Контроле обавештења за затварање апликације <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
<string name="notification_channel_switch_accessibility" msgid="3420796005601900717">"Дозволи обавештења са овог канала"</string>
- <string name="notification_all_categories" msgid="5407190218055113282">"Све категорије"</string>
<string name="notification_more_settings" msgid="816306283396553571">"Још подешавања"</string>
- <string name="notification_app_settings" msgid="3743278649182392015">"Прилагодите: <xliff:g id="SUB_CATEGORY">%1$s</xliff:g>"</string>
+ <string name="notification_app_settings" msgid="420348114670768449">"Прилагоди"</string>
<string name="notification_done" msgid="5279426047273930175">"Готово"</string>
+ <string name="inline_undo" msgid="558916737624706010">"Опозови"</string>
<string name="notification_menu_accessibility" msgid="2046162834248888553">"<xliff:g id="APP_NAME">%1$s</xliff:g> <xliff:g id="MENU_DESCRIPTION">%2$s</xliff:g>"</string>
<string name="notification_menu_gear_description" msgid="2204480013726775108">"контроле обавештења"</string>
<string name="notification_menu_snooze_description" msgid="3653669438131034525">"опције за одлагање обавештења"</string>
@@ -737,8 +732,7 @@
<string name="pip_phone_expand" msgid="5889780005575693909">"Прошири"</string>
<string name="pip_phone_minimize" msgid="1079119422589131792">"Умањи"</string>
<string name="pip_phone_close" msgid="8416647892889710330">"Затвори"</string>
- <!-- no translation found for pip_phone_settings (8080777499521528521) -->
- <skip />
+ <string name="pip_phone_settings" msgid="8080777499521528521">"Подешавања"</string>
<string name="pip_phone_dismiss_hint" msgid="6351678169095923899">"Превуците надоле да бисте одбили"</string>
<string name="pip_menu_title" msgid="4707292089961887657">"Мени"</string>
<string name="pip_notification_title" msgid="3204024940158161322">"<xliff:g id="NAME">%s</xliff:g> је слика у слици"</string>
diff --git a/packages/SystemUI/res/values-sv/strings.xml b/packages/SystemUI/res/values-sv/strings.xml
index 2d267dfed26c..d2da3b7c5986 100644
--- a/packages/SystemUI/res/values-sv/strings.xml
+++ b/packages/SystemUI/res/values-sv/strings.xml
@@ -33,7 +33,10 @@
<string name="status_bar_ongoing_events_title" msgid="1682504513316879202">"Pågående"</string>
<string name="status_bar_latest_events_title" msgid="6594767438577593172">"Meddelanden"</string>
<string name="battery_low_title" msgid="6456385927409742437">"Lågt batteri"</string>
+ <string name="battery_low_title_hybrid" msgid="6268991275887381595">"Batterinivån är låg. Aktivera batterisparläge"</string>
<string name="battery_low_percent_format" msgid="2900940511201380775">"<xliff:g id="PERCENTAGE">%s</xliff:g> kvar"</string>
+ <string name="battery_low_percent_format_hybrid" msgid="6838677459286775617">"<xliff:g id="PERCENTAGE">%s</xliff:g> återstår, cirka <xliff:g id="TIME">%s</xliff:g> kvar utifrån din användning"</string>
+ <string name="battery_low_percent_format_hybrid_short" msgid="9025795469949145586">"<xliff:g id="PERCENTAGE">%s</xliff:g> återstår, cirka <xliff:g id="TIME">%s</xliff:g> kvar"</string>
<string name="battery_low_percent_format_saver_started" msgid="7879389868952879166">"<xliff:g id="PERCENTAGE">%s</xliff:g> kvar. Batterisparläget är aktiverat."</string>
<string name="invalid_charger" msgid="4549105996740522523">"Det går inte att ladda via USB.\nAnvänd endast den laddare som levererades med telefonen."</string>
<string name="invalid_charger_title" msgid="3515740382572798460">"Det finns inget stöd för laddning via USB."</string>
@@ -67,14 +70,15 @@
<string name="usb_debugging_secondary_user_message" msgid="6067122453571699801">"Användaren som är inloggad på enheten för närvarande kan inte aktivera USB-felsökning. Byt till den primära användaren om du vill använda den här funktionen."</string>
<string name="compat_mode_on" msgid="6623839244840638213">"Zooma för att fylla skärm"</string>
<string name="compat_mode_off" msgid="4434467572461327898">"Dra för att fylla skärmen"</string>
+ <string name="global_action_screenshot" msgid="8329831278085426283">"Skärmdump"</string>
<string name="screenshot_saving_ticker" msgid="7403652894056693515">"Skärmdumpen sparas ..."</string>
<string name="screenshot_saving_title" msgid="8242282144535555697">"Skärmdumpen sparas ..."</string>
- <string name="screenshot_saving_text" msgid="2419718443411738818">"Skärmdumpen sparas."</string>
- <string name="screenshot_saved_title" msgid="6461865960961414961">"Skärmdumpen har tagits."</string>
- <string name="screenshot_saved_text" msgid="2685605830386712477">"Visa skärmdumpen genom att trycka här."</string>
- <string name="screenshot_failed_title" msgid="705781116746922771">"Det gick inte att ta någon skärmdump."</string>
- <string name="screenshot_failed_to_save_unknown_text" msgid="7887826345701753830">"Det gick inte att spara skärmdumpen."</string>
- <string name="screenshot_failed_to_save_text" msgid="2592658083866306296">"Det går inte att spara skärmdumpen eftersom lagringsutrymmet inte räcker."</string>
+ <string name="screenshot_saving_text" msgid="2545047868936087248">"Skärmdumpen sparas"</string>
+ <string name="screenshot_saved_title" msgid="5637073968117370753">"Skärmdumpen har sparats"</string>
+ <string name="screenshot_saved_text" msgid="7574667448002050363">"Visa skärmdumpen genom att trycka här"</string>
+ <string name="screenshot_failed_title" msgid="9096484883063264803">"Det gick inte att ta en skärmdump"</string>
+ <string name="screenshot_failed_to_save_unknown_text" msgid="8844781948876286488">"Det gick inte att spara skärmdumpen"</string>
+ <string name="screenshot_failed_to_save_text" msgid="3041612585107107310">"Det går inte att spara skärmdumpen eftersom lagringsutrymmet inte räcker"</string>
<string name="screenshot_failed_to_capture_text" msgid="173674476457581486">"Appen eller organisationen tillåter inte att du tar skärmdumpar"</string>
<string name="usb_preference_title" msgid="6551050377388882787">"Överföringsalternativ"</string>
<string name="use_mtp_button_title" msgid="4333504413563023626">"Montera som mediaspelare (MTP)"</string>
@@ -557,26 +561,19 @@
<string name="tuner_full_importance_settings_off" msgid="8208165412614935229">"På"</string>
<string name="power_notification_controls_description" msgid="4372459941671353358">"Med aviseringsinställningarna kan du ange prioritetsnivå från 0 till 5 för aviseringar från en app. \n\n"<b>"Nivå 5"</b>" \n– Visa högst upp i aviseringslistan\n– Tillåt avbrott i helskärmsläge \n– Snabbvisa alltid \n\n"<b>"Nivå 4"</b>" \n– Tillåt inte avbrott i helskärmsläge \n– Snabbvisa alltid \n\n"<b>"Nivå 3"</b>" \n- Tillåt inte avbrott i helskärmsläge \n– Snabbvisa aldrig \n\n"<b>"Nivå 2"</b>" \n– Tillåt inte avbrott i helskärmsläge \n– Snabbvisa aldrig \n– Aldrig med ljud eller vibration \n\n"<b>"Nivå 1"</b>" \n– Tillåt inte avbrott i helskärmsläge \n– Snabbvisa aldrig \n– Aldrig med ljud eller vibration \n– Visa inte på låsskärmen och i statusfältet \n– Visa längst ned i aviseringslistan \n\n"<b>"Nivå 0"</b>" \n– Blockera alla aviseringar från appen"</string>
<string name="notification_header_default_channel" msgid="7506845022070889909">"Aviseringar"</string>
- <string name="notification_channel_disabled" msgid="2139193533791840539">"Inga fler aviseringar av det här slaget visas"</string>
- <string name="notification_num_channels" msgid="2048144408999179471">"<xliff:g id="NUMBER">%d</xliff:g> aviseringskategorier"</string>
- <string name="notification_default_channel_desc" msgid="2506053815870808359">"Det finns inga aviseringskategorier i appen"</string>
- <string name="notification_unblockable_desc" msgid="3561016061737896906">"Det går inte att inaktivera aviseringar från den här appen"</string>
- <plurals name="notification_num_channels_desc" formatted="false" msgid="5492793452274077663">
- <item quantity="other">1 av <xliff:g id="NUMBER_1">%s</xliff:g> aviseringskategorier från denna app</item>
- <item quantity="one">1 av <xliff:g id="NUMBER_0">%s</xliff:g> aviseringskategorier från denna app</item>
- </plurals>
- <string name="notification_channels_list_desc_2" msgid="6214732715833946441">"<xliff:g id="CHANNEL_NAME_1">%1$s</xliff:g>, <xliff:g id="CHANNEL_NAME_2">%2$s</xliff:g>"</string>
- <plurals name="notification_channels_list_desc_2_and_others" formatted="false" msgid="2747813553355336157">
- <item quantity="other"><xliff:g id="CHANNEL_NAME_1_3">%1$s</xliff:g>, <xliff:g id="CHANNEL_NAME_2_4">%2$s</xliff:g> och <xliff:g id="NUMBER_5">%3$d</xliff:g> till</item>
- <item quantity="one"><xliff:g id="CHANNEL_NAME_1_0">%1$s</xliff:g>, <xliff:g id="CHANNEL_NAME_2_1">%2$s</xliff:g> och <xliff:g id="NUMBER_2">%3$d</xliff:g> till</item>
- </plurals>
+ <string name="notification_channel_disabled" msgid="344536703863700565">"De här aviseringarna visas inte längre"</string>
+ <string name="inline_keep_showing" msgid="8945102997083836858">"Vill du fortsätta visa de här aviseringarna?"</string>
+ <string name="inline_stop_button" msgid="4172980096860941033">"Stoppa aviseringar"</string>
+ <string name="inline_keep_button" msgid="6665940297019018232">"Fortsätt visa"</string>
+ <string name="inline_keep_showing_app" msgid="1723113469580031041">"Vill du fortsätta visa aviseringar för den här appen?"</string>
+ <string name="notification_unblockable_desc" msgid="1037434112919403708">"De här aviseringarna kan inte inaktiveras"</string>
<string name="notification_channel_controls_opened_accessibility" msgid="6553950422055908113">"Aviseringsinställningarna för <xliff:g id="APP_NAME">%1$s</xliff:g> är öppna"</string>
<string name="notification_channel_controls_closed_accessibility" msgid="7521619812603693144">"Aviseringsinställningarna för <xliff:g id="APP_NAME">%1$s</xliff:g> har stängts"</string>
<string name="notification_channel_switch_accessibility" msgid="3420796005601900717">"Tillåt aviseringar från den här kanalen"</string>
- <string name="notification_all_categories" msgid="5407190218055113282">"Alla kategorier"</string>
<string name="notification_more_settings" msgid="816306283396553571">"Fler inställningar"</string>
- <string name="notification_app_settings" msgid="3743278649182392015">"Anpassa: <xliff:g id="SUB_CATEGORY">%1$s</xliff:g>"</string>
+ <string name="notification_app_settings" msgid="420348114670768449">"Anpassa"</string>
<string name="notification_done" msgid="5279426047273930175">"Klar"</string>
+ <string name="inline_undo" msgid="558916737624706010">"Ångra"</string>
<string name="notification_menu_accessibility" msgid="2046162834248888553">"<xliff:g id="APP_NAME">%1$s</xliff:g> <xliff:g id="MENU_DESCRIPTION">%2$s</xliff:g>"</string>
<string name="notification_menu_gear_description" msgid="2204480013726775108">"inställningar för aviseringar"</string>
<string name="notification_menu_snooze_description" msgid="3653669438131034525">"alternativ för att snooza aviseringar"</string>
@@ -731,8 +728,7 @@
<string name="pip_phone_expand" msgid="5889780005575693909">"Utöka"</string>
<string name="pip_phone_minimize" msgid="1079119422589131792">"Minimera"</string>
<string name="pip_phone_close" msgid="8416647892889710330">"Stäng"</string>
- <!-- no translation found for pip_phone_settings (8080777499521528521) -->
- <skip />
+ <string name="pip_phone_settings" msgid="8080777499521528521">"Inställningar"</string>
<string name="pip_phone_dismiss_hint" msgid="6351678169095923899">"Tryck och dra nedåt för att avvisa"</string>
<string name="pip_menu_title" msgid="4707292089961887657">"Meny"</string>
<string name="pip_notification_title" msgid="3204024940158161322">"<xliff:g id="NAME">%s</xliff:g> visas i bild-i-bild"</string>
diff --git a/packages/SystemUI/res/values-sw/strings.xml b/packages/SystemUI/res/values-sw/strings.xml
index 58eac297a2c8..8cae1c43d72d 100644
--- a/packages/SystemUI/res/values-sw/strings.xml
+++ b/packages/SystemUI/res/values-sw/strings.xml
@@ -35,8 +35,8 @@
<string name="battery_low_title" msgid="6456385927409742437">"Betri inaisha"</string>
<string name="battery_low_title_hybrid" msgid="6268991275887381595">"Chaji imepungua. Washa Kiokoa Betri"</string>
<string name="battery_low_percent_format" msgid="2900940511201380775">"Imebakisha <xliff:g id="PERCENTAGE">%s</xliff:g>"</string>
- <string name="battery_low_percent_format_hybrid" msgid="6838677459286775617">"Imesalia <xliff:g id="PERCENTAGE">%s</xliff:g>, zimesalia takribani <xliff:g id="TIME">%s</xliff:g> kulingana na jinsi unavyotumia"</string>
- <string name="battery_low_percent_format_hybrid_short" msgid="9025795469949145586">"Imesalia <xliff:g id="PERCENTAGE">%s</xliff:g>, zimesalia takribani <xliff:g id="TIME">%s</xliff:g>"</string>
+ <string name="battery_low_percent_format_hybrid" msgid="6838677459286775617">"Imesalia <xliff:g id="PERCENTAGE">%s</xliff:g>, itadumu takribani <xliff:g id="TIME">%s</xliff:g> kulingana na jinsi unavyotumia"</string>
+ <string name="battery_low_percent_format_hybrid_short" msgid="9025795469949145586">"Imesalia <xliff:g id="PERCENTAGE">%s</xliff:g>, itadumu takribani <xliff:g id="TIME">%s</xliff:g>"</string>
<string name="battery_low_percent_format_saver_started" msgid="7879389868952879166">"Imesalia <xliff:g id="PERCENTAGE">%s</xliff:g>. Umewasha Kiokoa Betri."</string>
<string name="invalid_charger" msgid="4549105996740522523">"Chaji ya USB haihamiliwi.\n Tumia chaka iliyopeanwa."</string>
<string name="invalid_charger_title" msgid="3515740382572798460">"Kuchaji kwa kutumia USB hakutumiki."</string>
diff --git a/packages/SystemUI/res/values-ta/strings.xml b/packages/SystemUI/res/values-ta/strings.xml
index 544cd7989ea9..5a209b0d1b14 100644
--- a/packages/SystemUI/res/values-ta/strings.xml
+++ b/packages/SystemUI/res/values-ta/strings.xml
@@ -33,7 +33,13 @@
<string name="status_bar_ongoing_events_title" msgid="1682504513316879202">"செயலில் இருக்கும்"</string>
<string name="status_bar_latest_events_title" msgid="6594767438577593172">"அறிவிப்புகள்"</string>
<string name="battery_low_title" msgid="6456385927409742437">"பேட்டரி குறைவு"</string>
+ <!-- no translation found for battery_low_title_hybrid (6268991275887381595) -->
+ <skip />
<string name="battery_low_percent_format" msgid="2900940511201380775">"<xliff:g id="PERCENTAGE">%s</xliff:g> உள்ளது"</string>
+ <!-- no translation found for battery_low_percent_format_hybrid (6838677459286775617) -->
+ <skip />
+ <!-- no translation found for battery_low_percent_format_hybrid_short (9025795469949145586) -->
+ <skip />
<string name="battery_low_percent_format_saver_started" msgid="7879389868952879166">"<xliff:g id="PERCENTAGE">%s</xliff:g> மீதமுள்ளது. பேட்டரி சேமிப்பான் ஆன் செய்யப்பட்டுள்ளது."</string>
<string name="invalid_charger" msgid="4549105996740522523">"USB மூலம் சார்ஜ் செய்வது ஆதரிக்கப்படவில்லை.\nவழங்கப்பட்ட சார்ஜரை மட்டும் பயன்படுத்தவும்."</string>
<string name="invalid_charger_title" msgid="3515740382572798460">"USB சார்ஜிங் ஆதரிக்கப்படவில்லை."</string>
@@ -67,14 +73,22 @@
<string name="usb_debugging_secondary_user_message" msgid="6067122453571699801">"தற்போது இந்தச் சாதனத்தில் உள்நுழைந்துள்ள பயனரால் USB பிழைத்திருத்தத்தை இயக்க முடியாது. இந்த அம்சத்தை இயக்க, முதன்மைப் பயனருக்கு மாறவும்."</string>
<string name="compat_mode_on" msgid="6623839244840638213">"திரையை நிரப்ப அளவை மாற்று"</string>
<string name="compat_mode_off" msgid="4434467572461327898">"திரையை நிரப்ப இழு"</string>
+ <!-- no translation found for global_action_screenshot (8329831278085426283) -->
+ <skip />
<string name="screenshot_saving_ticker" msgid="7403652894056693515">"ஸ்க்ரீன் ஷாட்டைச் சேமிக்கிறது…"</string>
<string name="screenshot_saving_title" msgid="8242282144535555697">"ஸ்க்ரீன் ஷாட்டைச் சேமிக்கிறது…"</string>
- <string name="screenshot_saving_text" msgid="2419718443411738818">"ஸ்க்ரீன் ஷாட் சேமிக்கப்படுகிறது."</string>
- <string name="screenshot_saved_title" msgid="6461865960961414961">"ஸ்கிரீன் ஷாட் எடுக்கப்பட்டது."</string>
- <string name="screenshot_saved_text" msgid="2685605830386712477">"ஸ்கிரீன்ஷாட்டைப் பார்க்க, தட்டவும்."</string>
- <string name="screenshot_failed_title" msgid="705781116746922771">"ஸ்க்ரீன் ஷாட்டை எடுக்க முடியவில்லை."</string>
- <string name="screenshot_failed_to_save_unknown_text" msgid="7887826345701753830">"ஸ்க்ரீன்ஷாட்டைச் சேமிக்கும் போது, பிழை ஏற்பட்டது."</string>
- <string name="screenshot_failed_to_save_text" msgid="2592658083866306296">"போதுமான சேமிப்பிடம் இல்லாததால் ஸ்கிரீன்ஷாட்டைச் சேமிக்க முடியவில்லை."</string>
+ <!-- no translation found for screenshot_saving_text (2545047868936087248) -->
+ <skip />
+ <!-- no translation found for screenshot_saved_title (5637073968117370753) -->
+ <skip />
+ <!-- no translation found for screenshot_saved_text (7574667448002050363) -->
+ <skip />
+ <!-- no translation found for screenshot_failed_title (9096484883063264803) -->
+ <skip />
+ <!-- no translation found for screenshot_failed_to_save_unknown_text (8844781948876286488) -->
+ <skip />
+ <!-- no translation found for screenshot_failed_to_save_text (3041612585107107310) -->
+ <skip />
<string name="screenshot_failed_to_capture_text" msgid="173674476457581486">"ஸ்கிரீன் ஷாட்டுகளை எடுப்பதை, பயன்பாடு அல்லது உங்கள் நிறுவனம் அனுமதிக்கவில்லை"</string>
<string name="usb_preference_title" msgid="6551050377388882787">"USB கோப்பு இடமாற்ற விருப்பங்கள்"</string>
<string name="use_mtp_button_title" msgid="4333504413563023626">"(MTP) மீடியா பிளேயராக ஏற்று"</string>
@@ -557,26 +571,27 @@
<string name="tuner_full_importance_settings_off" msgid="8208165412614935229">"ஆஃப்"</string>
<string name="power_notification_controls_description" msgid="4372459941671353358">"ஆற்றல்மிக்க அறிவிப்புக் கட்டுப்பாடுகள் மூலம், பயன்பாட்டின் அறிவிப்புகளுக்கு முக்கியத்துவ நிலையை (0-5) அமைக்கலாம். \n\n"<b>"நிலை 5"</b>" \n- அறிவிப்புப் பட்டியலின் மேலே காட்டும் \n- முழுத் திரைக் குறுக்கீட்டை அனுமதிக்கும் \n- எப்போதும் நடப்புத் திரையின் மேல் பகுதியில் அறிவிப்புகளைக் காட்டும் \n\n"<b>"நிலை 4"</b>" \n- முழுத் திரைக் குறுக்கீட்டைத் தடுக்கும் \n- எப்போதும் நடப்புத் திரையின் மேல் பகுதியில் அறிவிப்புகளைக் காட்டும் \n\n"<b>"நிலை 3"</b>" \n- முழுத் திரைக் குறுக்கீட்டைத் தடுக்கும் \n- ஒருபோதும் நடப்புத் திரையின் மேல் பகுதியில் அறிவிப்புகளைக் காட்டாது \n\n"<b>"நிலை 2"</b>" \n- முழுத் திரைக் குறுக்கீட்டைத் தடுக்கும் \n- ஒருபோதும் நடப்புத் திரையின் மேல் பகுதியில் அறிவிப்புகளைக் காட்டாது \n- ஒருபோதும் ஒலி எழுப்பாது, அதிர்வுறாது \n\n"<b>"நிலை 1"</b>" \n- முழுத் திரைக் குறுக்கீட்டைத் தடுக்கும் \n- ஒருபோதும் நடப்புத் திரையின் மேல் பகுதியில் அறிவிப்புகளைக் காட்டாது \n- ஒருபோதும் ஒலி எழுப்பாது அல்லது அதிர்வுறாது \n- பூட்டுத்திரை மற்றும் நிலைப்பட்டியிலிருந்து மறைக்கும் \n- அறிவிப்புகள் பட்டியலின் கீழே காட்டும் \n\n"<b>"நிலை 0"</b>" \n- பயன்பாட்டின் எல்லா அறிவிப்புகளையும் தடுக்கும்"</string>
<string name="notification_header_default_channel" msgid="7506845022070889909">"அறிவிப்புகள்"</string>
- <string name="notification_channel_disabled" msgid="2139193533791840539">"இந்த அறிவிப்புகளை இனி பெறமாட்டீர்கள்"</string>
- <string name="notification_num_channels" msgid="2048144408999179471">"<xliff:g id="NUMBER">%d</xliff:g> அறிவிப்பு வகைகள்"</string>
- <string name="notification_default_channel_desc" msgid="2506053815870808359">"இந்தப் பயன்பாட்டில் அறிவிப்பு வகைகள் இல்லை"</string>
- <string name="notification_unblockable_desc" msgid="3561016061737896906">"இந்தப் பயன்பாட்டிலிருந்து அறிவிப்புகளைப் பெறுவதை முடக்க முடியாது"</string>
- <plurals name="notification_num_channels_desc" formatted="false" msgid="5492793452274077663">
- <item quantity="other">இந்தப் பயன்பாடு வழங்கும் <xliff:g id="NUMBER_1">%s</xliff:g> அறிவிப்பு வகைகளில் ஒரு அறிவிப்பு வகை</item>
- <item quantity="one">இந்தப் பயன்பாடு வழங்கும் <xliff:g id="NUMBER_0">%s</xliff:g> அறிவிப்பு வகையில் ஒரு அறிவிப்பு வகை</item>
- </plurals>
- <string name="notification_channels_list_desc_2" msgid="6214732715833946441">"<xliff:g id="CHANNEL_NAME_1">%1$s</xliff:g>, <xliff:g id="CHANNEL_NAME_2">%2$s</xliff:g>"</string>
- <plurals name="notification_channels_list_desc_2_and_others" formatted="false" msgid="2747813553355336157">
- <item quantity="other"><xliff:g id="CHANNEL_NAME_1_3">%1$s</xliff:g>, <xliff:g id="CHANNEL_NAME_2_4">%2$s</xliff:g>, மேலும் <xliff:g id="NUMBER_5">%3$d</xliff:g> சேனல்கள்</item>
- <item quantity="one"><xliff:g id="CHANNEL_NAME_1_0">%1$s</xliff:g>, <xliff:g id="CHANNEL_NAME_2_1">%2$s</xliff:g>, மேலும் <xliff:g id="NUMBER_2">%3$d</xliff:g> சேனல்</item>
- </plurals>
+ <!-- no translation found for notification_channel_disabled (344536703863700565) -->
+ <skip />
+ <!-- no translation found for inline_keep_showing (8945102997083836858) -->
+ <skip />
+ <!-- no translation found for inline_stop_button (4172980096860941033) -->
+ <skip />
+ <!-- no translation found for inline_keep_button (6665940297019018232) -->
+ <skip />
+ <!-- no translation found for inline_keep_showing_app (1723113469580031041) -->
+ <skip />
+ <!-- no translation found for notification_unblockable_desc (1037434112919403708) -->
+ <skip />
<string name="notification_channel_controls_opened_accessibility" msgid="6553950422055908113">"<xliff:g id="APP_NAME">%1$s</xliff:g>க்கான அறிவிப்புக் கட்டுப்பாடுகள் திறக்கப்பட்டன"</string>
<string name="notification_channel_controls_closed_accessibility" msgid="7521619812603693144">"<xliff:g id="APP_NAME">%1$s</xliff:g>க்கான அறிவிப்புக் கட்டுப்பாடுகள் மூடப்பட்டன"</string>
<string name="notification_channel_switch_accessibility" msgid="3420796005601900717">"இந்தச் சேனலிலிருந்து அறிவிப்புகளைப் பெறுவதை அனுமதிக்கும்"</string>
- <string name="notification_all_categories" msgid="5407190218055113282">"எல்லா வகைகளும்"</string>
<string name="notification_more_settings" msgid="816306283396553571">"மேலும் அமைப்புகள்"</string>
- <string name="notification_app_settings" msgid="3743278649182392015">"தனிப்பயனாக்கு: <xliff:g id="SUB_CATEGORY">%1$s</xliff:g>"</string>
+ <!-- no translation found for notification_app_settings (420348114670768449) -->
+ <skip />
<string name="notification_done" msgid="5279426047273930175">"முடிந்தது"</string>
+ <!-- no translation found for inline_undo (558916737624706010) -->
+ <skip />
<string name="notification_menu_accessibility" msgid="2046162834248888553">"<xliff:g id="APP_NAME">%1$s</xliff:g> <xliff:g id="MENU_DESCRIPTION">%2$s</xliff:g>"</string>
<string name="notification_menu_gear_description" msgid="2204480013726775108">"அறிவிப்புக் கட்டுப்பாடுகள்"</string>
<string name="notification_menu_snooze_description" msgid="3653669438131034525">"அறிவிப்பை உறக்கநிலையாக்கும் விருப்பங்கள்"</string>
@@ -731,8 +746,7 @@
<string name="pip_phone_expand" msgid="5889780005575693909">"விரி"</string>
<string name="pip_phone_minimize" msgid="1079119422589131792">"சிறிதாக்கு"</string>
<string name="pip_phone_close" msgid="8416647892889710330">"மூடு"</string>
- <!-- no translation found for pip_phone_settings (8080777499521528521) -->
- <skip />
+ <string name="pip_phone_settings" msgid="8080777499521528521">"அமைப்புகள்"</string>
<string name="pip_phone_dismiss_hint" msgid="6351678169095923899">"நிராகரிக்க, கீழே இழுக்கவும்"</string>
<string name="pip_menu_title" msgid="4707292089961887657">"மெனு"</string>
<string name="pip_notification_title" msgid="3204024940158161322">"<xliff:g id="NAME">%s</xliff:g> தற்போது பிக்ச்சர்-இன்-பிக்ச்சரில் உள்ளது"</string>
diff --git a/packages/SystemUI/res/values-th/strings.xml b/packages/SystemUI/res/values-th/strings.xml
index 5b3106135c38..01b75e33f985 100644
--- a/packages/SystemUI/res/values-th/strings.xml
+++ b/packages/SystemUI/res/values-th/strings.xml
@@ -33,7 +33,10 @@
<string name="status_bar_ongoing_events_title" msgid="1682504513316879202">"ดำเนินอยู่"</string>
<string name="status_bar_latest_events_title" msgid="6594767438577593172">"การแจ้งเตือน"</string>
<string name="battery_low_title" msgid="6456385927409742437">"แบตเตอรี่เหลือน้อย"</string>
+ <string name="battery_low_title_hybrid" msgid="6268991275887381595">"แบตเตอรี่เหลือน้อย โปรดเปิดโหมดประหยัดแบตเตอรี่"</string>
<string name="battery_low_percent_format" msgid="2900940511201380775">"เหลืออีก <xliff:g id="PERCENTAGE">%s</xliff:g>"</string>
+ <string name="battery_low_percent_format_hybrid" msgid="6838677459286775617">"เหลือ <xliff:g id="PERCENTAGE">%s</xliff:g> หรืออีกราว <xliff:g id="TIME">%s</xliff:g> ขึ้นอยู่กับการใช้งานของคุณ"</string>
+ <string name="battery_low_percent_format_hybrid_short" msgid="9025795469949145586">"เหลือ <xliff:g id="PERCENTAGE">%s</xliff:g> หรืออีกราว <xliff:g id="TIME">%s</xliff:g>"</string>
<string name="battery_low_percent_format_saver_started" msgid="7879389868952879166">"แบตเตอรี่เหลือ <xliff:g id="PERCENTAGE">%s</xliff:g> เปิดโหมดประหยัดแบตเตอรี่อยู่"</string>
<string name="invalid_charger" msgid="4549105996740522523">"ไม่สนับสนุนการชาร์จแบบ USB\nใช้เฉพาะที่ชาร์จที่ให้มาเท่านั้น"</string>
<string name="invalid_charger_title" msgid="3515740382572798460">"ไม่รองรับการชาร์จผ่าน USB"</string>
@@ -67,14 +70,15 @@
<string name="usb_debugging_secondary_user_message" msgid="6067122453571699801">"ผู้ใช้ที่ลงชื่อเข้าใช้อุปกรณ์อยู่ในขณะนี้ไม่สามารถเปิดการแก้ไขข้อบกพร่องผ่าน USB ได้ หากต้องการใช้ฟีเจอร์นี้ ให้เปลี่ยนไปเป็นผู้ใช้หลัก"</string>
<string name="compat_mode_on" msgid="6623839244840638213">"ขยายจนเต็มหน้าจอ"</string>
<string name="compat_mode_off" msgid="4434467572461327898">"ยืดจนเต็มหน้าจอ"</string>
+ <string name="global_action_screenshot" msgid="8329831278085426283">"ภาพหน้าจอ"</string>
<string name="screenshot_saving_ticker" msgid="7403652894056693515">"กำลังบันทึกภาพหน้าจอ..."</string>
<string name="screenshot_saving_title" msgid="8242282144535555697">"กำลังบันทึกภาพหน้าจอ..."</string>
- <string name="screenshot_saving_text" msgid="2419718443411738818">"กำลังบันทึกภาพหน้าจอ"</string>
- <string name="screenshot_saved_title" msgid="6461865960961414961">"จับภาพหน้าจอแล้ว"</string>
- <string name="screenshot_saved_text" msgid="2685605830386712477">"แตะเพื่อดูภาพหน้าจอของคุณ"</string>
- <string name="screenshot_failed_title" msgid="705781116746922771">"ไม่สามารถจับภาพหน้าจอ"</string>
- <string name="screenshot_failed_to_save_unknown_text" msgid="7887826345701753830">"พบปัญหาขณะกำลังบันทึกภาพหน้าจอ"</string>
- <string name="screenshot_failed_to_save_text" msgid="2592658083866306296">"ไม่สามารถบันทึกภาพหน้าจอเนื่องจากพื้นที่เก็บข้อมูลมีจำกัด"</string>
+ <string name="screenshot_saving_text" msgid="2545047868936087248">"กำลังบันทึกภาพหน้าจอ"</string>
+ <string name="screenshot_saved_title" msgid="5637073968117370753">"บันทึกภาพหน้าจอแล้ว"</string>
+ <string name="screenshot_saved_text" msgid="7574667448002050363">"แตะเพื่อดูภาพหน้าจอ"</string>
+ <string name="screenshot_failed_title" msgid="9096484883063264803">"จับภาพหน้าจอไม่ได้"</string>
+ <string name="screenshot_failed_to_save_unknown_text" msgid="8844781948876286488">"พบปัญหาขณะบันทึกภาพหน้าจอ"</string>
+ <string name="screenshot_failed_to_save_text" msgid="3041612585107107310">"บันทึกภาพหน้าจอไม่ได้เนื่องจากพื้นที่เก็บข้อมูลมีจำกัด"</string>
<string name="screenshot_failed_to_capture_text" msgid="173674476457581486">"แอปหรือองค์กรของคุณไม่อนุญาตให้จับภาพหน้าจอ"</string>
<string name="usb_preference_title" msgid="6551050377388882787">"ตัวเลือกการถ่ายโอนไฟล์ USB"</string>
<string name="use_mtp_button_title" msgid="4333504413563023626">"ต่อเชื่อมเป็นโปรแกรมเล่นสื่อ (MTP)"</string>
@@ -557,26 +561,19 @@
<string name="tuner_full_importance_settings_off" msgid="8208165412614935229">"ปิด"</string>
<string name="power_notification_controls_description" msgid="4372459941671353358">"ส่วนควบคุมการแจ้งเตือนแบบเปิด/ปิดช่วยให้คุณตั้งค่าระดับความสำคัญสำหรับการแจ้งเตือนของแอปได้ตั้งแต่ระดับ 0-5 \n\n"<b>"ระดับ 5"</b>" \n- แสดงที่ด้านบนของรายการแจ้งเตือน \n- อนุญาตให้รบกวนแบบเต็มหน้าจอ \n- อนุญาตให้แสดงชั่วครู่ \n\n"<b>"ระดับ 4"</b>" \n- ป้องกันการรบกวนแบบเต็มหน้าจอ \n- แสดงชั่วครู่เสมอ \n\n"<b>"ระดับ 3"</b>" \n- ป้องกันการรบกวนแบบเต็มหน้าจอ \n- ไม่แสดงชั่วครู่เลย \n\n"<b>"ระดับ 2"</b>" \n- ป้องกันการรบกวนแบบเต็มหน้าจอ \n- ไม่แสดงชั่วครู่เลย \n- ไม่ส่งเสียงหรือสั่นเลย \n\n"<b>"ระดับ 1"</b>" \n- ป้องกันการรบกวนแบบเต็มหน้าจอ \n- ไม่แสดงชั่วครู่เลย \n- ไม่ส่งเสียงหรือสั่นเลย \n- ซ่อนจากหน้าจอล็อกและแถบสถานะ \n- แสดงที่ด้านล่างของรายการแจ้งเตือน \n\n"<b>"ระดับ 0"</b>" \n- บล็อกการแจ้งเตือนทั้งหมดจากแอป"</string>
<string name="notification_header_default_channel" msgid="7506845022070889909">"การแจ้งเตือน"</string>
- <string name="notification_channel_disabled" msgid="2139193533791840539">"คุณจะไม่ได้รับการแจ้งเตือนเหล่านี้อีก"</string>
- <string name="notification_num_channels" msgid="2048144408999179471">"หมวดหมู่การแจ้งเตือน <xliff:g id="NUMBER">%d</xliff:g> หมวด"</string>
- <string name="notification_default_channel_desc" msgid="2506053815870808359">"แอปนี้ไม่มีหมวดหมู่การแจ้งเตือน"</string>
- <string name="notification_unblockable_desc" msgid="3561016061737896906">"ไม่สามารถปิดการแจ้งเตือนจากแอปนี้"</string>
- <plurals name="notification_num_channels_desc" formatted="false" msgid="5492793452274077663">
- <item quantity="other">การแจ้งเตือน 1 ใน <xliff:g id="NUMBER_1">%s</xliff:g> หมวดหมู่จากแอปนี้</item>
- <item quantity="one">การแจ้งเตือน 1 ใน <xliff:g id="NUMBER_0">%s</xliff:g> หมวดหมู่จากแอปนี้</item>
- </plurals>
- <string name="notification_channels_list_desc_2" msgid="6214732715833946441">"<xliff:g id="CHANNEL_NAME_1">%1$s</xliff:g>, <xliff:g id="CHANNEL_NAME_2">%2$s</xliff:g>"</string>
- <plurals name="notification_channels_list_desc_2_and_others" formatted="false" msgid="2747813553355336157">
- <item quantity="other"><xliff:g id="CHANNEL_NAME_1_3">%1$s</xliff:g>, <xliff:g id="CHANNEL_NAME_2_4">%2$s</xliff:g> และอีก <xliff:g id="NUMBER_5">%3$d</xliff:g> ช่องทาง</item>
- <item quantity="one"><xliff:g id="CHANNEL_NAME_1_0">%1$s</xliff:g>, <xliff:g id="CHANNEL_NAME_2_1">%2$s</xliff:g> และอีก <xliff:g id="NUMBER_2">%3$d</xliff:g> ช่องทาง</item>
- </plurals>
+ <string name="notification_channel_disabled" msgid="344536703863700565">"คุณจะไม่เห็นการแจ้งเตือนเหล่านี้อีก"</string>
+ <string name="inline_keep_showing" msgid="8945102997083836858">"แสดงการแจ้งเตือนเหล่านี้ต่อไปไหม"</string>
+ <string name="inline_stop_button" msgid="4172980096860941033">"ปิดการแจ้งเตือน"</string>
+ <string name="inline_keep_button" msgid="6665940297019018232">"แสดงต่อไป"</string>
+ <string name="inline_keep_showing_app" msgid="1723113469580031041">"แสดงการแจ้งเตือนจากแอปนี้ต่อไปไหม"</string>
+ <string name="notification_unblockable_desc" msgid="1037434112919403708">"ปิดการแจ้งเตือนเหล่านี้ไม่ได้"</string>
<string name="notification_channel_controls_opened_accessibility" msgid="6553950422055908113">"ส่วนควบคุมการแจ้งเตือนของ <xliff:g id="APP_NAME">%1$s</xliff:g> เปิดอยู่"</string>
<string name="notification_channel_controls_closed_accessibility" msgid="7521619812603693144">"ส่วนควบคุมการแจ้งเตือนของ <xliff:g id="APP_NAME">%1$s</xliff:g> ปิดอยู่"</string>
<string name="notification_channel_switch_accessibility" msgid="3420796005601900717">"อนุญาตการแจ้งเตือนจากช่องนี้"</string>
- <string name="notification_all_categories" msgid="5407190218055113282">"ทุกหมวดหมู่"</string>
<string name="notification_more_settings" msgid="816306283396553571">"การตั้งค่าเพิ่มเติม"</string>
- <string name="notification_app_settings" msgid="3743278649182392015">"ปรับแต่ง: <xliff:g id="SUB_CATEGORY">%1$s</xliff:g>"</string>
+ <string name="notification_app_settings" msgid="420348114670768449">"ปรับแต่ง"</string>
<string name="notification_done" msgid="5279426047273930175">"เสร็จสิ้น"</string>
+ <string name="inline_undo" msgid="558916737624706010">"เลิกทำ"</string>
<string name="notification_menu_accessibility" msgid="2046162834248888553">"<xliff:g id="APP_NAME">%1$s</xliff:g> <xliff:g id="MENU_DESCRIPTION">%2$s</xliff:g>"</string>
<string name="notification_menu_gear_description" msgid="2204480013726775108">"ส่วนควบคุมการแจ้งเตือน"</string>
<string name="notification_menu_snooze_description" msgid="3653669438131034525">"ตัวเลือกการปิดเสียงแจ้งเตือนชั่วคราว"</string>
@@ -731,8 +728,7 @@
<string name="pip_phone_expand" msgid="5889780005575693909">"ขยาย"</string>
<string name="pip_phone_minimize" msgid="1079119422589131792">"ย่อเล็กสุด"</string>
<string name="pip_phone_close" msgid="8416647892889710330">"ปิด"</string>
- <!-- no translation found for pip_phone_settings (8080777499521528521) -->
- <skip />
+ <string name="pip_phone_settings" msgid="8080777499521528521">"การตั้งค่า"</string>
<string name="pip_phone_dismiss_hint" msgid="6351678169095923899">"ลากลงเพื่อปิด"</string>
<string name="pip_menu_title" msgid="4707292089961887657">"เมนู"</string>
<string name="pip_notification_title" msgid="3204024940158161322">"<xliff:g id="NAME">%s</xliff:g> ใช้การแสดงภาพซ้อนภาพ"</string>
diff --git a/packages/SystemUI/res/values-tl/strings.xml b/packages/SystemUI/res/values-tl/strings.xml
index dadd57eb87e7..5352cf0497ba 100644
--- a/packages/SystemUI/res/values-tl/strings.xml
+++ b/packages/SystemUI/res/values-tl/strings.xml
@@ -33,7 +33,10 @@
<string name="status_bar_ongoing_events_title" msgid="1682504513316879202">"Nagpapatuloy"</string>
<string name="status_bar_latest_events_title" msgid="6594767438577593172">"Mga Notification"</string>
<string name="battery_low_title" msgid="6456385927409742437">"Mahina na ang baterya"</string>
+ <string name="battery_low_title_hybrid" msgid="6268991275887381595">"Paubos na ang baterya. I-on ang Pangtipid sa Baterya"</string>
<string name="battery_low_percent_format" msgid="2900940511201380775">"<xliff:g id="PERCENTAGE">%s</xliff:g> na lang ang natitira"</string>
+ <string name="battery_low_percent_format_hybrid" msgid="6838677459286775617">"<xliff:g id="PERCENTAGE">%s</xliff:g> na lang ang natitira, humigit-kumulang <xliff:g id="TIME">%s</xliff:g> ang natitira batay sa iyong paggamit"</string>
+ <string name="battery_low_percent_format_hybrid_short" msgid="9025795469949145586">"<xliff:g id="PERCENTAGE">%s</xliff:g> na lang ang natitira, humigit-kumulang <xliff:g id="TIME">%s</xliff:g> ang natitira"</string>
<string name="battery_low_percent_format_saver_started" msgid="7879389868952879166">"<xliff:g id="PERCENTAGE">%s</xliff:g> na lang ang natitira. Naka-on ang Pangtipid sa Baterya."</string>
<string name="invalid_charger" msgid="4549105996740522523">"Hindi sinusuportahan ang pag-charge sa USB.\nGamitin lang ang ibinigay na charger."</string>
<string name="invalid_charger_title" msgid="3515740382572798460">"Hindi sinusuportahan ang pagtsa-charge gamit ang USB."</string>
@@ -67,14 +70,15 @@
<string name="usb_debugging_secondary_user_message" msgid="6067122453571699801">"Hindi mao-on ng user na kasalukuyang naka-sign in sa device na ito ang pag-debug ng USB. Upang magamit ang feature na ito, lumipat sa pangunahing user."</string>
<string name="compat_mode_on" msgid="6623839244840638213">"I-zoom upang punan screen"</string>
<string name="compat_mode_off" msgid="4434467572461327898">"I-stretch upang mapuno screen"</string>
+ <string name="global_action_screenshot" msgid="8329831278085426283">"Screenshot"</string>
<string name="screenshot_saving_ticker" msgid="7403652894056693515">"Sine-save ang screenshot…"</string>
<string name="screenshot_saving_title" msgid="8242282144535555697">"Sine-save ang screenshot…"</string>
- <string name="screenshot_saving_text" msgid="2419718443411738818">"Sine-save ang screenshot."</string>
- <string name="screenshot_saved_title" msgid="6461865960961414961">"Nakuha ang screenshot."</string>
- <string name="screenshot_saved_text" msgid="2685605830386712477">"I-tap upang tingnan ang iyong screenshot."</string>
- <string name="screenshot_failed_title" msgid="705781116746922771">"Hindi makuha ang screenshot."</string>
- <string name="screenshot_failed_to_save_unknown_text" msgid="7887826345701753830">"Nagkaroon ng problema habang sine-save ang screenshot."</string>
- <string name="screenshot_failed_to_save_text" msgid="2592658083866306296">"Hindi ma-save ang screenshot dahil sa limitadong espasyo ng storage."</string>
+ <string name="screenshot_saving_text" msgid="2545047868936087248">"Sine-save ang screenshot"</string>
+ <string name="screenshot_saved_title" msgid="5637073968117370753">"Na-save ang screenshot"</string>
+ <string name="screenshot_saved_text" msgid="7574667448002050363">"I-tap upang tingnan ang iyong screenshot"</string>
+ <string name="screenshot_failed_title" msgid="9096484883063264803">"Hindi makunan ng screenshot"</string>
+ <string name="screenshot_failed_to_save_unknown_text" msgid="8844781948876286488">"Nagkaproblema habang sine-save ang screenshot"</string>
+ <string name="screenshot_failed_to_save_text" msgid="3041612585107107310">"Hindi ma-save ang screenshot dahil sa limitadong espasyo ng storage"</string>
<string name="screenshot_failed_to_capture_text" msgid="173674476457581486">"Hindi pinahihintulutan ng app o ng iyong organisasyon ang pagkuha ng mga screenshot"</string>
<string name="usb_preference_title" msgid="6551050377388882787">"Opsyon paglipat ng USB file"</string>
<string name="use_mtp_button_title" msgid="4333504413563023626">"I-mount bilang isang media player (MTP)"</string>
@@ -557,26 +561,19 @@
<string name="tuner_full_importance_settings_off" msgid="8208165412614935229">"Naka-off"</string>
<string name="power_notification_controls_description" msgid="4372459941671353358">"Sa pamamagitan ng mga kontrol sa notification ng power, magagawa mong itakda ang antas ng kahalagahan ng mga notification ng isang app mula 0 hanggang 5. \n\n"<b>"Antas 5"</b>" \n- Ipakita sa itaas ng listahan ng notification \n- Payagan ang pag-istorbo kapag full screen \n- Palaging sumilip \n\n"<b>"Antas 4"</b>" \n- Pigilan ang pag-istorbo kapag full screen \n- Palaging sumilip \n\n"<b>"Antas 3"</b>" \n- Pigilan ang pag-istorbo kapag full screen \n- Huwag kailanman sumilip \n\n"<b>"Antas 2"</b>" \n- Pigilan ang pag-istorbo kapag full screen \n- Huwag kailanman sumilip \n- Huwag kailanman tumunog o mag-vibrate \n\n"<b>"Antas 1"</b>" \n- Pigilan ang pag-istorbo kapag full screen \n- Huwag kailanman sumilip \n- Huwag kailanman tumunog o mag-vibrate \n- Itago sa lock screen at status bar \n- Ipakita sa ibaba ng listahan ng notification \n\n"<b>"Antas 0"</b>" \n- I-block ang lahat ng notification mula sa app"</string>
<string name="notification_header_default_channel" msgid="7506845022070889909">"Mga Notification"</string>
- <string name="notification_channel_disabled" msgid="2139193533791840539">"Hindi ka na makakatanggap ng ganitong mga notification"</string>
- <string name="notification_num_channels" msgid="2048144408999179471">"<xliff:g id="NUMBER">%d</xliff:g> (na) kategorya ng notification"</string>
- <string name="notification_default_channel_desc" msgid="2506053815870808359">"Walang kategorya ng notification ang app na ito"</string>
- <string name="notification_unblockable_desc" msgid="3561016061737896906">"Hindi maaaring i-off ang mga notification mula sa app na ito"</string>
- <plurals name="notification_num_channels_desc" formatted="false" msgid="5492793452274077663">
- <item quantity="one">1 sa <xliff:g id="NUMBER_1">%s</xliff:g> kategorya ng notification mula sa app na ito</item>
- <item quantity="other">1 sa <xliff:g id="NUMBER_1">%s</xliff:g> na kategorya ng notification mula sa app na ito</item>
- </plurals>
- <string name="notification_channels_list_desc_2" msgid="6214732715833946441">"<xliff:g id="CHANNEL_NAME_1">%1$s</xliff:g>, <xliff:g id="CHANNEL_NAME_2">%2$s</xliff:g>"</string>
- <plurals name="notification_channels_list_desc_2_and_others" formatted="false" msgid="2747813553355336157">
- <item quantity="one"><xliff:g id="CHANNEL_NAME_1_3">%1$s</xliff:g>, <xliff:g id="CHANNEL_NAME_2_4">%2$s</xliff:g>, at <xliff:g id="NUMBER_5">%3$d</xliff:g> pang iba</item>
- <item quantity="other"><xliff:g id="CHANNEL_NAME_1_3">%1$s</xliff:g>, <xliff:g id="CHANNEL_NAME_2_4">%2$s</xliff:g>, at <xliff:g id="NUMBER_5">%3$d</xliff:g> pang iba</item>
- </plurals>
+ <string name="notification_channel_disabled" msgid="344536703863700565">"Hindi mo na makikita ang mga notification na ito"</string>
+ <string name="inline_keep_showing" msgid="8945102997083836858">"Patuloy na ipakita ang mga notification na ito?"</string>
+ <string name="inline_stop_button" msgid="4172980096860941033">"Ihinto ang mga notification"</string>
+ <string name="inline_keep_button" msgid="6665940297019018232">"Patuloy na ipakita"</string>
+ <string name="inline_keep_showing_app" msgid="1723113469580031041">"Patuloy na ipakita ang mga notification mula sa app na ito?"</string>
+ <string name="notification_unblockable_desc" msgid="1037434112919403708">"Hindi maaaring i-off ang mga notification na ito"</string>
<string name="notification_channel_controls_opened_accessibility" msgid="6553950422055908113">"Binuksan ang mga kontrol sa notification para sa <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
<string name="notification_channel_controls_closed_accessibility" msgid="7521619812603693144">"Isinara ang mga kontrol sa notification para sa <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
<string name="notification_channel_switch_accessibility" msgid="3420796005601900717">"Payagan ang mga notification mula sa channel na ito"</string>
- <string name="notification_all_categories" msgid="5407190218055113282">"Lahat ng Kategorya"</string>
<string name="notification_more_settings" msgid="816306283396553571">"Higit pang mga setting"</string>
- <string name="notification_app_settings" msgid="3743278649182392015">"I-customize: <xliff:g id="SUB_CATEGORY">%1$s</xliff:g>"</string>
+ <string name="notification_app_settings" msgid="420348114670768449">"I-customize"</string>
<string name="notification_done" msgid="5279426047273930175">"Tapos Na"</string>
+ <string name="inline_undo" msgid="558916737624706010">"I-undo"</string>
<string name="notification_menu_accessibility" msgid="2046162834248888553">"<xliff:g id="APP_NAME">%1$s</xliff:g> <xliff:g id="MENU_DESCRIPTION">%2$s</xliff:g>"</string>
<string name="notification_menu_gear_description" msgid="2204480013726775108">"mga kontrol ng notification"</string>
<string name="notification_menu_snooze_description" msgid="3653669438131034525">"mga opsyon sa pag-snooze ng notification"</string>
@@ -731,8 +728,7 @@
<string name="pip_phone_expand" msgid="5889780005575693909">"Palawakin"</string>
<string name="pip_phone_minimize" msgid="1079119422589131792">"I-minimize"</string>
<string name="pip_phone_close" msgid="8416647892889710330">"Isara"</string>
- <!-- no translation found for pip_phone_settings (8080777499521528521) -->
- <skip />
+ <string name="pip_phone_settings" msgid="8080777499521528521">"Mga Setting"</string>
<string name="pip_phone_dismiss_hint" msgid="6351678169095923899">"I-drag pababa upang i-dismiss"</string>
<string name="pip_menu_title" msgid="4707292089961887657">"Menu"</string>
<string name="pip_notification_title" msgid="3204024940158161322">"Nasa picture-in-picture ang <xliff:g id="NAME">%s</xliff:g>"</string>
diff --git a/packages/SystemUI/res/values-tr/strings.xml b/packages/SystemUI/res/values-tr/strings.xml
index d2d8ac659e38..092cfa50606d 100644
--- a/packages/SystemUI/res/values-tr/strings.xml
+++ b/packages/SystemUI/res/values-tr/strings.xml
@@ -33,7 +33,10 @@
<string name="status_bar_ongoing_events_title" msgid="1682504513316879202">"Sürüyor"</string>
<string name="status_bar_latest_events_title" msgid="6594767438577593172">"Bildirimler"</string>
<string name="battery_low_title" msgid="6456385927409742437">"Pil gücü düşük"</string>
+ <string name="battery_low_title_hybrid" msgid="6268991275887381595">"Pil az. Pil Tasarrufu\'nu açın"</string>
<string name="battery_low_percent_format" msgid="2900940511201380775">"<xliff:g id="PERCENTAGE">%s</xliff:g> kaldı"</string>
+ <string name="battery_low_percent_format_hybrid" msgid="6838677459286775617">"<xliff:g id="PERCENTAGE">%s</xliff:g> kaldı (kullanımınıza göre yaklaşık <xliff:g id="TIME">%s</xliff:g>)"</string>
+ <string name="battery_low_percent_format_hybrid_short" msgid="9025795469949145586">"<xliff:g id="PERCENTAGE">%s</xliff:g> (yaklaşık <xliff:g id="TIME">%s</xliff:g>) kaldı"</string>
<string name="battery_low_percent_format_saver_started" msgid="7879389868952879166">"<xliff:g id="PERCENTAGE">%s</xliff:g> kaldı. Pil Tasarrufu açık."</string>
<string name="invalid_charger" msgid="4549105996740522523">"USB üzerinden şarj desteklenmiyor.\nYalnızca ürünle birlikte verilen şarj cihazını kullanın."</string>
<string name="invalid_charger_title" msgid="3515740382572798460">"USB şarjı desteklenmiyor."</string>
@@ -67,14 +70,15 @@
<string name="usb_debugging_secondary_user_message" msgid="6067122453571699801">"Bu cihazda geçerli olarak oturum açmış olan kullanıcı, USB hata ayıklama özelliğini açamaz. Bu özelliği kullanmak için birincil kullanıcıya geçin."</string>
<string name="compat_mode_on" msgid="6623839244840638213">"Yakınlaştır (ekranı kaplasın)"</string>
<string name="compat_mode_off" msgid="4434467572461327898">"Genişlet (ekran kapansın)"</string>
+ <string name="global_action_screenshot" msgid="8329831278085426283">"Ekran görüntüsü"</string>
<string name="screenshot_saving_ticker" msgid="7403652894056693515">"Ekran görüntüsü kaydediliyor..."</string>
<string name="screenshot_saving_title" msgid="8242282144535555697">"Ekran görüntüsü kaydediliyor..."</string>
- <string name="screenshot_saving_text" msgid="2419718443411738818">"Ekran görüntüsü kaydediliyor."</string>
- <string name="screenshot_saved_title" msgid="6461865960961414961">"Ekran görüntüsü alındı."</string>
- <string name="screenshot_saved_text" msgid="2685605830386712477">"Ekran görüntünüzü görüntülemek için dokunun."</string>
- <string name="screenshot_failed_title" msgid="705781116746922771">"Ekran görüntüsü alınamadı."</string>
- <string name="screenshot_failed_to_save_unknown_text" msgid="7887826345701753830">"Ekran görüntüsü kaydedilirken sorun oluştu."</string>
- <string name="screenshot_failed_to_save_text" msgid="2592658083866306296">"Depolama alanı sınırlı olduğundan ekran görüntüsü kaydedilemiyor."</string>
+ <string name="screenshot_saving_text" msgid="2545047868936087248">"Ekran görüntüsü kaydediliyor"</string>
+ <string name="screenshot_saved_title" msgid="5637073968117370753">"Ekran görüntüsü kaydedildi"</string>
+ <string name="screenshot_saved_text" msgid="7574667448002050363">"Ekran görüntünüzü görmek için dokunun"</string>
+ <string name="screenshot_failed_title" msgid="9096484883063264803">"Ekran görüntüsü alınamadı"</string>
+ <string name="screenshot_failed_to_save_unknown_text" msgid="8844781948876286488">"Ekran görüntüsü kaydedilirken sorun oluştu"</string>
+ <string name="screenshot_failed_to_save_text" msgid="3041612585107107310">"Depolama alanı sınırlı olduğundan ekran görüntüsü kaydedilemiyor"</string>
<string name="screenshot_failed_to_capture_text" msgid="173674476457581486">"Uygulama veya kuruluşunuz, ekran görüntüsü alınmasına izin vermiyor."</string>
<string name="usb_preference_title" msgid="6551050377388882787">"USB dosya aktarım seçenekleri"</string>
<string name="use_mtp_button_title" msgid="4333504413563023626">"Medya oynatıcı olarak ekle (MTP)"</string>
@@ -557,26 +561,19 @@
<string name="tuner_full_importance_settings_off" msgid="8208165412614935229">"Kapalı"</string>
<string name="power_notification_controls_description" msgid="4372459941671353358">"Güç bildirim kontrolleriyle, bir uygulamanın bildirimleri için 0 ile 5 arasında bir önem düzeyi ayarlayabilirsiniz. \n\n"<b>"5. Düzey"</b>" \n- Bildirim listesinin en üstünde gösterilsin \n- Tam ekran kesintisine izin verilsin \n- Ekranda her zaman kısaca belirsin \n\n"<b>"4. Düzey"</b>" \n- Tam ekran kesintisi engellensin \n- Ekranda her zaman kısaca belirsin \n\n"<b>"3. Düzey"</b>" \n- Tam ekran kesintisi engellensin \n- Ekranda hiçbir zaman kısaca belirmesin \n\n"<b>"2. Düzey"</b>" \n- Tam ekran kesintisi engellensin \n- Ekranda hiçbir zaman belirmesin \n- Hiçbir zaman ses çıkarmasın ve titreştirmesin \n\n"<b>"1. Düzey"</b>" \n- Tam ekran kesintisi engellensin \n- Ekranda hiçbir zaman kısaca belirmesin \n- Hiçbir zaman ses çıkarmasın veya titreştirmesin \n- Kilit ekranından ve durum çubuğundan gizlensin \n- Bildirim listesinin en altında gösterilsin \n\n"<b>"0. Düzey"</b>" \n- Uygulamadan gelen tüm bildirimler engellensin"</string>
<string name="notification_header_default_channel" msgid="7506845022070889909">"Bildirimler"</string>
- <string name="notification_channel_disabled" msgid="2139193533791840539">"Bu bildirimleri artık almayacaksınız"</string>
- <string name="notification_num_channels" msgid="2048144408999179471">"<xliff:g id="NUMBER">%d</xliff:g> bildirim kategorisi"</string>
- <string name="notification_default_channel_desc" msgid="2506053815870808359">"Bu uygulamanın bildirim kategorisi yok"</string>
- <string name="notification_unblockable_desc" msgid="3561016061737896906">"Bu uygulamanın bildirimleri kapatılamaz"</string>
- <plurals name="notification_num_channels_desc" formatted="false" msgid="5492793452274077663">
- <item quantity="other">Bu uygulamadaki <xliff:g id="NUMBER_1">%s</xliff:g> bildirim kategorisinden 1 tanesi</item>
- <item quantity="one">Bu uygulamadaki <xliff:g id="NUMBER_0">%s</xliff:g> bildirim kategorisinden 1 tanesi</item>
- </plurals>
- <string name="notification_channels_list_desc_2" msgid="6214732715833946441">"<xliff:g id="CHANNEL_NAME_1">%1$s</xliff:g>, <xliff:g id="CHANNEL_NAME_2">%2$s</xliff:g>"</string>
- <plurals name="notification_channels_list_desc_2_and_others" formatted="false" msgid="2747813553355336157">
- <item quantity="other"><xliff:g id="CHANNEL_NAME_1_3">%1$s</xliff:g>, <xliff:g id="CHANNEL_NAME_2_4">%2$s</xliff:g> ve diğer <xliff:g id="NUMBER_5">%3$d</xliff:g></item>
- <item quantity="one"><xliff:g id="CHANNEL_NAME_1_0">%1$s</xliff:g>, <xliff:g id="CHANNEL_NAME_2_1">%2$s</xliff:g> ve <xliff:g id="NUMBER_2">%3$d</xliff:g> tane daha</item>
- </plurals>
+ <string name="notification_channel_disabled" msgid="344536703863700565">"Bu bildirimleri artık görmeyeceksiniz"</string>
+ <string name="inline_keep_showing" msgid="8945102997083836858">"Bu bildirimler gösterilmeye devam edilsin mi?"</string>
+ <string name="inline_stop_button" msgid="4172980096860941033">"Bildirimleri durdur"</string>
+ <string name="inline_keep_button" msgid="6665940297019018232">"Göstermeye devam et"</string>
+ <string name="inline_keep_showing_app" msgid="1723113469580031041">"Bu uygulamadan gelen bildirimler gösterilmeye devam edilsin mi?"</string>
+ <string name="notification_unblockable_desc" msgid="1037434112919403708">"Bu bildirimler kapatılamaz"</string>
<string name="notification_channel_controls_opened_accessibility" msgid="6553950422055908113">"<xliff:g id="APP_NAME">%1$s</xliff:g> için bildirim kontrolleri açıldı"</string>
<string name="notification_channel_controls_closed_accessibility" msgid="7521619812603693144">"<xliff:g id="APP_NAME">%1$s</xliff:g> için bildirim kontrolleri kapatıldı"</string>
<string name="notification_channel_switch_accessibility" msgid="3420796005601900717">"Bu kanaldan bildirimlere izin verir"</string>
- <string name="notification_all_categories" msgid="5407190218055113282">"Tüm Kategoriler"</string>
<string name="notification_more_settings" msgid="816306283396553571">"Diğer ayarlar"</string>
- <string name="notification_app_settings" msgid="3743278649182392015">"Özelleştir: <xliff:g id="SUB_CATEGORY">%1$s</xliff:g>"</string>
+ <string name="notification_app_settings" msgid="420348114670768449">"Özelleştir"</string>
<string name="notification_done" msgid="5279426047273930175">"Bitti"</string>
+ <string name="inline_undo" msgid="558916737624706010">"Geri al"</string>
<string name="notification_menu_accessibility" msgid="2046162834248888553">"<xliff:g id="APP_NAME">%1$s</xliff:g> <xliff:g id="MENU_DESCRIPTION">%2$s</xliff:g>"</string>
<string name="notification_menu_gear_description" msgid="2204480013726775108">"Bildirim kontrolleri"</string>
<string name="notification_menu_snooze_description" msgid="3653669438131034525">"bildirim erteleme seçenekleri"</string>
@@ -731,8 +728,7 @@
<string name="pip_phone_expand" msgid="5889780005575693909">"Genişlet"</string>
<string name="pip_phone_minimize" msgid="1079119422589131792">"Simge durumuna getir"</string>
<string name="pip_phone_close" msgid="8416647892889710330">"Kapat"</string>
- <!-- no translation found for pip_phone_settings (8080777499521528521) -->
- <skip />
+ <string name="pip_phone_settings" msgid="8080777499521528521">"Ayarlar"</string>
<string name="pip_phone_dismiss_hint" msgid="6351678169095923899">"Kapatmak için aşağıya sürükleyin"</string>
<string name="pip_menu_title" msgid="4707292089961887657">"Menü"</string>
<string name="pip_notification_title" msgid="3204024940158161322">"<xliff:g id="NAME">%s</xliff:g>, pencere içinde pencere özelliğini kullanıyor"</string>
diff --git a/packages/SystemUI/res/values-ur/strings.xml b/packages/SystemUI/res/values-ur/strings.xml
index e2023637e325..ffcb60a619f4 100644
--- a/packages/SystemUI/res/values-ur/strings.xml
+++ b/packages/SystemUI/res/values-ur/strings.xml
@@ -33,13 +33,10 @@
<string name="status_bar_ongoing_events_title" msgid="1682504513316879202">"جاری"</string>
<string name="status_bar_latest_events_title" msgid="6594767438577593172">"اطلاعات"</string>
<string name="battery_low_title" msgid="6456385927409742437">"بیٹری کم ہے"</string>
- <!-- no translation found for battery_low_title_hybrid (6268991275887381595) -->
- <skip />
+ <string name="battery_low_title_hybrid" msgid="6268991275887381595">"بیٹری کم ہے۔ بیٹری سیور آن کریں"</string>
<string name="battery_low_percent_format" msgid="2900940511201380775">"<xliff:g id="PERCENTAGE">%s</xliff:g> باقی ہے"</string>
- <!-- no translation found for battery_low_percent_format_hybrid (6838677459286775617) -->
- <skip />
- <!-- no translation found for battery_low_percent_format_hybrid_short (9025795469949145586) -->
- <skip />
+ <string name="battery_low_percent_format_hybrid" msgid="6838677459286775617">"<xliff:g id="PERCENTAGE">%s</xliff:g> باقی، آپ کے استعمال کی بنیاد پر تقریباً <xliff:g id="TIME">%s</xliff:g> باقی ہے"</string>
+ <string name="battery_low_percent_format_hybrid_short" msgid="9025795469949145586">"<xliff:g id="PERCENTAGE">%s</xliff:g> باقی، تقریباً <xliff:g id="TIME">%s</xliff:g> باقی ہے"</string>
<string name="battery_low_percent_format_saver_started" msgid="7879389868952879166">"<xliff:g id="PERCENTAGE">%s</xliff:g> باقی ہے۔ بیٹری سیور آن ہے۔"</string>
<string name="invalid_charger" msgid="4549105996740522523">"‏USB چارجنگ تعاون یافتہ نہیں ہے.\nصرف فراہم کردہ چارجر کا ہی استعمال کریں۔"</string>
<string name="invalid_charger_title" msgid="3515740382572798460">"‏USB چارجنگ تعاون یافتہ نہیں ہے۔"</string>
@@ -73,22 +70,15 @@
<string name="usb_debugging_secondary_user_message" msgid="6067122453571699801">"‏اس آلہ پر فی الحال سائن ان کردہ صارف USB ڈیبگنگ آن نہیں کر سکتا۔ اس خصوصیت کا استعمال کرنے کیلئے، ابتدائی صارف پر سوئچ کریں۔"</string>
<string name="compat_mode_on" msgid="6623839244840638213">"پوری سکرین پر زوم کریں"</string>
<string name="compat_mode_off" msgid="4434467572461327898">"پوری سکرین پر پھیلائیں"</string>
- <!-- no translation found for global_action_screenshot (8329831278085426283) -->
- <skip />
+ <string name="global_action_screenshot" msgid="8329831278085426283">"اسکرین شاٹ"</string>
<string name="screenshot_saving_ticker" msgid="7403652894056693515">"اسکرین شاٹ محفوظ ہو رہا ہے…"</string>
<string name="screenshot_saving_title" msgid="8242282144535555697">"اسکرین شاٹ محفوظ ہو رہا ہے…"</string>
- <!-- no translation found for screenshot_saving_text (2545047868936087248) -->
- <skip />
- <!-- no translation found for screenshot_saved_title (5637073968117370753) -->
- <skip />
- <!-- no translation found for screenshot_saved_text (7574667448002050363) -->
- <skip />
- <!-- no translation found for screenshot_failed_title (9096484883063264803) -->
- <skip />
- <!-- no translation found for screenshot_failed_to_save_unknown_text (8844781948876286488) -->
- <skip />
- <!-- no translation found for screenshot_failed_to_save_text (3041612585107107310) -->
- <skip />
+ <string name="screenshot_saving_text" msgid="2545047868936087248">"اسکرین شاٹ محفوظ کیا جا رہا ہے"</string>
+ <string name="screenshot_saved_title" msgid="5637073968117370753">"اسکرین شاٹ محفوظ ہو گیا"</string>
+ <string name="screenshot_saved_text" msgid="7574667448002050363">"اپنا اسکرین شاٹ دیکھنے کیلئے تھپتھپائیں"</string>
+ <string name="screenshot_failed_title" msgid="9096484883063264803">"اسکرین شاٹ کیپچر نہیں ہو سکا"</string>
+ <string name="screenshot_failed_to_save_unknown_text" msgid="8844781948876286488">"اسکرین شاٹ محفوظ کرتے وقت مسئلہ پیش آ گیا"</string>
+ <string name="screenshot_failed_to_save_text" msgid="3041612585107107310">"اسٹوریج کی محدود جگہ کی وجہ سے اسکرین شاٹ کو محفوظ نہیں کیا جا سکتا"</string>
<string name="screenshot_failed_to_capture_text" msgid="173674476457581486">"ایپ یا آپ کی تنظیم کی جانب سے اسکرین شاٹس لینے کی اجازت نہیں ہے"</string>
<string name="usb_preference_title" msgid="6551050377388882787">"‏USB فائل منتقل کرنیکے اختیارات"</string>
<string name="use_mtp_button_title" msgid="4333504413563023626">"‏ایک میڈیا پلیئر (MTP) کے بطور ماؤنٹ کریں"</string>
@@ -571,27 +561,19 @@
<string name="tuner_full_importance_settings_off" msgid="8208165412614935229">"آف"</string>
<string name="power_notification_controls_description" msgid="4372459941671353358">"پاور اطلاع کنٹرولز کے ساتھ آپ کسی ایپ کی اطلاعات کیلئے 0 سے 5 تک اہمیت کی سطح سیٹ کر سکتے ہیں۔ \n\n"<b>"سطح 5"</b>\n"- اطلاعات کی فہرست کے اوپر دکھائیں \n- پوری اسکرین کی مداخلت کی اجازت دیں \n- ہمیشہ جھانکنا\n\n"<b>"سطح 4"</b>\n"- پوری اسکرین کی مداخلت کو روکیں \n- ہمیشہ جھانکنا\n\n"<b>"سطح 3"</b>\n"- پوری اسکرین کی مداخلت کو روکیں \n- کبھی نہ جھانکنا \n\n"<b>"سطح 2"</b>\n"- پوری اسکرین کی مداخلت کو روکیں \n- کبھی نہ جھانکنا \n- کبھی آواز اور ارتعاش پیدا نہ کرنا \n\n"<b>" سطح 1"</b>\n"- پوری اسکرین کی مداخلت کو روکنا \n- کبھی نہ جھانکنا \n- کبھی بھی آواز یا ارتعاش پیدا نہ کرنا\n- مقفل اسکرین اور اسٹیٹس بار سے چھپانا \n - اطلاع کی فہرست کی نیچے دکھانا \n\n"<b>"سطح 0"</b>\n"- ایپ سے تمام اطلاعات مسدود کریں"</string>
<string name="notification_header_default_channel" msgid="7506845022070889909">"اطلاعات"</string>
- <!-- no translation found for notification_channel_disabled (344536703863700565) -->
- <skip />
- <!-- no translation found for inline_keep_showing (8945102997083836858) -->
- <skip />
- <!-- no translation found for inline_stop_button (4172980096860941033) -->
- <skip />
- <!-- no translation found for inline_keep_button (6665940297019018232) -->
- <skip />
- <!-- no translation found for inline_keep_showing_app (1723113469580031041) -->
- <skip />
- <!-- no translation found for notification_unblockable_desc (1037434112919403708) -->
- <skip />
+ <string name="notification_channel_disabled" msgid="344536703863700565">"آپ کو یہ اطلاعات مزید دکھائی نہیں دیں گی"</string>
+ <string name="inline_keep_showing" msgid="8945102997083836858">"یہ اطلاعات دکھانا جاری رکھیں؟"</string>
+ <string name="inline_stop_button" msgid="4172980096860941033">"اطلاعات روک دیں"</string>
+ <string name="inline_keep_button" msgid="6665940297019018232">"دکھانا جاری رکھیں"</string>
+ <string name="inline_keep_showing_app" msgid="1723113469580031041">"اس ایپ کی طرف سے اطلاعات دکھانا جاری رکھیں؟"</string>
+ <string name="notification_unblockable_desc" msgid="1037434112919403708">"ان اطلاعات کو آف نہیں کیا جا سکتا"</string>
<string name="notification_channel_controls_opened_accessibility" msgid="6553950422055908113">"<xliff:g id="APP_NAME">%1$s</xliff:g> کیلئے اطلاعی کنٹرولز کھلے ہیں"</string>
<string name="notification_channel_controls_closed_accessibility" msgid="7521619812603693144">"<xliff:g id="APP_NAME">%1$s</xliff:g> کیلئے اطلاعی کنٹرولز بند کر دئے گئے ہیں"</string>
<string name="notification_channel_switch_accessibility" msgid="3420796005601900717">"اس چینل سے اطلاعات کی اجازت دیں"</string>
<string name="notification_more_settings" msgid="816306283396553571">"مزید ترتیبات"</string>
- <!-- no translation found for notification_app_settings (420348114670768449) -->
- <skip />
+ <string name="notification_app_settings" msgid="420348114670768449">"حسب ضرورت بنائیں"</string>
<string name="notification_done" msgid="5279426047273930175">"ہوگیا"</string>
- <!-- no translation found for inline_undo (558916737624706010) -->
- <skip />
+ <string name="inline_undo" msgid="558916737624706010">"کالعدم کریں"</string>
<string name="notification_menu_accessibility" msgid="2046162834248888553">"<xliff:g id="APP_NAME">%1$s</xliff:g> <xliff:g id="MENU_DESCRIPTION">%2$s</xliff:g>"</string>
<string name="notification_menu_gear_description" msgid="2204480013726775108">"اطلاع کے کنٹرولز"</string>
<string name="notification_menu_snooze_description" msgid="3653669438131034525">"اطلاع اسنوز کرنے کے اختیارات"</string>
diff --git a/packages/SystemUI/res/values-vi/strings.xml b/packages/SystemUI/res/values-vi/strings.xml
index 75b18caea63c..e5c25dcf9a34 100644
--- a/packages/SystemUI/res/values-vi/strings.xml
+++ b/packages/SystemUI/res/values-vi/strings.xml
@@ -33,7 +33,10 @@
<string name="status_bar_ongoing_events_title" msgid="1682504513316879202">"Đang diễn ra"</string>
<string name="status_bar_latest_events_title" msgid="6594767438577593172">"Thông báo"</string>
<string name="battery_low_title" msgid="6456385927409742437">"Pin yếu"</string>
+ <string name="battery_low_title_hybrid" msgid="6268991275887381595">"Pin yếu. Bật Trình tiết kiệm pin"</string>
<string name="battery_low_percent_format" msgid="2900940511201380775">"Còn lại <xliff:g id="PERCENTAGE">%s</xliff:g>"</string>
+ <string name="battery_low_percent_format_hybrid" msgid="6838677459286775617">"Còn lại <xliff:g id="PERCENTAGE">%s</xliff:g>, còn khoảng <xliff:g id="TIME">%s</xliff:g> dựa trên mức sử dụng của bạn"</string>
+ <string name="battery_low_percent_format_hybrid_short" msgid="9025795469949145586">"Còn lại <xliff:g id="PERCENTAGE">%s</xliff:g>, còn khoảng <xliff:g id="TIME">%s</xliff:g>"</string>
<string name="battery_low_percent_format_saver_started" msgid="7879389868952879166">"Còn lại <xliff:g id="PERCENTAGE">%s</xliff:g>. Trình tiết kiệm pin đang bật."</string>
<string name="invalid_charger" msgid="4549105996740522523">"Không hỗ trợ sạc qua USB.\nChỉ sử dụng bộ sạc được cung cấp."</string>
<string name="invalid_charger_title" msgid="3515740382572798460">"Sạc qua USB không được hỗ trợ."</string>
@@ -67,14 +70,15 @@
<string name="usb_debugging_secondary_user_message" msgid="6067122453571699801">"Người dùng hiện đã đăng nhập vào thiết bị này không thể bật tính năng gỡ lỗi USB. Để sử dụng tính năng này, hãy chuyển sang người dùng chính."</string>
<string name="compat_mode_on" msgid="6623839244840638213">"T.phóng để lấp đầy m.hình"</string>
<string name="compat_mode_off" msgid="4434467572461327898">"Giãn ra để lấp đầy m.hình"</string>
+ <string name="global_action_screenshot" msgid="8329831278085426283">"Ảnh chụp màn hình"</string>
<string name="screenshot_saving_ticker" msgid="7403652894056693515">"Đang lưu ảnh chụp màn hình..."</string>
<string name="screenshot_saving_title" msgid="8242282144535555697">"Đang lưu ảnh chụp màn hình..."</string>
- <string name="screenshot_saving_text" msgid="2419718443411738818">"Ảnh chụp màn hình đang được lưu."</string>
- <string name="screenshot_saved_title" msgid="6461865960961414961">"Đã chụp ảnh màn hình."</string>
- <string name="screenshot_saved_text" msgid="2685605830386712477">"Nhấn để xem ảnh chụp màn hình của bạn."</string>
- <string name="screenshot_failed_title" msgid="705781116746922771">"Không thể chụp ảnh màn hình."</string>
- <string name="screenshot_failed_to_save_unknown_text" msgid="7887826345701753830">"Đã gặp phải sự cố khi đang lưu ảnh chụp màn hình."</string>
- <string name="screenshot_failed_to_save_text" msgid="2592658083866306296">"Không thể lưu ảnh chụp màn hình do giới hạn dung lượng bộ nhớ."</string>
+ <string name="screenshot_saving_text" msgid="2545047868936087248">"Đang lưu ảnh chụp màn hình"</string>
+ <string name="screenshot_saved_title" msgid="5637073968117370753">"Đã lưu ảnh chụp màn hình"</string>
+ <string name="screenshot_saved_text" msgid="7574667448002050363">"Nhấn để xem ảnh chụp màn hình của bạn"</string>
+ <string name="screenshot_failed_title" msgid="9096484883063264803">"Không thể chụp ảnh màn hình"</string>
+ <string name="screenshot_failed_to_save_unknown_text" msgid="8844781948876286488">"Đã xảy ra sự cố khi lưu ảnh chụp màn hình"</string>
+ <string name="screenshot_failed_to_save_text" msgid="3041612585107107310">"Không thể lưu ảnh chụp màn hình do giới hạn dung lượng bộ nhớ"</string>
<string name="screenshot_failed_to_capture_text" msgid="173674476457581486">"Ứng dụng hoặc tổ chức của bạn không cho phép chụp ảnh màn hình"</string>
<string name="usb_preference_title" msgid="6551050377388882787">"Tùy chọn truyền tệp USB"</string>
<string name="use_mtp_button_title" msgid="4333504413563023626">"Gắn như một trình phát đa phương tiện (MTP)"</string>
@@ -559,26 +563,19 @@
<string name="tuner_full_importance_settings_off" msgid="8208165412614935229">"Tắt"</string>
<string name="power_notification_controls_description" msgid="4372459941671353358">"Với các kiểm soát thông báo nguồn, bạn có thể đặt cấp độ quan trọng từ 0 đến 5 cho các thông báo của ứng dụng. \n\n"<b>"Cấp 5"</b>" \n- Hiển thị ở đầu danh sách thông báo \n- Cho phép gián đoạn ở chế độ toàn màn hình \n- Luôn xem nhanh \n\n"<b>"Cấp 4"</b>" \n- Ngăn gián đoạn ở chế độ toàn màn hình \n- Luôn xem nhanh \n\n"<b>"Cấp 3"</b>" \n- Ngăn gián đoạn ở chế độ toàn màn hình \n- Không bao giờ xem nhanh \n\n"<b>"Cấp 2"</b>" \n- Ngăn gián đoạn ở chế độ toàn màn hình \n- Không bao giờ xem nhanh \n- Không bao giờ có âm báo và rung \n\n"<b>"Cấp 1"</b>" \n- Ngăn gián đoạn ở chế độ toàn màn hình \n- Không bao giờ xem nhanh \n- Không bao giờ có âm báo và rung \n- Ẩn khỏi màn hình khóa và thanh trạng thái \n- Hiển thị ở cuối danh sách thông báo \n\n"<b>"Cấp 0"</b>" \n- Chặn tất cả các thông báo từ ứng dụng"</string>
<string name="notification_header_default_channel" msgid="7506845022070889909">"Thông báo"</string>
- <string name="notification_channel_disabled" msgid="2139193533791840539">"Bạn sẽ không nhận được những thông báo này nữa"</string>
- <string name="notification_num_channels" msgid="2048144408999179471">"<xliff:g id="NUMBER">%d</xliff:g> danh mục thông báo"</string>
- <string name="notification_default_channel_desc" msgid="2506053815870808359">"Ứng dụng này không có loại thông báo"</string>
- <string name="notification_unblockable_desc" msgid="3561016061737896906">"Không thể tắt thông báo từ ứng dụng này"</string>
- <plurals name="notification_num_channels_desc" formatted="false" msgid="5492793452274077663">
- <item quantity="other">1 trên tổng số <xliff:g id="NUMBER_1">%s</xliff:g> loại thông báo từ ứng dụng này</item>
- <item quantity="one">1 trên tổng số <xliff:g id="NUMBER_0">%s</xliff:g> loại thông báo từ ứng dụng này</item>
- </plurals>
- <string name="notification_channels_list_desc_2" msgid="6214732715833946441">"<xliff:g id="CHANNEL_NAME_1">%1$s</xliff:g>, <xliff:g id="CHANNEL_NAME_2">%2$s</xliff:g>"</string>
- <plurals name="notification_channels_list_desc_2_and_others" formatted="false" msgid="2747813553355336157">
- <item quantity="other"><xliff:g id="CHANNEL_NAME_1_3">%1$s</xliff:g>, <xliff:g id="CHANNEL_NAME_2_4">%2$s</xliff:g> và <xliff:g id="NUMBER_5">%3$d</xliff:g> kênh khác</item>
- <item quantity="one"><xliff:g id="CHANNEL_NAME_1_0">%1$s</xliff:g>, <xliff:g id="CHANNEL_NAME_2_1">%2$s</xliff:g> và <xliff:g id="NUMBER_2">%3$d</xliff:g> kênh khác</item>
- </plurals>
+ <string name="notification_channel_disabled" msgid="344536703863700565">"Bạn sẽ không thấy các thông báo này nữa"</string>
+ <string name="inline_keep_showing" msgid="8945102997083836858">"Tiếp tục hiển thị các thông báo này?"</string>
+ <string name="inline_stop_button" msgid="4172980096860941033">"Dừng thông báo"</string>
+ <string name="inline_keep_button" msgid="6665940297019018232">"Tiếp tục hiển thị"</string>
+ <string name="inline_keep_showing_app" msgid="1723113469580031041">"Tiếp tục hiển thị các thông báo từ ứng dụng này?"</string>
+ <string name="notification_unblockable_desc" msgid="1037434112919403708">"Không thể tắt các thông báo này"</string>
<string name="notification_channel_controls_opened_accessibility" msgid="6553950422055908113">"Đã mở điều khiển thông báo đối với <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
<string name="notification_channel_controls_closed_accessibility" msgid="7521619812603693144">"Đã đóng điều khiển thông báo đối với <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
<string name="notification_channel_switch_accessibility" msgid="3420796005601900717">"Cho phép thông báo từ kênh này"</string>
- <string name="notification_all_categories" msgid="5407190218055113282">"Tất cả danh mục"</string>
<string name="notification_more_settings" msgid="816306283396553571">"Cài đặt khác"</string>
- <string name="notification_app_settings" msgid="3743278649182392015">"Tùy chỉnh: <xliff:g id="SUB_CATEGORY">%1$s</xliff:g>"</string>
+ <string name="notification_app_settings" msgid="420348114670768449">"Tùy chỉnh"</string>
<string name="notification_done" msgid="5279426047273930175">"Xong"</string>
+ <string name="inline_undo" msgid="558916737624706010">"Hoàn tác"</string>
<string name="notification_menu_accessibility" msgid="2046162834248888553">"<xliff:g id="APP_NAME">%1$s</xliff:g> <xliff:g id="MENU_DESCRIPTION">%2$s</xliff:g>"</string>
<string name="notification_menu_gear_description" msgid="2204480013726775108">"điều khiển thông báo"</string>
<string name="notification_menu_snooze_description" msgid="3653669438131034525">"Tùy chọn báo lại thông báo"</string>
@@ -733,8 +730,7 @@
<string name="pip_phone_expand" msgid="5889780005575693909">"Mở rộng"</string>
<string name="pip_phone_minimize" msgid="1079119422589131792">"Thu nhỏ"</string>
<string name="pip_phone_close" msgid="8416647892889710330">"Đóng"</string>
- <!-- no translation found for pip_phone_settings (8080777499521528521) -->
- <skip />
+ <string name="pip_phone_settings" msgid="8080777499521528521">"Cài đặt"</string>
<string name="pip_phone_dismiss_hint" msgid="6351678169095923899">"Kéo xuống để loại bỏ"</string>
<string name="pip_menu_title" msgid="4707292089961887657">"Menu"</string>
<string name="pip_notification_title" msgid="3204024940158161322">"<xliff:g id="NAME">%s</xliff:g> đang ở chế độ ảnh trong ảnh"</string>
diff --git a/packages/SystemUI/res/values-zh-rCN/strings.xml b/packages/SystemUI/res/values-zh-rCN/strings.xml
index 16161ee16276..94a9961869f4 100644
--- a/packages/SystemUI/res/values-zh-rCN/strings.xml
+++ b/packages/SystemUI/res/values-zh-rCN/strings.xml
@@ -33,7 +33,13 @@
<string name="status_bar_ongoing_events_title" msgid="1682504513316879202">"正在进行的"</string>
<string name="status_bar_latest_events_title" msgid="6594767438577593172">"通知"</string>
<string name="battery_low_title" msgid="6456385927409742437">"电池电量偏低"</string>
+ <!-- no translation found for battery_low_title_hybrid (6268991275887381595) -->
+ <skip />
<string name="battery_low_percent_format" msgid="2900940511201380775">"剩余<xliff:g id="PERCENTAGE">%s</xliff:g>"</string>
+ <!-- no translation found for battery_low_percent_format_hybrid (6838677459286775617) -->
+ <skip />
+ <!-- no translation found for battery_low_percent_format_hybrid_short (9025795469949145586) -->
+ <skip />
<string name="battery_low_percent_format_saver_started" msgid="7879389868952879166">"剩余 <xliff:g id="PERCENTAGE">%s</xliff:g>。省电模式已开启。"</string>
<string name="invalid_charger" msgid="4549105996740522523">"不支持USB充电功能。\n只能使用随附的充电器充电。"</string>
<string name="invalid_charger_title" msgid="3515740382572798460">"不支持USB充电。"</string>
@@ -67,14 +73,22 @@
<string name="usb_debugging_secondary_user_message" msgid="6067122453571699801">"目前已登录此设备的用户无法开启 USB 调试功能。要使用此功能,请切换为主要用户的帐号。"</string>
<string name="compat_mode_on" msgid="6623839244840638213">"缩放以填满屏幕"</string>
<string name="compat_mode_off" msgid="4434467572461327898">"拉伸以填满屏幕"</string>
+ <!-- no translation found for global_action_screenshot (8329831278085426283) -->
+ <skip />
<string name="screenshot_saving_ticker" msgid="7403652894056693515">"正在保存屏幕截图..."</string>
<string name="screenshot_saving_title" msgid="8242282144535555697">"正在保存屏幕截图..."</string>
- <string name="screenshot_saving_text" msgid="2419718443411738818">"正在保存屏幕截图。"</string>
- <string name="screenshot_saved_title" msgid="6461865960961414961">"已抓取屏幕截图。"</string>
- <string name="screenshot_saved_text" msgid="2685605830386712477">"点按即可查看您的屏幕截图。"</string>
- <string name="screenshot_failed_title" msgid="705781116746922771">"无法抓取屏幕截图。"</string>
- <string name="screenshot_failed_to_save_unknown_text" msgid="7887826345701753830">"保存屏幕截图时出现问题。"</string>
- <string name="screenshot_failed_to_save_text" msgid="2592658083866306296">"由于存储空间有限,无法保存屏幕截图。"</string>
+ <!-- no translation found for screenshot_saving_text (2545047868936087248) -->
+ <skip />
+ <!-- no translation found for screenshot_saved_title (5637073968117370753) -->
+ <skip />
+ <!-- no translation found for screenshot_saved_text (7574667448002050363) -->
+ <skip />
+ <!-- no translation found for screenshot_failed_title (9096484883063264803) -->
+ <skip />
+ <!-- no translation found for screenshot_failed_to_save_unknown_text (8844781948876286488) -->
+ <skip />
+ <!-- no translation found for screenshot_failed_to_save_text (3041612585107107310) -->
+ <skip />
<string name="screenshot_failed_to_capture_text" msgid="173674476457581486">"此应用或您所在的单位不允许进行屏幕截图"</string>
<string name="usb_preference_title" msgid="6551050377388882787">"USB文件传输选项"</string>
<string name="use_mtp_button_title" msgid="4333504413563023626">"作为媒体播放器(MTP)装载"</string>
@@ -557,26 +571,27 @@
<string name="tuner_full_importance_settings_off" msgid="8208165412614935229">"关闭"</string>
<string name="power_notification_controls_description" msgid="4372459941671353358">"利用高级通知设置,您可以为应用通知设置从 0 级到 5 级的重要程度等级。\n\n"<b>"5 级"</b>" \n- 在通知列表顶部显示 \n- 允许全屏打扰 \n- 一律短暂显示通知 \n\n"<b>"4 级"</b>" \n- 禁止全屏打扰 \n- 一律短暂显示通知 \n\n"<b>"3 级"</b>" \n- 禁止全屏打扰 \n- 一律不短暂显示通知 \n\n"<b>"2 级"</b>" \n- 禁止全屏打扰 \n- 一律不短暂显示通知 \n- 一律不发出声音或振动 \n\n"<b>"1 级"</b>" \n- 禁止全屏打扰 \n- 一律不短暂显示通知 \n- 一律不发出声音或振动 \n- 不在锁定屏幕和状态栏中显示 \n- 在通知列表底部显示 \n\n"<b>"0 级"</b>" \n- 屏蔽应用的所有通知"</string>
<string name="notification_header_default_channel" msgid="7506845022070889909">"通知"</string>
- <string name="notification_channel_disabled" msgid="2139193533791840539">"您将不会再收到这类通知"</string>
- <string name="notification_num_channels" msgid="2048144408999179471">"<xliff:g id="NUMBER">%d</xliff:g> 个通知类别"</string>
- <string name="notification_default_channel_desc" msgid="2506053815870808359">"此应用没有通知类别"</string>
- <string name="notification_unblockable_desc" msgid="3561016061737896906">"无法关闭来自此应用的通知"</string>
- <plurals name="notification_num_channels_desc" formatted="false" msgid="5492793452274077663">
- <item quantity="other">此应用指定的 1 个通知类别(共 <xliff:g id="NUMBER_1">%s</xliff:g> 个)</item>
- <item quantity="one">此应用指定的 1 个通知类别(共 <xliff:g id="NUMBER_0">%s</xliff:g> 个)</item>
- </plurals>
- <string name="notification_channels_list_desc_2" msgid="6214732715833946441">"<xliff:g id="CHANNEL_NAME_1">%1$s</xliff:g>、<xliff:g id="CHANNEL_NAME_2">%2$s</xliff:g>"</string>
- <plurals name="notification_channels_list_desc_2_and_others" formatted="false" msgid="2747813553355336157">
- <item quantity="other"><xliff:g id="CHANNEL_NAME_1_3">%1$s</xliff:g>、<xliff:g id="CHANNEL_NAME_2_4">%2$s</xliff:g>以及另外 <xliff:g id="NUMBER_5">%3$d</xliff:g> 项</item>
- <item quantity="one"><xliff:g id="CHANNEL_NAME_1_0">%1$s</xliff:g>、<xliff:g id="CHANNEL_NAME_2_1">%2$s</xliff:g>以及另外 <xliff:g id="NUMBER_2">%3$d</xliff:g> 项</item>
- </plurals>
+ <!-- no translation found for notification_channel_disabled (344536703863700565) -->
+ <skip />
+ <!-- no translation found for inline_keep_showing (8945102997083836858) -->
+ <skip />
+ <!-- no translation found for inline_stop_button (4172980096860941033) -->
+ <skip />
+ <!-- no translation found for inline_keep_button (6665940297019018232) -->
+ <skip />
+ <!-- no translation found for inline_keep_showing_app (1723113469580031041) -->
+ <skip />
+ <!-- no translation found for notification_unblockable_desc (1037434112919403708) -->
+ <skip />
<string name="notification_channel_controls_opened_accessibility" msgid="6553950422055908113">"<xliff:g id="APP_NAME">%1$s</xliff:g>的通知控件已打开"</string>
<string name="notification_channel_controls_closed_accessibility" msgid="7521619812603693144">"<xliff:g id="APP_NAME">%1$s</xliff:g>的通知控件已关闭"</string>
<string name="notification_channel_switch_accessibility" msgid="3420796005601900717">"允许接收来自此频道的通知"</string>
- <string name="notification_all_categories" msgid="5407190218055113282">"所有类别"</string>
<string name="notification_more_settings" msgid="816306283396553571">"更多设置"</string>
- <string name="notification_app_settings" msgid="3743278649182392015">"自定义:<xliff:g id="SUB_CATEGORY">%1$s</xliff:g>"</string>
+ <!-- no translation found for notification_app_settings (420348114670768449) -->
+ <skip />
<string name="notification_done" msgid="5279426047273930175">"完成"</string>
+ <!-- no translation found for inline_undo (558916737624706010) -->
+ <skip />
<string name="notification_menu_accessibility" msgid="2046162834248888553">"<xliff:g id="APP_NAME">%1$s</xliff:g><xliff:g id="MENU_DESCRIPTION">%2$s</xliff:g>"</string>
<string name="notification_menu_gear_description" msgid="2204480013726775108">"通知设置"</string>
<string name="notification_menu_snooze_description" msgid="3653669438131034525">"通知延后选项"</string>
@@ -731,8 +746,7 @@
<string name="pip_phone_expand" msgid="5889780005575693909">"展开"</string>
<string name="pip_phone_minimize" msgid="1079119422589131792">"最小化"</string>
<string name="pip_phone_close" msgid="8416647892889710330">"关闭"</string>
- <!-- no translation found for pip_phone_settings (8080777499521528521) -->
- <skip />
+ <string name="pip_phone_settings" msgid="8080777499521528521">"设置"</string>
<string name="pip_phone_dismiss_hint" msgid="6351678169095923899">"向下拖动即可关闭"</string>
<string name="pip_menu_title" msgid="4707292089961887657">"菜单"</string>
<string name="pip_notification_title" msgid="3204024940158161322">"<xliff:g id="NAME">%s</xliff:g>目前位于“画中画”中"</string>
diff --git a/packages/SystemUI/res/values-zh-rHK/strings.xml b/packages/SystemUI/res/values-zh-rHK/strings.xml
index e0ab7e468eb1..3e624f20d2a2 100644
--- a/packages/SystemUI/res/values-zh-rHK/strings.xml
+++ b/packages/SystemUI/res/values-zh-rHK/strings.xml
@@ -33,7 +33,10 @@
<string name="status_bar_ongoing_events_title" msgid="1682504513316879202">"持續進行"</string>
<string name="status_bar_latest_events_title" msgid="6594767438577593172">"通知"</string>
<string name="battery_low_title" msgid="6456385927409742437">"電量低"</string>
+ <string name="battery_low_title_hybrid" msgid="6268991275887381595">"電量不足。請開啟省電模式"</string>
<string name="battery_low_percent_format" msgid="2900940511201380775">"剩餘 <xliff:g id="PERCENTAGE">%s</xliff:g>"</string>
+ <string name="battery_low_percent_format_hybrid" msgid="6838677459286775617">"電量剩餘 <xliff:g id="PERCENTAGE">%s</xliff:g>,根據您的使用情況,剩餘時間大約 <xliff:g id="TIME">%s</xliff:g>"</string>
+ <string name="battery_low_percent_format_hybrid_short" msgid="9025795469949145586">"電量剩餘 <xliff:g id="PERCENTAGE">%s</xliff:g>,剩餘時間大約 <xliff:g id="TIME">%s</xliff:g>"</string>
<string name="battery_low_percent_format_saver_started" msgid="7879389868952879166">"剩餘 <xliff:g id="PERCENTAGE">%s</xliff:g>。省電模式已開啟。"</string>
<string name="invalid_charger" msgid="4549105996740522523">"不支援 USB 充電。\n僅能使用隨附的充電器。"</string>
<string name="invalid_charger_title" msgid="3515740382572798460">"不支援 USB 充電功能。"</string>
@@ -67,14 +70,15 @@
<string name="usb_debugging_secondary_user_message" msgid="6067122453571699801">"目前登入此裝置的使用者無法啟用 USB 偵錯功能。如要使用此功能,請切換至主要使用者。"</string>
<string name="compat_mode_on" msgid="6623839244840638213">"放大為全螢幕"</string>
<string name="compat_mode_off" msgid="4434467572461327898">"放大為全螢幕"</string>
+ <string name="global_action_screenshot" msgid="8329831278085426283">"擷取螢幕畫面"</string>
<string name="screenshot_saving_ticker" msgid="7403652894056693515">"正在儲存螢幕擷取畫面..."</string>
<string name="screenshot_saving_title" msgid="8242282144535555697">"正在儲存螢幕擷取畫面..."</string>
- <string name="screenshot_saving_text" msgid="2419718443411738818">"正在儲存螢幕擷取畫面。"</string>
- <string name="screenshot_saved_title" msgid="6461865960961414961">"已擷取螢幕畫面。"</string>
- <string name="screenshot_saved_text" msgid="2685605830386712477">"輕按即可查看螢幕擷圖。"</string>
- <string name="screenshot_failed_title" msgid="705781116746922771">"無法擷取螢幕畫面。"</string>
- <string name="screenshot_failed_to_save_unknown_text" msgid="7887826345701753830">"儲存螢幕擷圖時發生問題。"</string>
- <string name="screenshot_failed_to_save_text" msgid="2592658083866306296">"由於儲存空間有限,因此無法儲存螢幕擷取畫面。"</string>
+ <string name="screenshot_saving_text" msgid="2545047868936087248">"正在儲存螢幕擷取畫面"</string>
+ <string name="screenshot_saved_title" msgid="5637073968117370753">"螢幕擷取畫面已儲存"</string>
+ <string name="screenshot_saved_text" msgid="7574667448002050363">"輕按即可查看螢幕擷取畫面"</string>
+ <string name="screenshot_failed_title" msgid="9096484883063264803">"無法擷取螢幕畫面"</string>
+ <string name="screenshot_failed_to_save_unknown_text" msgid="8844781948876286488">"儲存螢幕擷取畫面時發生問題"</string>
+ <string name="screenshot_failed_to_save_text" msgid="3041612585107107310">"由於儲存空間有限,因此無法儲存螢幕擷取畫面"</string>
<string name="screenshot_failed_to_capture_text" msgid="173674476457581486">"應用程式或您的機構不允許擷取螢幕畫面"</string>
<string name="usb_preference_title" msgid="6551050377388882787">"USB 檔案傳輸選項"</string>
<string name="use_mtp_button_title" msgid="4333504413563023626">"掛接為媒體播放器 (MTP)"</string>
@@ -559,26 +563,19 @@
<string name="tuner_full_importance_settings_off" msgid="8208165412614935229">"關閉"</string>
<string name="power_notification_controls_description" msgid="4372459941671353358">"通知控制項讓您設定應用程式通知的重要性 (0 至 5 級)。\n\n"<b>"第 5 級"</b>" \n- 在通知清單頂部顯示 \n- 允許全螢幕騷擾 \n- 一律顯示通知 \n\n"<b>"第 4 級"</b>" \n- 阻止全螢幕騷擾 \n- 一律顯示通知 \n\n"<b>"第 3 級"</b>" \n- 阻止全螢幕騷擾 \n- 永不顯示通知 \n\n"<b>"第 2 級"</b>" \n- 阻止全螢幕騷擾 \n- 永不顯示通知 \n- 永不發出聲響和震動 \n\n"<b>"第 1 級"</b>" \n- 阻止全螢幕騷擾 \n- 永不顯示通知 \n- 永不發出聲響和震動 \n- 從上鎖畫面和狀態列中隱藏 \n- 在通知清單底部顯示 \n\n"<b>"第 0 級"</b>" \n- 封鎖所有應用程式通知"</string>
<string name="notification_header_default_channel" msgid="7506845022070889909">"通知"</string>
- <string name="notification_channel_disabled" msgid="2139193533791840539">"您不會再收到這些通知"</string>
- <string name="notification_num_channels" msgid="2048144408999179471">"<xliff:g id="NUMBER">%d</xliff:g> 個通知類別"</string>
- <string name="notification_default_channel_desc" msgid="2506053815870808359">"此應用程式沒有通知類別"</string>
- <string name="notification_unblockable_desc" msgid="3561016061737896906">"無法關閉此應用程式的通知"</string>
- <plurals name="notification_num_channels_desc" formatted="false" msgid="5492793452274077663">
- <item quantity="other">此應用程式的 1 個通知類別 (共 <xliff:g id="NUMBER_1">%s</xliff:g> 個)</item>
- <item quantity="one">此應用程式的 1 個通知類別 (共 <xliff:g id="NUMBER_0">%s</xliff:g> 個)</item>
- </plurals>
- <string name="notification_channels_list_desc_2" msgid="6214732715833946441">"<xliff:g id="CHANNEL_NAME_1">%1$s</xliff:g>、<xliff:g id="CHANNEL_NAME_2">%2$s</xliff:g>"</string>
- <plurals name="notification_channels_list_desc_2_and_others" formatted="false" msgid="2747813553355336157">
- <item quantity="other"><xliff:g id="CHANNEL_NAME_1_3">%1$s</xliff:g>、<xliff:g id="CHANNEL_NAME_2_4">%2$s</xliff:g>和另外 <xliff:g id="NUMBER_5">%3$d</xliff:g> 個頻道</item>
- <item quantity="one"><xliff:g id="CHANNEL_NAME_1_0">%1$s</xliff:g>、<xliff:g id="CHANNEL_NAME_2_1">%2$s</xliff:g>和另外 <xliff:g id="NUMBER_2">%3$d</xliff:g> 個頻道</item>
- </plurals>
+ <string name="notification_channel_disabled" msgid="344536703863700565">"您不會再看到這些通知"</string>
+ <string name="inline_keep_showing" msgid="8945102997083836858">"要繼續顯示這些通知嗎?"</string>
+ <string name="inline_stop_button" msgid="4172980096860941033">"停止通知"</string>
+ <string name="inline_keep_button" msgid="6665940297019018232">"繼續顯示"</string>
+ <string name="inline_keep_showing_app" msgid="1723113469580031041">"要繼續顯示此應用程式的通知嗎?"</string>
+ <string name="notification_unblockable_desc" msgid="1037434112919403708">"無法關閉這些通知"</string>
<string name="notification_channel_controls_opened_accessibility" msgid="6553950422055908113">"開咗「<xliff:g id="APP_NAME">%1$s</xliff:g>」嘅通知控制項"</string>
<string name="notification_channel_controls_closed_accessibility" msgid="7521619812603693144">"閂咗「<xliff:g id="APP_NAME">%1$s</xliff:g>」嘅通知控制項"</string>
<string name="notification_channel_switch_accessibility" msgid="3420796005601900717">"允許收到呢個頻道嘅通知"</string>
- <string name="notification_all_categories" msgid="5407190218055113282">"所有類別"</string>
<string name="notification_more_settings" msgid="816306283396553571">"更多設定"</string>
- <string name="notification_app_settings" msgid="3743278649182392015">"自訂:<xliff:g id="SUB_CATEGORY">%1$s</xliff:g>"</string>
+ <string name="notification_app_settings" msgid="420348114670768449">"自訂"</string>
<string name="notification_done" msgid="5279426047273930175">"完成"</string>
+ <string name="inline_undo" msgid="558916737624706010">"復原"</string>
<string name="notification_menu_accessibility" msgid="2046162834248888553">"<xliff:g id="APP_NAME">%1$s</xliff:g> <xliff:g id="MENU_DESCRIPTION">%2$s</xliff:g>"</string>
<string name="notification_menu_gear_description" msgid="2204480013726775108">"通知控制項"</string>
<string name="notification_menu_snooze_description" msgid="3653669438131034525">"通知延後選項"</string>
@@ -733,8 +730,7 @@
<string name="pip_phone_expand" msgid="5889780005575693909">"展開"</string>
<string name="pip_phone_minimize" msgid="1079119422589131792">"最小化"</string>
<string name="pip_phone_close" msgid="8416647892889710330">"關閉"</string>
- <!-- no translation found for pip_phone_settings (8080777499521528521) -->
- <skip />
+ <string name="pip_phone_settings" msgid="8080777499521528521">"設定"</string>
<string name="pip_phone_dismiss_hint" msgid="6351678169095923899">"向下拖曳即可關閉"</string>
<string name="pip_menu_title" msgid="4707292089961887657">"選單"</string>
<string name="pip_notification_title" msgid="3204024940158161322">"「<xliff:g id="NAME">%s</xliff:g>」目前在畫中畫模式"</string>
diff --git a/packages/SystemUI/res/values-zh-rTW/strings.xml b/packages/SystemUI/res/values-zh-rTW/strings.xml
index 2d43da875b51..e6ff9d7c4ae0 100644
--- a/packages/SystemUI/res/values-zh-rTW/strings.xml
+++ b/packages/SystemUI/res/values-zh-rTW/strings.xml
@@ -33,7 +33,10 @@
<string name="status_bar_ongoing_events_title" msgid="1682504513316879202">"進行中"</string>
<string name="status_bar_latest_events_title" msgid="6594767438577593172">"通知"</string>
<string name="battery_low_title" msgid="6456385927409742437">"電池電力不足"</string>
+ <string name="battery_low_title_hybrid" msgid="6268991275887381595">"電池電力不足,請開啟節約耗電量模式"</string>
<string name="battery_low_percent_format" msgid="2900940511201380775">"僅剩 <xliff:g id="PERCENTAGE">%s</xliff:g>"</string>
+ <string name="battery_low_percent_format_hybrid" msgid="6838677459286775617">"電力剩餘 <xliff:g id="PERCENTAGE">%s</xliff:g>,根據你的使用情形,剩餘時間大約還有 <xliff:g id="TIME">%s</xliff:g>"</string>
+ <string name="battery_low_percent_format_hybrid_short" msgid="9025795469949145586">"電力剩餘 <xliff:g id="PERCENTAGE">%s</xliff:g>,剩餘時間大約還有 <xliff:g id="TIME">%s</xliff:g>"</string>
<string name="battery_low_percent_format_saver_started" msgid="7879389868952879166">"僅剩 <xliff:g id="PERCENTAGE">%s</xliff:g>。節約耗電量模式已開啟。"</string>
<string name="invalid_charger" msgid="4549105996740522523">"不支援 USB 充電。\n僅能使用隨附的充電器。"</string>
<string name="invalid_charger_title" msgid="3515740382572798460">"不支援 USB 充電功能。"</string>
@@ -67,14 +70,15 @@
<string name="usb_debugging_secondary_user_message" msgid="6067122453571699801">"目前登入這個裝置的使用者無法啟用 USB 偵錯功能。如要使用這項功能,請切換到主要使用者。"</string>
<string name="compat_mode_on" msgid="6623839244840638213">"放大為全螢幕"</string>
<string name="compat_mode_off" msgid="4434467572461327898">"放大為全螢幕"</string>
+ <string name="global_action_screenshot" msgid="8329831278085426283">"擷取螢幕畫面"</string>
<string name="screenshot_saving_ticker" msgid="7403652894056693515">"正在儲存螢幕擷取畫面…"</string>
<string name="screenshot_saving_title" msgid="8242282144535555697">"正在儲存螢幕擷取畫面…"</string>
- <string name="screenshot_saving_text" msgid="2419718443411738818">"正在儲存螢幕擷取畫面。"</string>
- <string name="screenshot_saved_title" msgid="6461865960961414961">"已拍攝螢幕擷取畫面。"</string>
- <string name="screenshot_saved_text" msgid="2685605830386712477">"輕觸即可查看螢幕擷圖。"</string>
- <string name="screenshot_failed_title" msgid="705781116746922771">"無法拍攝螢幕擷取畫面。"</string>
- <string name="screenshot_failed_to_save_unknown_text" msgid="7887826345701753830">"儲存螢幕擷取畫面時發生問題。"</string>
- <string name="screenshot_failed_to_save_text" msgid="2592658083866306296">"由於儲存空間有限,因此無法儲存螢幕擷取畫面。"</string>
+ <string name="screenshot_saving_text" msgid="2545047868936087248">"正在儲存螢幕擷取畫面"</string>
+ <string name="screenshot_saved_title" msgid="5637073968117370753">"螢幕擷取畫面已儲存"</string>
+ <string name="screenshot_saved_text" msgid="7574667448002050363">"輕觸即可查看螢幕擷取畫面"</string>
+ <string name="screenshot_failed_title" msgid="9096484883063264803">"無法擷取螢幕畫面"</string>
+ <string name="screenshot_failed_to_save_unknown_text" msgid="8844781948876286488">"儲存螢幕擷取畫面時發生問題"</string>
+ <string name="screenshot_failed_to_save_text" msgid="3041612585107107310">"由於儲存空間有限,因此無法儲存螢幕擷取畫面"</string>
<string name="screenshot_failed_to_capture_text" msgid="173674476457581486">"這個應用程式或貴機構不允許擷取螢幕畫面"</string>
<string name="usb_preference_title" msgid="6551050377388882787">"USB 檔案傳輸選項"</string>
<string name="use_mtp_button_title" msgid="4333504413563023626">"掛接為媒體播放器 (MTP)"</string>
@@ -557,26 +561,19 @@
<string name="tuner_full_importance_settings_off" msgid="8208165412614935229">"關閉"</string>
<string name="power_notification_controls_description" msgid="4372459941671353358">"只要使用電源通知控制項,你就能為應用程式通知設定從 0 到 5 的重要性等級。\n\n"<b>"等級 5"</b>" \n- 顯示在通知清單頂端 \n- 允許全螢幕通知 \n- 一律允許短暫顯示通知 \n\n"<b>"等級 4"</b>" \n- 禁止全螢幕通知 \n- 一律允許短暫顯示通知 \n\n"<b>"等級 3"</b>" \n- 禁止全螢幕通知 \n- 一律不允許短暫顯示通知 \n\n"<b>"等級 2"</b>" \n- 禁止全螢幕通知 \n- 一律不允許短暫顯示通知 \n- 一律不發出音效或震動 \n\n"<b>"等級 1"</b>" \n- 禁止全螢幕通知 \n- 一律不允許短暫顯示通知 \n- 一律不發出音效或震動 \n- 在鎖定畫面和狀態列中隱藏 \n- 顯示在通知清單底端 \n\n"<b>"等級 0"</b>" \n- 封鎖應用程式的所有通知"</string>
<string name="notification_header_default_channel" msgid="7506845022070889909">"通知"</string>
- <string name="notification_channel_disabled" msgid="2139193533791840539">"你不會再收到這類通知"</string>
- <string name="notification_num_channels" msgid="2048144408999179471">"<xliff:g id="NUMBER">%d</xliff:g> 個通知類別"</string>
- <string name="notification_default_channel_desc" msgid="2506053815870808359">"這個應用程式沒有通知類別"</string>
- <string name="notification_unblockable_desc" msgid="3561016061737896906">"無法關閉這個應用程式發出的通知"</string>
- <plurals name="notification_num_channels_desc" formatted="false" msgid="5492793452274077663">
- <item quantity="other">在 <xliff:g id="NUMBER_1">%s</xliff:g> 個通知類別中,有 1 個類別是來自這個應用程式</item>
- <item quantity="one">在 <xliff:g id="NUMBER_0">%s</xliff:g> 個通知類別中,有 1 個類別是來自這個應用程式</item>
- </plurals>
- <string name="notification_channels_list_desc_2" msgid="6214732715833946441">"<xliff:g id="CHANNEL_NAME_1">%1$s</xliff:g>、<xliff:g id="CHANNEL_NAME_2">%2$s</xliff:g>"</string>
- <plurals name="notification_channels_list_desc_2_and_others" formatted="false" msgid="2747813553355336157">
- <item quantity="other"><xliff:g id="CHANNEL_NAME_1_3">%1$s</xliff:g>、<xliff:g id="CHANNEL_NAME_2_4">%2$s</xliff:g>和另外 <xliff:g id="NUMBER_5">%3$d</xliff:g> 個管道</item>
- <item quantity="one"><xliff:g id="CHANNEL_NAME_1_0">%1$s</xliff:g>、<xliff:g id="CHANNEL_NAME_2_1">%2$s</xliff:g>和另外 <xliff:g id="NUMBER_2">%3$d</xliff:g> 個管道</item>
- </plurals>
+ <string name="notification_channel_disabled" msgid="344536703863700565">"你不會再看到這些通知"</string>
+ <string name="inline_keep_showing" msgid="8945102997083836858">"要繼續顯示這些通知嗎?"</string>
+ <string name="inline_stop_button" msgid="4172980096860941033">"停止通知"</string>
+ <string name="inline_keep_button" msgid="6665940297019018232">"繼續顯示"</string>
+ <string name="inline_keep_showing_app" msgid="1723113469580031041">"要繼續顯示這個應用程式的通知嗎?"</string>
+ <string name="notification_unblockable_desc" msgid="1037434112919403708">"無法關閉這些通知"</string>
<string name="notification_channel_controls_opened_accessibility" msgid="6553950422055908113">"「<xliff:g id="APP_NAME">%1$s</xliff:g>」的通知控制項已開啟"</string>
<string name="notification_channel_controls_closed_accessibility" msgid="7521619812603693144">"「<xliff:g id="APP_NAME">%1$s</xliff:g>」的通知控制項已關閉"</string>
<string name="notification_channel_switch_accessibility" msgid="3420796005601900717">"允許來自這個頻道的通知"</string>
- <string name="notification_all_categories" msgid="5407190218055113282">"所有類別"</string>
<string name="notification_more_settings" msgid="816306283396553571">"更多設定"</string>
- <string name="notification_app_settings" msgid="3743278649182392015">"自訂:<xliff:g id="SUB_CATEGORY">%1$s</xliff:g>"</string>
+ <string name="notification_app_settings" msgid="420348114670768449">"自訂"</string>
<string name="notification_done" msgid="5279426047273930175">"完成"</string>
+ <string name="inline_undo" msgid="558916737624706010">"復原"</string>
<string name="notification_menu_accessibility" msgid="2046162834248888553">"<xliff:g id="APP_NAME">%1$s</xliff:g> <xliff:g id="MENU_DESCRIPTION">%2$s</xliff:g>"</string>
<string name="notification_menu_gear_description" msgid="2204480013726775108">"通知控制項"</string>
<string name="notification_menu_snooze_description" msgid="3653669438131034525">"通知延後選項"</string>
@@ -731,8 +728,7 @@
<string name="pip_phone_expand" msgid="5889780005575693909">"展開"</string>
<string name="pip_phone_minimize" msgid="1079119422589131792">"最小化"</string>
<string name="pip_phone_close" msgid="8416647892889710330">"關閉"</string>
- <!-- no translation found for pip_phone_settings (8080777499521528521) -->
- <skip />
+ <string name="pip_phone_settings" msgid="8080777499521528521">"設定"</string>
<string name="pip_phone_dismiss_hint" msgid="6351678169095923899">"向下拖曳即可關閉"</string>
<string name="pip_menu_title" msgid="4707292089961887657">"選單"</string>
<string name="pip_notification_title" msgid="3204024940158161322">"「<xliff:g id="NAME">%s</xliff:g>」目前在子母畫面中"</string>
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java b/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java
index e58ad0589c8a..19afcf5e33a8 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java
@@ -991,6 +991,12 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener {
maxChargingWattage > fastThreshold ? CHARGING_FAST :
CHARGING_REGULAR;
}
+
+ @Override
+ public String toString() {
+ return "BatteryStatus{status=" + status + ",level=" + level + ",plugged=" + plugged
+ + ",health=" + health + ",maxChargingWattage=" + maxChargingWattage + "}";
+ }
}
public class StrongAuthTracker extends LockPatternUtils.StrongAuthTracker {
@@ -1624,18 +1630,8 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener {
return true;
}
- // change in battery level while plugged in
- if (nowPluggedIn && old.level != current.level) {
- return true;
- }
-
- // change in battery level while keyguard visible
- if (mKeyguardIsVisible && old.level != current.level) {
- return true;
- }
-
- // change where battery needs charging
- if (!nowPluggedIn && current.isBatteryLow() && current.level != old.level) {
+ // change in battery level
+ if (old.level != current.level) {
return true;
}
diff --git a/packages/SystemUI/src/com/android/systemui/RecentsComponent.java b/packages/SystemUI/src/com/android/systemui/RecentsComponent.java
index 880ae709b59d..f9dbf4a15e5c 100644
--- a/packages/SystemUI/src/com/android/systemui/RecentsComponent.java
+++ b/packages/SystemUI/src/com/android/systemui/RecentsComponent.java
@@ -21,7 +21,7 @@ import android.view.Display;
import android.view.View;
public interface RecentsComponent {
- void showRecentApps(boolean triggeredFromAltTab, boolean fromHome);
+ void showRecentApps(boolean triggeredFromAltTab);
void showNextAffiliatedTask();
void showPrevAffiliatedTask();
diff --git a/packages/SystemUI/src/com/android/systemui/SwipeHelper.java b/packages/SystemUI/src/com/android/systemui/SwipeHelper.java
index 592dda073d32..a64ce296c76c 100644
--- a/packages/SystemUI/src/com/android/systemui/SwipeHelper.java
+++ b/packages/SystemUI/src/com/android/systemui/SwipeHelper.java
@@ -21,6 +21,7 @@ import android.animation.AnimatorListenerAdapter;
import android.animation.ObjectAnimator;
import android.animation.ValueAnimator;
import android.animation.ValueAnimator.AnimatorUpdateListener;
+import android.annotation.NonNull;
import android.content.Context;
import android.content.res.Resources;
import android.graphics.RectF;
@@ -316,10 +317,12 @@ public class SwipeHelper implements Gefingerpoken {
float deltaPerpendicular = perpendicularPos - mPerpendicularInitialTouchPos;
if (Math.abs(delta) > mPagingTouchSlop
&& Math.abs(delta) > Math.abs(deltaPerpendicular)) {
- mCallback.onBeginDrag(mCurrView);
- mDragging = true;
- mInitialTouchPos = getPos(ev);
- mTranslation = getTranslation(mCurrView);
+ if (mCallback.canChildBeDragged(mCurrView)) {
+ mCallback.onBeginDrag(mCurrView);
+ mDragging = true;
+ mInitialTouchPos = getPos(ev);
+ mTranslation = getTranslation(mCurrView);
+ }
cancelLongPress();
}
}
@@ -722,5 +725,10 @@ public class SwipeHelper implements Gefingerpoken {
* @return The factor the falsing threshold should be multiplied with
*/
float getFalsingThresholdFactor();
+
+ /**
+ * @return If true, the given view is draggable.
+ */
+ default boolean canChildBeDragged(@NonNull View animView) { return true; }
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/analytics/DataCollector.java b/packages/SystemUI/src/com/android/systemui/analytics/DataCollector.java
index 931a99415615..69e347c9476d 100644
--- a/packages/SystemUI/src/com/android/systemui/analytics/DataCollector.java
+++ b/packages/SystemUI/src/com/android/systemui/analytics/DataCollector.java
@@ -463,4 +463,8 @@ public class DataCollector implements SensorEventListener {
public boolean isReportingEnabled() {
return mAllowReportRejectedTouch;
}
+
+ public void onFalsingSessionStarted() {
+ sessionEntrypoint();
+ }
}
diff --git a/packages/SystemUI/src/com/android/systemui/classifier/FalsingManager.java b/packages/SystemUI/src/com/android/systemui/classifier/FalsingManager.java
index e4b405f580d4..ed659e2d16d5 100644
--- a/packages/SystemUI/src/com/android/systemui/classifier/FalsingManager.java
+++ b/packages/SystemUI/src/com/android/systemui/classifier/FalsingManager.java
@@ -167,6 +167,9 @@ public class FalsingManager implements SensorEventListener {
if (mDataCollector.isEnabledFull()) {
registerSensors(COLLECTOR_SENSORS);
}
+ if (mDataCollector.isEnabled()) {
+ mDataCollector.onFalsingSessionStarted();
+ }
}
private void registerSensors(int [] sensors) {
diff --git a/packages/SystemUI/src/com/android/systemui/recents/IRecentsNonSystemUserCallbacks.aidl b/packages/SystemUI/src/com/android/systemui/recents/IRecentsNonSystemUserCallbacks.aidl
index 5ae7f22c4905..fc1831d55c9d 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/IRecentsNonSystemUserCallbacks.aidl
+++ b/packages/SystemUI/src/com/android/systemui/recents/IRecentsNonSystemUserCallbacks.aidl
@@ -27,7 +27,7 @@ oneway interface IRecentsNonSystemUserCallbacks {
void preloadRecents();
void cancelPreloadingRecents();
void showRecents(boolean triggeredFromAltTab, boolean draggingInRecents, boolean animate,
- boolean reloadTasks, boolean fromHome, int recentsGrowTarget);
+ int recentsGrowTarget);
void hideRecents(boolean triggeredFromAltTab, boolean triggeredFromHomeKey);
void toggleRecents(int recentsGrowTarget);
void onConfigurationChanged();
diff --git a/packages/SystemUI/src/com/android/systemui/recents/Recents.java b/packages/SystemUI/src/com/android/systemui/recents/Recents.java
index 5b62c7d3c002..1da4deb61176 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/Recents.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/Recents.java
@@ -240,7 +240,7 @@ public class Recents extends SystemUI
* Shows the Recents.
*/
@Override
- public void showRecentApps(boolean triggeredFromAltTab, boolean fromHome) {
+ public void showRecentApps(boolean triggeredFromAltTab) {
// Ensure the device has been provisioned before allowing the user to interact with
// recents
if (!isUserSetup()) {
@@ -252,7 +252,7 @@ public class Recents extends SystemUI
int currentUser = sSystemServicesProxy.getCurrentUser();
if (sSystemServicesProxy.isSystemUser(currentUser)) {
mImpl.showRecents(triggeredFromAltTab, false /* draggingInRecents */,
- true /* animate */, false /* reloadTasks */, fromHome, recentsGrowTarget);
+ true /* animate */, recentsGrowTarget);
} else {
if (mSystemToUserCallbacks != null) {
IRecentsNonSystemUserCallbacks callbacks =
@@ -260,8 +260,7 @@ public class Recents extends SystemUI
if (callbacks != null) {
try {
callbacks.showRecents(triggeredFromAltTab, false /* draggingInRecents */,
- true /* animate */, false /* reloadTasks */, fromHome,
- recentsGrowTarget);
+ true /* animate */, recentsGrowTarget);
} catch (RemoteException e) {
Log.e(TAG, "Callback failed", e);
}
diff --git a/packages/SystemUI/src/com/android/systemui/recents/RecentsActivity.java b/packages/SystemUI/src/com/android/systemui/recents/RecentsActivity.java
index 06dfd183b3aa..b0a2fadf1f84 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/RecentsActivity.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/RecentsActivity.java
@@ -356,15 +356,15 @@ public class RecentsActivity extends Activity implements ViewTreeObserver.OnPreD
registerReceiver(mSystemBroadcastReceiver, filter);
getWindow().addPrivateFlags(LayoutParams.PRIVATE_FLAG_NO_MOVE_ANIMATION);
-
- // Reload the stack view
- reloadStackView();
}
@Override
protected void onStart() {
super.onStart();
+ // Reload the stack view whenever we are made visible again
+ reloadStackView();
+
// Notify that recents is now visible
EventBus.getDefault().send(new RecentsVisibilityChangedEvent(this, true));
MetricsLogger.visible(this, MetricsEvent.OVERVIEW_ACTIVITY);
@@ -411,14 +411,6 @@ public class RecentsActivity extends Activity implements ViewTreeObserver.OnPreD
}
}
- @Override
- protected void onNewIntent(Intent intent) {
- super.onNewIntent(intent);
-
- // Reload the stack view
- reloadStackView();
- }
-
/**
* Reloads the stack views upon launching Recents.
*/
@@ -530,7 +522,11 @@ public class RecentsActivity extends Activity implements ViewTreeObserver.OnPreD
// Set the window background
mRecentsView.updateBackgroundScrim(getWindow(), isInMultiWindowMode);
- reloadTaskStack(isInMultiWindowMode, true /* sendConfigChangedEvent */);
+ // Reload the task stack view if we are still visible to pick up the change in tasks that
+ // result from entering/exiting multi-window
+ if (mIsVisible) {
+ reloadTaskStack(isInMultiWindowMode, true /* sendConfigChangedEvent */);
+ }
}
@Override
diff --git a/packages/SystemUI/src/com/android/systemui/recents/RecentsImpl.java b/packages/SystemUI/src/com/android/systemui/recents/RecentsImpl.java
index 8359690b4fe3..ee1b09109d38 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/RecentsImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/RecentsImpl.java
@@ -255,7 +255,6 @@ public class RecentsImpl implements ActivityOptions.OnAnimationFinishedListener
// When this fires, then the user has not released alt-tab for at least
// FAST_ALT_TAB_DELAY_MS milliseconds
showRecents(mTriggeredFromAltTab, false /* draggingInRecents */, true /* animate */,
- false /* reloadTasks */, false /* fromHome */,
DividerView.INVALID_RECENTS_GROW_TARGET);
}
});
@@ -322,8 +321,15 @@ public class RecentsImpl implements ActivityOptions.OnAnimationFinishedListener
}
public void showRecents(boolean triggeredFromAltTab, boolean draggingInRecents,
- boolean animate, boolean launchedWhileDockingTask, boolean fromHome,
- int growTarget) {
+ boolean animate, int growTarget) {
+ final SystemServicesProxy ssp = Recents.getSystemServices();
+ final MutableBoolean isHomeStackVisible = new MutableBoolean(true);
+ final boolean isRecentsVisible = Recents.getSystemServices().isRecentsActivityVisible(
+ isHomeStackVisible);
+ final boolean fromHome = isHomeStackVisible.value;
+ final boolean launchedWhileDockingTask =
+ Recents.getSystemServices().getSplitScreenPrimaryStack() != null;
+
mTriggeredFromAltTab = triggeredFromAltTab;
mDraggingInRecents = draggingInRecents;
mLaunchedWhileDocking = launchedWhileDockingTask;
@@ -349,10 +355,8 @@ public class RecentsImpl implements ActivityOptions.OnAnimationFinishedListener
try {
// Check if the top task is in the home stack, and start the recents activity
- SystemServicesProxy ssp = Recents.getSystemServices();
- boolean forceVisible = launchedWhileDockingTask || draggingInRecents;
- MutableBoolean isHomeStackVisible = new MutableBoolean(forceVisible);
- if (forceVisible || !ssp.isRecentsActivityVisible(isHomeStackVisible)) {
+ final boolean forceVisible = launchedWhileDockingTask || draggingInRecents;
+ if (forceVisible || !isRecentsVisible) {
ActivityManager.RunningTaskInfo runningTask =
ActivityManagerWrapper.getInstance().getRunningTask();
startRecentsActivityAndDismissKeyguardIfNeeded(runningTask,
diff --git a/packages/SystemUI/src/com/android/systemui/recents/RecentsImplProxy.java b/packages/SystemUI/src/com/android/systemui/recents/RecentsImplProxy.java
index 9493c78f6278..beec4b395e9c 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/RecentsImplProxy.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/RecentsImplProxy.java
@@ -58,15 +58,12 @@ public class RecentsImplProxy extends IRecentsNonSystemUserCallbacks.Stub {
@Override
public void showRecents(boolean triggeredFromAltTab, boolean draggingInRecents, boolean animate,
- boolean reloadTasks, boolean fromHome, int growTarget)
- throws RemoteException {
+ int growTarget) throws RemoteException {
SomeArgs args = SomeArgs.obtain();
args.argi1 = triggeredFromAltTab ? 1 : 0;
args.argi2 = draggingInRecents ? 1 : 0;
args.argi3 = animate ? 1 : 0;
- args.argi4 = reloadTasks ? 1 : 0;
- args.argi5 = fromHome ? 1 : 0;
- args.argi6 = growTarget;
+ args.argi4 = growTarget;
mHandler.sendMessage(mHandler.obtainMessage(MSG_SHOW_RECENTS, args));
}
@@ -130,7 +127,7 @@ public class RecentsImplProxy extends IRecentsNonSystemUserCallbacks.Stub {
case MSG_SHOW_RECENTS:
args = (SomeArgs) msg.obj;
mImpl.showRecents(args.argi1 != 0, args.argi2 != 0, args.argi3 != 0,
- args.argi4 != 0, args.argi5 != 0, args.argi6);
+ args.argi4);
break;
case MSG_HIDE_RECENTS:
mImpl.hideRecents(msg.arg1 != 0, msg.arg2 != 0);
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 130a5e310fd1..613d9fbb985c 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/misc/SystemServicesProxy.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/misc/SystemServicesProxy.java
@@ -274,20 +274,21 @@ public class SystemServicesProxy {
return false;
}
+ public ActivityManager.StackInfo getSplitScreenPrimaryStack() {
+ try {
+ return mIam.getStackInfo(WINDOWING_MODE_SPLIT_SCREEN_PRIMARY, ACTIVITY_TYPE_UNDEFINED);
+ } catch (RemoteException e) {
+ return null;
+ }
+ }
+
/**
* @return whether there are any docked tasks for the current user.
*/
public boolean hasDockedTask() {
if (mIam == null) return false;
- ActivityManager.StackInfo stackInfo = null;
- try {
- stackInfo =
- mIam.getStackInfo(WINDOWING_MODE_SPLIT_SCREEN_PRIMARY, ACTIVITY_TYPE_UNDEFINED);
- } catch (RemoteException e) {
- e.printStackTrace();
- }
-
+ ActivityManager.StackInfo stackInfo = getSplitScreenPrimaryStack();
if (stackInfo != null) {
int userId = getCurrentUser();
boolean hasUserTask = false;
diff --git a/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackView.java b/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackView.java
index 36c9095fe8ae..5be2900831b3 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackView.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackView.java
@@ -210,7 +210,7 @@ public class TaskStackView extends FrameLayout implements TaskStack.TaskStackCal
private boolean mStackActionButtonVisible;
// Percentage of last ScrollP from the min to max scrollP that lives after configuration changes
- private float mLastScrollPPercent;
+ private float mLastScrollPPercent = -1;
// We keep track of the task view focused by user interaction and draw a frame around it in the
// grid layout.
@@ -647,14 +647,12 @@ public class TaskStackView extends FrameLayout implements TaskStack.TaskStackCal
* an animation provided in {@param animationOverrides}, that will be used instead.
*/
private void relayoutTaskViews(AnimationProps animation,
- ArrayMap<Task, AnimationProps> animationOverrides,
- boolean ignoreTaskOverrides) {
+ ArrayMap<Task, AnimationProps> animationOverrides, boolean ignoreTaskOverrides) {
// If we had a deferred animation, cancel that
cancelDeferredTaskViewLayoutAnimation();
// Synchronize the current set of TaskViews
- bindVisibleTaskViews(mStackScroller.getStackScroll(),
- ignoreTaskOverrides /* ignoreTaskOverrides */);
+ bindVisibleTaskViews(mStackScroller.getStackScroll(), ignoreTaskOverrides);
// Animate them to their final transforms with the given animation
List<TaskView> taskViews = getTaskViews();
@@ -2067,8 +2065,11 @@ public class TaskStackView extends FrameLayout implements TaskStack.TaskStackCal
// Update the Clear All button in case we're switching in or out of grid layout.
updateStackActionButtonVisibility();
- // Trigger a new layout and update to the initial state if necessary
- if (event.fromMultiWindow) {
+ // Trigger a new layout and update to the initial state if necessary. When entering split
+ // screen, the multi-window configuration change event can happen after the stack is already
+ // reloaded (but pending measure/layout), in this case, do not override the intiial state
+ // and just wait for the upcoming measure/layout pass.
+ if (event.fromMultiWindow && mInitialState == INITIAL_STATE_UPDATE_NONE) {
mInitialState = INITIAL_STATE_UPDATE_LAYOUT_ONLY;
requestLayout();
} else if (event.fromDeviceOrientationChange) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/CommandQueue.java b/packages/SystemUI/src/com/android/systemui/statusbar/CommandQueue.java
index 8e1b10432a3d..657b9534f3a8 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/CommandQueue.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/CommandQueue.java
@@ -116,7 +116,7 @@ public class CommandQueue extends IStatusBar.Stub {
default void topAppWindowChanged(boolean visible) { }
default void setImeWindowStatus(IBinder token, int vis, int backDisposition,
boolean showImeSwitcher) { }
- default void showRecentApps(boolean triggeredFromAltTab, boolean fromHome) { }
+ default void showRecentApps(boolean triggeredFromAltTab) { }
default void hideRecentApps(boolean triggeredFromAltTab, boolean triggeredFromHomeKey) { }
default void toggleRecentApps() { }
default void toggleSplitScreen() { }
@@ -268,11 +268,11 @@ public class CommandQueue extends IStatusBar.Stub {
}
}
- public void showRecentApps(boolean triggeredFromAltTab, boolean fromHome) {
+ public void showRecentApps(boolean triggeredFromAltTab) {
synchronized (mLock) {
mHandler.removeMessages(MSG_SHOW_RECENT_APPS);
- mHandler.obtainMessage(MSG_SHOW_RECENT_APPS,
- triggeredFromAltTab ? 1 : 0, fromHome ? 1 : 0, null).sendToTarget();
+ mHandler.obtainMessage(MSG_SHOW_RECENT_APPS, triggeredFromAltTab ? 1 : 0, 0,
+ null).sendToTarget();
}
}
@@ -541,7 +541,7 @@ public class CommandQueue extends IStatusBar.Stub {
break;
case MSG_SHOW_RECENT_APPS:
for (int i = 0; i < mCallbacks.size(); i++) {
- mCallbacks.get(i).showRecentApps(msg.arg1 != 0, msg.arg2 != 0);
+ mCallbacks.get(i).showRecentApps(msg.arg1 != 0);
}
break;
case MSG_HIDE_RECENT_APPS:
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/KeyguardIndicationController.java b/packages/SystemUI/src/com/android/systemui/statusbar/KeyguardIndicationController.java
index 43047ed6a5c5..0a12be4eac7f 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/KeyguardIndicationController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/KeyguardIndicationController.java
@@ -52,6 +52,8 @@ import com.android.systemui.statusbar.policy.UserInfoController;
import com.android.systemui.util.wakelock.SettableWakeLock;
import com.android.systemui.util.wakelock.WakeLock;
+import java.io.FileDescriptor;
+import java.io.PrintWriter;
import java.text.NumberFormat;
/**
@@ -116,11 +118,9 @@ public class KeyguardIndicationController {
WakeLock wakeLock) {
mContext = context;
mIndicationArea = indicationArea;
- mTextView = (KeyguardIndicationTextView) indicationArea.findViewById(
- R.id.keyguard_indication_text);
+ mTextView = indicationArea.findViewById(R.id.keyguard_indication_text);
mInitialTextColor = mTextView != null ? mTextView.getCurrentTextColor() : Color.WHITE;
- mDisclosure = (KeyguardIndicationTextView) indicationArea.findViewById(
- R.id.keyguard_indication_enterprise_disclosure);
+ mDisclosure = indicationArea.findViewById(R.id.keyguard_indication_enterprise_disclosure);
mLockIcon = lockIcon;
mWakeLock = new SettableWakeLock(wakeLock);
@@ -416,6 +416,21 @@ public class KeyguardIndicationController {
updateDisclosure();
}
+ public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
+ pw.println("KeyguardIndicationController:");
+ pw.println(" mTransientTextColor: " + Integer.toHexString(mTransientTextColor));
+ pw.println(" mInitialTextColor: " + Integer.toHexString(mInitialTextColor));
+ pw.println(" mPowerPluggedIn: " + mPowerPluggedIn);
+ pw.println(" mPowerCharged: " + mPowerCharged);
+ pw.println(" mChargingSpeed: " + mChargingSpeed);
+ pw.println(" mChargingWattage: " + mChargingWattage);
+ pw.println(" mMessageToShowOnScreenOn: " + mMessageToShowOnScreenOn);
+ pw.println(" mDozing: " + mDozing);
+ pw.println(" mBatteryLevel: " + mBatteryLevel);
+ pw.println(" mTextView.getText(): " + (mTextView == null ? null : mTextView.getText()));
+ pw.println(" computePowerIndication(): " + computePowerIndication());
+ }
+
protected class BaseKeyguardCallback extends KeyguardUpdateMonitorCallback {
public static final int HIDE_DELAY_MS = 5000;
private int mLastSuccessiveErrorMessage = -1;
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 b11367523c08..e09d31cea082 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarTransitions.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarTransitions.java
@@ -26,6 +26,7 @@ import android.view.IWallpaperVisibilityListener;
import android.view.IWindowManager;
import android.view.MotionEvent;
import android.view.View;
+import android.view.View.OnLayoutChangeListener;
import com.android.internal.statusbar.IStatusBarService;
import com.android.systemui.Dependency;
@@ -41,6 +42,7 @@ public final class NavigationBarTransitions extends BarTransitions {
private boolean mLightsOut;
private boolean mAutoDim;
+ private View mNavButtons;
public NavigationBarTransitions(NavigationBarView view) {
super(view, R.drawable.nav_background);
@@ -66,6 +68,18 @@ public final class NavigationBarTransitions extends BarTransitions {
}, Display.DEFAULT_DISPLAY);
} catch (RemoteException e) {
}
+ mView.addOnLayoutChangeListener(
+ (v, left, top, right, bottom, oldLeft, oldTop, oldRight, oldBottom) -> {
+ View currentView = mView.getCurrentView();
+ if (currentView != null) {
+ mNavButtons = currentView.findViewById(R.id.nav_buttons);
+ applyLightsOut(false, true);
+ }
+ });
+ View currentView = mView.getCurrentView();
+ if (currentView != null) {
+ mNavButtons = currentView.findViewById(R.id.nav_buttons);
+ }
}
public void init() {
@@ -105,21 +119,20 @@ public final class NavigationBarTransitions extends BarTransitions {
if (!force && lightsOut == mLightsOut) return;
mLightsOut = lightsOut;
-
- final View navButtons = mView.getCurrentView().findViewById(R.id.nav_buttons);
+ if (mNavButtons == null) return;
// ok, everyone, stop it right there
- navButtons.animate().cancel();
+ mNavButtons.animate().cancel();
// Bump percentage by 10% if dark.
float darkBump = mLightTransitionsController.getCurrentDarkIntensity() / 10;
final float navButtonsAlpha = lightsOut ? 0.6f + darkBump : 1f;
if (!animate) {
- navButtons.setAlpha(navButtonsAlpha);
+ mNavButtons.setAlpha(navButtonsAlpha);
} else {
final int duration = lightsOut ? LIGHTS_OUT_DURATION : LIGHTS_IN_DURATION;
- navButtons.animate()
+ mNavButtons.animate()
.alpha(navButtonsAlpha)
.setDuration(duration)
.start();
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimController.java
index 14329b564800..3b394ddd63cf 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimController.java
@@ -866,13 +866,13 @@ public class ScrimController implements ViewTreeObserver.OnPreDrawListener,
@Override
public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
- pw.println(" ScrimController:");
- pw.print(" state:"); pw.println(mState);
- pw.print(" frontScrim:"); pw.print(" viewAlpha="); pw.print(mScrimInFront.getViewAlpha());
+ pw.println(" ScrimController: ");
+ pw.print(" state: "); pw.println(mState);
+ pw.print(" frontScrim:"); pw.print(" viewAlpha="); pw.print(mScrimInFront.getViewAlpha());
pw.print(" alpha="); pw.print(mCurrentInFrontAlpha);
pw.print(" tint=0x"); pw.println(Integer.toHexString(mScrimInFront.getTint()));
- pw.print(" backScrim:"); pw.print(" viewAlpha="); pw.print(mScrimBehind.getViewAlpha());
+ pw.print(" backScrim:"); pw.print(" viewAlpha="); pw.print(mScrimBehind.getViewAlpha());
pw.print(" alpha="); pw.print(mCurrentBehindAlpha);
pw.print(" tint=0x"); pw.println(Integer.toHexString(mScrimBehind.getTint()));
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 5e08ec3575fc..c30fb22630da 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java
@@ -1704,7 +1704,7 @@ public class StatusBar extends SystemUI implements DemoMode,
if (mReportRejectedTouch == null) {
return;
}
- mReportRejectedTouch.setVisibility(mState == StatusBarState.KEYGUARD
+ mReportRejectedTouch.setVisibility(mState == StatusBarState.KEYGUARD && !mDozing
&& mFalsingManager.isReportingEnabled() ? View.VISIBLE : View.INVISIBLE);
}
@@ -2663,6 +2663,10 @@ public class StatusBar extends SystemUI implements DemoMode,
mFingerprintUnlockController.dump(pw);
}
+ if (mKeyguardIndicationController != null) {
+ mKeyguardIndicationController.dump(fd, pw, args);
+ }
+
if (mScrimController != null) {
mScrimController.dump(fd, pw, args);
}
@@ -4506,6 +4510,7 @@ public class StatusBar extends SystemUI implements DemoMode,
((DozeReceiver) mAmbientIndicationContainer).setDozing(mDozing);
}
updateDozingState();
+ updateReportRejectedTouchVisibility();
Trace.endSection();
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/DataSaverControllerImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/DataSaverControllerImpl.java
index 2951943404b3..2ede327ab698 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/DataSaverControllerImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/DataSaverControllerImpl.java
@@ -74,17 +74,9 @@ public class DataSaverControllerImpl implements DataSaverController {
}
}
- private final INetworkPolicyListener mPolicyListener = new INetworkPolicyListener.Stub() {
+ private final INetworkPolicyListener mPolicyListener = new NetworkPolicyManager.Listener() {
@Override
- public void onUidRulesChanged(int uid, int uidRules) throws RemoteException {
- }
-
- @Override
- public void onMeteredIfacesChanged(String[] strings) throws RemoteException {
- }
-
- @Override
- public void onRestrictBackgroundChanged(final boolean isDataSaving) throws RemoteException {
+ public void onRestrictBackgroundChanged(final boolean isDataSaving) {
mHandler.post(new Runnable() {
@Override
public void run() {
@@ -92,10 +84,6 @@ public class DataSaverControllerImpl implements DataSaverController {
}
});
}
-
- @Override
- public void onUidPoliciesChanged(int uid, int uidPolicies) throws RemoteException {
- }
};
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/stack/AmbientState.java b/packages/SystemUI/src/com/android/systemui/statusbar/stack/AmbientState.java
index 4d8da441c039..ebf4cda457e7 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/stack/AmbientState.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/stack/AmbientState.java
@@ -16,6 +16,7 @@
package com.android.systemui.statusbar.stack;
+import android.annotation.Nullable;
import android.content.Context;
import android.view.View;
@@ -236,6 +237,7 @@ public class AmbientState {
mShelf = shelf;
}
+ @Nullable
public NotificationShelf getShelf() {
return mShelf;
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/stack/StackScrollAlgorithm.java b/packages/SystemUI/src/com/android/systemui/statusbar/stack/StackScrollAlgorithm.java
index 7374f115a19b..2ce6df275588 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/stack/StackScrollAlgorithm.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/stack/StackScrollAlgorithm.java
@@ -122,7 +122,9 @@ public class StackScrollAlgorithm {
}
private void updateShelfState(StackScrollState resultState, AmbientState ambientState) {
NotificationShelf shelf = ambientState.getShelf();
- shelf.updateState(resultState, ambientState);
+ if (shelf != null) {
+ shelf.updateState(resultState, ambientState);
+ }
}
private void updateClipping(StackScrollState resultState,
@@ -495,6 +497,10 @@ public class StackScrollAlgorithm {
*/
private void clampPositionToShelf(ExpandableViewState childViewState,
AmbientState ambientState) {
+ if (ambientState.getShelf() == null) {
+ return;
+ }
+
int shelfStart = ambientState.getInnerHeight()
- ambientState.getShelf().getIntrinsicHeight();
childViewState.yTranslation = Math.min(childViewState.yTranslation, shelfStart);
@@ -556,7 +562,8 @@ public class StackScrollAlgorithm {
} else if (i == 0 && ambientState.isAboveShelf(child)) {
// In case this is a new view that has never been measured before, we don't want to
// elevate if we are currently expanded more then the notification
- int shelfHeight = ambientState.getShelf().getIntrinsicHeight();
+ int shelfHeight = ambientState.getShelf() == null ? 0 :
+ ambientState.getShelf().getIntrinsicHeight();
float shelfStart = ambientState.getInnerHeight()
- shelfHeight + ambientState.getTopPadding()
+ ambientState.getStackTranslation();
diff --git a/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogImpl.java b/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogImpl.java
index 9041d5a16da1..9f7c5a7fde22 100644
--- a/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogImpl.java
@@ -103,7 +103,6 @@ public class VolumeDialogImpl implements VolumeDialog {
private ViewGroup mDialogView;
private ViewGroup mDialogRowsView;
private ImageButton mRingerIcon;
- private ImageButton mOutputChooser;
private TextView mRingerStatus;
private final List<VolumeRow> mRows = new ArrayList<>();
private ConfigurableTexts mConfigurableTexts;
@@ -225,9 +224,6 @@ public class VolumeDialogImpl implements VolumeDialog {
addExistingRows();
}
- mOutputChooser = mDialogView.findViewById(R.id.output_chooser);
- mOutputChooser.setOnClickListener(mClickOutputChooser);
-
updateRowsH(getActiveRow());
initRingerH();
}
@@ -335,6 +331,9 @@ public class VolumeDialogImpl implements VolumeDialog {
row.slider.setOnSeekBarChangeListener(new VolumeSeekBarChangeListener(row));
row.anim = null;
+ ImageButton outputChooser = row.view.findViewById(R.id.output_chooser);
+ outputChooser.setOnClickListener(mClickOutputChooser);
+
// forward events above the slider into the slider
row.view.setOnTouchListener(new OnTouchListener() {
private final Rect mSliderHitRect = new Rect();
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/CommandQueueTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/CommandQueueTest.java
index 960320722c56..a02ef98f834d 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/CommandQueueTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/CommandQueueTest.java
@@ -119,9 +119,9 @@ public class CommandQueueTest extends SysuiTestCase {
@Test
public void testShowRecentApps() {
- mCommandQueue.showRecentApps(true, false);
+ mCommandQueue.showRecentApps(true);
waitForIdleSync();
- verify(mCallbacks).showRecentApps(eq(true), eq(false));
+ verify(mCallbacks).showRecentApps(eq(true));
}
@Test
diff --git a/packages/VpnDialogs/res/values-hi/strings.xml b/packages/VpnDialogs/res/values-hi/strings.xml
index fc4fdcd93459..526541d26b08 100644
--- a/packages/VpnDialogs/res/values-hi/strings.xml
+++ b/packages/VpnDialogs/res/values-hi/strings.xml
@@ -17,7 +17,7 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="prompt" msgid="3183836924226407828">"कनेक्शन अनुरोध"</string>
- <string name="warning" msgid="809658604548412033">"<xliff:g id="APP">%s</xliff:g> VPN कनेक्‍शन सेट करना चाहता है जिससे वह नेटवर्क ट्रैफ़िक पर नज़र रख पाएगा. इसकी मंज़ूरी तभी दें जब आपको आप इसपर भरोसा हो. VPN चालू होने पर आपकी स्क्रीन के सबसे ऊपर &lt;br /&gt; &lt;br /&gt; &lt;img src=vpn_icon /&gt; दिखाई देता है."</string>
+ <string name="warning" msgid="809658604548412033">"<xliff:g id="APP">%s</xliff:g> VPN कनेक्‍शन सेट अप करना चाहता है, जिससे वह नेटवर्क ट्रैफ़िक पर नज़र रख पाएगा. इसकी मंज़ूरी तभी दें जब आपको आप इस पर भरोसा हो. VPN चालू होने पर आपकी स्क्रीन के सबसे ऊपर &lt;br /&gt; &lt;br /&gt; &lt;img src=vpn_icon /&gt; दिखाई देता है."</string>
<string name="legacy_title" msgid="192936250066580964">"VPN कनेक्‍ट है"</string>
<string name="session" msgid="6470628549473641030">"सत्र:"</string>
<string name="duration" msgid="3584782459928719435">"अवधि:"</string>
diff --git a/packages/overlays/DisplayCutoutEmulationOverlay/res/values/config.xml b/packages/overlays/DisplayCutoutEmulationOverlay/res/values/config.xml
index 88c19c7ccf05..30e8b689883d 100644
--- a/packages/overlays/DisplayCutoutEmulationOverlay/res/values/config.xml
+++ b/packages/overlays/DisplayCutoutEmulationOverlay/res/values/config.xml
@@ -18,17 +18,26 @@
<!-- The bounding path of the cutout region of the main built-in display.
Must either be empty if there is no cutout region, or a string that is parsable by
- {@link android.util.PathParser}. -->
+ {@link android.util.PathParser}.
+
+ The path is assumed to be specified in display coordinates with pixel units and in
+ the display's native orientation, with the origin of the coordinate system at the
+ center top of the display.
+
+ To facilitate writing device-independent emulation overlays, the marker `@dp` can be
+ appended after the path string to interpret coordinates in dp instead of px units.
+ Note that a physical cutout should be configured in pixels for the best results.
+ -->
<string translatable="false" name="config_mainBuiltInDisplayCutout">
- M 687.0,0
- l -66,50
- l 0,50
- l 66,50
- l 66,0
- l 66,-50
- l 0,-50
- l -66,-50
- z
+ M 0,0
+ L -24, 0
+ L -21.9940446283, 20.0595537175
+ C -21.1582133885, 28.4178661152 -17.2, 32.0 -8.8, 32.0
+ L 8.8, 32.0
+ C 17.2, 32.0 21.1582133885, 28.4178661152 21.9940446283, 20.0595537175
+ L 24, 0
+ Z
+ @dp
</string>
<!-- Whether the display cutout region of the main built-in display should be forced to
@@ -37,7 +46,7 @@
<bool name="config_fillMainBuiltInDisplayCutout">true</bool>
<!-- Height of the status bar -->
- <dimen name="status_bar_height">150px</dimen>
+ <dimen name="status_bar_height">48dp</dimen>
</resources>
diff --git a/proto/src/metrics_constants.proto b/proto/src/metrics_constants.proto
index 04cee676075d..9b67f8f32704 100644
--- a/proto/src/metrics_constants.proto
+++ b/proto/src/metrics_constants.proto
@@ -5134,15 +5134,20 @@ message MetricsEvent {
// OS: P
ACTION_SCREENSHOT_POWER_MENU = 1282;
- // OPEN: Settings > Apps & Notifications -> Special app access -> Storage Access
+ // OPEN: Settings > Apps & Notifications -> Special app access -> Directory Access
// CATEGORY: SETTINGS
// OS: P
- STORAGE_ACCESS = 1283;
+ DIRECTORY_ACCESS = 1283;
- // OPEN: Settings > Apps & Notifications -> Special app access -> Storage Access -> Package
+ // OPEN: Settings > Apps & Notifications -> Special app access -> Directory Access -> Package
// CATEGORY: SETTINGS
// OS: P
- APPLICATIONS_STORAGE_DETAIL = 1284;
+ APPLICATIONS_DIRECTORY_ACCESS_DETAIL = 1284;
+
+ // OPEN: Settings > Battery > Smart Battery > Restricted apps
+ // CATEGORY: SETTINGS
+ // OS: P
+ FUELGAUGE_RESTRICTED_APP_DETAILS = 1285;
// ---- End P Constants, all P constants go above this line ----
// Add new aosp constants above this line.
diff --git a/proto/src/system_messages.proto b/proto/src/system_messages.proto
index d817da53f523..7c6019e76416 100644
--- a/proto/src/system_messages.proto
+++ b/proto/src/system_messages.proto
@@ -193,6 +193,9 @@ message SystemMessage {
// Inform the user that Wifi Wake has automatically re-enabled Wifi
NOTE_WIFI_WAKE_TURNED_BACK_ON = 44;
+ // Inform the user that unexpectedly rapid network usage is happening
+ NOTE_NET_RAPID = 45;
+
// ADD_NEW_IDS_ABOVE_THIS_LINE
// Legacy IDs with arbitrary values appear below
// Legacy IDs existed as stable non-conflicting constants prior to the O release
diff --git a/services/accessibility/java/com/android/server/accessibility/GlobalActionPerformer.java b/services/accessibility/java/com/android/server/accessibility/GlobalActionPerformer.java
index 3b8d4bca0598..672518cc17ed 100644
--- a/services/accessibility/java/com/android/server/accessibility/GlobalActionPerformer.java
+++ b/services/accessibility/java/com/android/server/accessibility/GlobalActionPerformer.java
@@ -21,6 +21,8 @@ import android.app.StatusBarManager;
import android.content.Context;
import android.hardware.input.InputManager;
import android.os.Binder;
+import android.os.Handler;
+import android.os.Looper;
import android.os.PowerManager;
import android.os.RemoteException;
import android.os.ServiceManager;
@@ -30,20 +32,34 @@ import android.view.InputDevice;
import android.view.KeyCharacterMap;
import android.view.KeyEvent;
+import com.android.internal.annotations.VisibleForTesting;
+import com.android.internal.util.ScreenshotHelper;
import com.android.server.LocalServices;
import com.android.server.statusbar.StatusBarManagerInternal;
import com.android.server.wm.WindowManagerInternal;
+import java.util.function.Supplier;
+
/**
* Handle the back-end of AccessibilityService#performGlobalAction
*/
public class GlobalActionPerformer {
private final WindowManagerInternal mWindowManagerService;
private final Context mContext;
+ private Supplier<ScreenshotHelper> mScreenshotHelperSupplier;
public GlobalActionPerformer(Context context, WindowManagerInternal windowManagerInternal) {
mContext = context;
mWindowManagerService = windowManagerInternal;
+ mScreenshotHelperSupplier = null;
+ }
+
+ // Used to mock ScreenshotHelper
+ @VisibleForTesting
+ public GlobalActionPerformer(Context context, WindowManagerInternal windowManagerInternal,
+ Supplier<ScreenshotHelper> screenshotHelperSupplier) {
+ this(context, windowManagerInternal);
+ mScreenshotHelperSupplier = screenshotHelperSupplier;
}
public boolean performGlobalAction(int action) {
@@ -79,6 +95,9 @@ public class GlobalActionPerformer {
case AccessibilityService.GLOBAL_ACTION_LOCK_SCREEN: {
return lockScreen();
}
+ case AccessibilityService.GLOBAL_ACTION_TAKE_SCREENSHOT: {
+ return takeScreenshot();
+ }
}
return false;
} finally {
@@ -167,4 +186,12 @@ public class GlobalActionPerformer {
mWindowManagerService.lockNow();
return true;
}
+
+ private boolean takeScreenshot() {
+ ScreenshotHelper screenshotHelper = (mScreenshotHelperSupplier != null)
+ ? mScreenshotHelperSupplier.get() : new ScreenshotHelper(mContext);
+ screenshotHelper.takeScreenshot(android.view.WindowManager.TAKE_SCREENSHOT_FULLSCREEN,
+ true, true, new Handler(Looper.getMainLooper()));
+ return true;
+ }
}
diff --git a/services/autofill/java/com/android/server/autofill/AutofillManagerService.java b/services/autofill/java/com/android/server/autofill/AutofillManagerService.java
index 6d845f9a9d3a..978ed25378e1 100644
--- a/services/autofill/java/com/android/server/autofill/AutofillManagerService.java
+++ b/services/autofill/java/com/android/server/autofill/AutofillManagerService.java
@@ -52,7 +52,6 @@ import android.os.UserHandle;
import android.os.UserManager;
import android.os.UserManagerInternal;
import android.provider.Settings;
-import android.service.autofill.AutofillFieldClassificationService.Scores;
import android.service.autofill.FillEventHistory;
import android.service.autofill.UserData;
import android.util.LocalLog;
@@ -646,37 +645,35 @@ public final class AutofillManagerService extends SystemService {
}
@Override
- public void getDefaultFieldClassificationAlgorithm(RemoteCallback callback)
- throws RemoteException {
+ public String getDefaultFieldClassificationAlgorithm() throws RemoteException {
final int userId = UserHandle.getCallingUserId();
synchronized (mLock) {
final AutofillManagerServiceImpl service = peekServiceForUserLocked(userId);
if (service != null) {
- service.getDefaultFieldClassificationAlgorithm(getCallingUid(), callback);
+ return service.getDefaultFieldClassificationAlgorithm(getCallingUid());
} else {
if (sVerbose) {
Slog.v(TAG, "getDefaultFcAlgorithm(): no service for " + userId);
}
- callback.sendResult(null);
- }
+ return null;
+ }
}
}
@Override
- public void getAvailableFieldClassificationAlgorithms(RemoteCallback callback)
- throws RemoteException {
+ public String[] getAvailableFieldClassificationAlgorithms() throws RemoteException {
final int userId = UserHandle.getCallingUserId();
synchronized (mLock) {
final AutofillManagerServiceImpl service = peekServiceForUserLocked(userId);
if (service != null) {
- service.getAvailableFieldClassificationAlgorithms(getCallingUid(), callback);
+ return service.getAvailableFieldClassificationAlgorithms(getCallingUid());
} else {
if (sVerbose) {
Slog.v(TAG, "getAvailableFcAlgorithms(): no service for " + userId);
}
- callback.sendResult(null);
+ return null;
}
}
}
diff --git a/services/autofill/java/com/android/server/autofill/AutofillManagerServiceImpl.java b/services/autofill/java/com/android/server/autofill/AutofillManagerServiceImpl.java
index a5bd59a9e77d..6bcfc4bf5a5e 100644
--- a/services/autofill/java/com/android/server/autofill/AutofillManagerServiceImpl.java
+++ b/services/autofill/java/com/android/server/autofill/AutofillManagerServiceImpl.java
@@ -1153,22 +1153,22 @@ final class AutofillManagerServiceImpl {
return mFieldClassificationStrategy;
}
- void getAvailableFieldClassificationAlgorithms(int callingUid, RemoteCallback callback) {
+ String[] getAvailableFieldClassificationAlgorithms(int callingUid) {
synchronized (mLock) {
if (!isCalledByServiceLocked("getFCAlgorithms()", callingUid)) {
- return;
+ return null;
}
}
- mFieldClassificationStrategy.getAvailableAlgorithms(callback);
+ return mFieldClassificationStrategy.getAvailableAlgorithms();
}
- void getDefaultFieldClassificationAlgorithm(int callingUid, RemoteCallback callback) {
+ String getDefaultFieldClassificationAlgorithm(int callingUid) {
synchronized (mLock) {
if (!isCalledByServiceLocked("getDefaultFCAlgorithm()", callingUid)) {
- return;
+ return null;
}
}
- mFieldClassificationStrategy.getDefaultAlgorithm(callback);
+ return mFieldClassificationStrategy.getDefaultAlgorithm();
}
@Override
diff --git a/services/autofill/java/com/android/server/autofill/AutofillManagerServiceShellCommand.java b/services/autofill/java/com/android/server/autofill/AutofillManagerServiceShellCommand.java
index 44560879f028..4d69ef952f72 100644
--- a/services/autofill/java/com/android/server/autofill/AutofillManagerServiceShellCommand.java
+++ b/services/autofill/java/com/android/server/autofill/AutofillManagerServiceShellCommand.java
@@ -191,10 +191,7 @@ public final class AutofillManagerServiceShellCommand extends ShellCommand {
if (scores == null) {
pw.println("no score");
} else {
- pw.print("algorithm: ");
- pw.print(scores.getAlgorithm());
- pw.print(" score: ");
- pw.println(scores.getScores()[0][0]);
+ pw.println(scores.scores[0][0]);
}
latch.countDown();
}));
diff --git a/services/autofill/java/com/android/server/autofill/FieldClassificationStrategy.java b/services/autofill/java/com/android/server/autofill/FieldClassificationStrategy.java
index 7228f1d2a8ea..da5220104e3c 100644
--- a/services/autofill/java/com/android/server/autofill/FieldClassificationStrategy.java
+++ b/services/autofill/java/com/android/server/autofill/FieldClassificationStrategy.java
@@ -15,12 +15,12 @@
*/
package com.android.server.autofill;
-import static android.view.autofill.AutofillManager.EXTRA_AVAILABLE_ALGORITHMS;
-import static android.view.autofill.AutofillManager.EXTRA_DEFAULT_ALGORITHM;
import static android.view.autofill.AutofillManager.FC_SERVICE_TIMEOUT;
import static com.android.server.autofill.Helper.sDebug;
import static com.android.server.autofill.Helper.sVerbose;
+import static android.service.autofill.AutofillFieldClassificationService.SERVICE_META_DATA_KEY_AVAILABLE_ALGORITHMS;
+import static android.service.autofill.AutofillFieldClassificationService.SERVICE_META_DATA_KEY_DEFAULT_ALGORITHM;
import android.Manifest;
import android.annotation.MainThread;
@@ -33,6 +33,7 @@ import android.content.ServiceConnection;
import android.content.pm.PackageManager;
import android.content.pm.ResolveInfo;
import android.content.pm.ServiceInfo;
+import android.content.res.Resources;
import android.os.Binder;
import android.os.Bundle;
import android.os.IBinder;
@@ -49,6 +50,7 @@ import com.android.internal.annotations.GuardedBy;
import java.io.PrintWriter;
import java.util.ArrayList;
+import java.util.Arrays;
import java.util.List;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit;
@@ -80,7 +82,8 @@ final class FieldClassificationStrategy {
mUserId = userId;
}
- private ComponentName getServiceComponentName() {
+ @Nullable
+ private ServiceInfo getServiceInfo() {
final String packageName =
mContext.getPackageManager().getServicesSystemSharedLibraryPackageName();
if (packageName == null) {
@@ -96,9 +99,15 @@ final class FieldClassificationStrategy {
Slog.w(TAG, "No valid components found.");
return null;
}
- final ServiceInfo serviceInfo = resolveInfo.serviceInfo;
- final ComponentName name = new ComponentName(serviceInfo.packageName, serviceInfo.name);
+ return resolveInfo.serviceInfo;
+ }
+
+ @Nullable
+ private ComponentName getServiceComponentName() {
+ final ServiceInfo serviceInfo = getServiceInfo();
+ if (serviceInfo == null) return null;
+ final ComponentName name = new ComponentName(serviceInfo.packageName, serviceInfo.name);
if (!Manifest.permission.BIND_AUTOFILL_FIELD_CLASSIFICATION_SERVICE
.equals(serviceInfo.permission)) {
Slog.w(TAG, name.flattenToShortString() + " does not require permission "
@@ -204,12 +213,40 @@ final class FieldClassificationStrategy {
}
}
- void getAvailableAlgorithms(RemoteCallback callback) {
- connectAndRun((service) -> service.getAvailableAlgorithms(callback));
+ /**
+ * Gets the name of all available algorithms.
+ */
+ @Nullable
+ String[] getAvailableAlgorithms() {
+ return getMetadataValue(SERVICE_META_DATA_KEY_AVAILABLE_ALGORITHMS,
+ (res, id) -> res.getStringArray(id));
}
- void getDefaultAlgorithm(RemoteCallback callback) {
- connectAndRun((service) -> service.getDefaultAlgorithm(callback));
+ /**
+ * Gets the default algorithm that's used when an algorithm is not specified or is invalid.
+ */
+ @Nullable
+ String getDefaultAlgorithm() {
+ return getMetadataValue(SERVICE_META_DATA_KEY_DEFAULT_ALGORITHM, (res, id) -> res.getString(id));
+ }
+
+ @Nullable
+ private <T> T getMetadataValue(String field, MetadataParser<T> parser) {
+ final ServiceInfo serviceInfo = getServiceInfo();
+ if (serviceInfo == null) return null;
+
+ final PackageManager pm = mContext.getPackageManager();
+
+ final Resources res;
+ try {
+ res = pm.getResourcesForApplication(serviceInfo.applicationInfo);
+ } catch (PackageManager.NameNotFoundException e) {
+ Log.e(TAG, "Error getting application resources for " + serviceInfo, e);
+ return null;
+ }
+
+ final int resourceId = serviceInfo.metaData.getInt(field);
+ return parser.get(res, resourceId);
}
//TODO(b/70291841): rename this method (and all others in the chain) to something like
@@ -237,43 +274,16 @@ final class FieldClassificationStrategy {
}
pw.println(impl.flattenToShortString());
- final CountDownLatch latch = new CountDownLatch(2);
-
- // Lock used to make sure lines don't overlap
- final Object lock = latch;
-
- connectAndRun((service) -> service.getAvailableAlgorithms(new RemoteCallback((bundle) -> {
- synchronized (lock) {
- pw.print(prefix); pw.print("Available algorithms: ");
- pw.println(bundle.getStringArrayList(EXTRA_AVAILABLE_ALGORITHMS));
- }
- latch.countDown();
- })));
-
- connectAndRun((service) -> service.getDefaultAlgorithm(new RemoteCallback((bundle) -> {
- synchronized (lock) {
- pw.print(prefix); pw.print("Default algorithm: ");
- pw.println(bundle.getString(EXTRA_DEFAULT_ALGORITHM));
- }
- latch.countDown();
- })));
-
- try {
- if (!latch.await(FC_SERVICE_TIMEOUT, TimeUnit.MILLISECONDS)) {
- synchronized (lock) {
- pw.print(prefix); pw.print("timeout ("); pw.print(FC_SERVICE_TIMEOUT);
- pw.println("ms) waiting for service");
- }
- }
- } catch (InterruptedException e) {
- synchronized (lock) {
- pw.print(prefix); pw.println("interrupted while waiting for service");
- }
- Thread.currentThread().interrupt();
- }
+ pw.print(prefix); pw.print("Available algorithms: ");
+ pw.println(Arrays.toString(getAvailableAlgorithms()));
+ pw.print(prefix); pw.print("Default algorithm: "); pw.println(getDefaultAlgorithm());
}
- private interface Command {
+ private static interface Command {
void run(IAutofillFieldClassificationService service) throws RemoteException;
}
+
+ private static interface MetadataParser<T> {
+ T get(Resources res, int resId);
+ }
}
diff --git a/services/autofill/java/com/android/server/autofill/Session.java b/services/autofill/java/com/android/server/autofill/Session.java
index a0e23a152224..63f83849db34 100644
--- a/services/autofill/java/com/android/server/autofill/Session.java
+++ b/services/autofill/java/com/android/server/autofill/Session.java
@@ -1172,8 +1172,6 @@ final class Session implements RemoteFillService.FillServiceCallbacks, ViewState
Slog.w(TAG, "No field classification score on " + result);
return;
}
- final float[][] scoresMatrix = scores.getScores();
-
int i = 0, j = 0;
try {
for (i = 0; i < viewsSize; i++) {
@@ -1182,8 +1180,7 @@ final class Session implements RemoteFillService.FillServiceCallbacks, ViewState
ArrayList<Match> matches = null;
for (j = 0; j < userValues.length; j++) {
String remoteId = remoteIds[j];
- final String actualAlgorithm = scores.getAlgorithm();
- final float score = scoresMatrix[i][j];
+ final float score = scores.scores[i][j];
if (score > 0) {
if (sVerbose) {
Slog.v(TAG, "adding score " + score + " at index " + j + " and id "
@@ -1192,7 +1189,7 @@ final class Session implements RemoteFillService.FillServiceCallbacks, ViewState
if (matches == null) {
matches = new ArrayList<>(userValues.length);
}
- matches.add(new Match(remoteId, score, actualAlgorithm));
+ matches.add(new Match(remoteId, score));
}
else if (sVerbose) {
Slog.v(TAG, "skipping score 0 at index " + j + " and id " + fieldId);
@@ -1205,7 +1202,7 @@ final class Session implements RemoteFillService.FillServiceCallbacks, ViewState
}
} catch (ArrayIndexOutOfBoundsException e) {
Slog.wtf(TAG, "Error accessing FC score at " + i + " x " + j + ": "
- + Arrays.toString(scoresMatrix), e);
+ + Arrays.toString(scores.scores), e);
return;
}
diff --git a/services/backup/java/com/android/server/backup/RefactoredBackupManagerService.java b/services/backup/java/com/android/server/backup/RefactoredBackupManagerService.java
index 518891006b37..465bb09927a5 100644
--- a/services/backup/java/com/android/server/backup/RefactoredBackupManagerService.java
+++ b/services/backup/java/com/android/server/backup/RefactoredBackupManagerService.java
@@ -3464,16 +3464,21 @@ public class RefactoredBackupManagerService implements BackupManagerServiceInter
mContext.enforceCallingOrSelfPermission(
android.Manifest.permission.BACKUP, "isAppEligibleForBackup");
- String callerLogString = "BMS.isAppEligibleForBackup";
- TransportClient transportClient =
- mTransportManager.getCurrentTransportClient(callerLogString);
- boolean eligible =
- AppBackupUtils.appIsRunningAndEligibleForBackupWithTransport(
- transportClient, packageName, mPackageManager);
- if (transportClient != null) {
- mTransportManager.disposeOfTransportClient(transportClient, callerLogString);
+ long oldToken = Binder.clearCallingIdentity();
+ try {
+ String callerLogString = "BMS.isAppEligibleForBackup";
+ TransportClient transportClient =
+ mTransportManager.getCurrentTransportClient(callerLogString);
+ boolean eligible =
+ AppBackupUtils.appIsRunningAndEligibleForBackupWithTransport(
+ transportClient, packageName, mPackageManager);
+ if (transportClient != null) {
+ mTransportManager.disposeOfTransportClient(transportClient, callerLogString);
+ }
+ return eligible;
+ } finally {
+ Binder.restoreCallingIdentity(oldToken);
}
- return eligible;
}
@Override
@@ -3481,21 +3486,26 @@ public class RefactoredBackupManagerService implements BackupManagerServiceInter
mContext.enforceCallingOrSelfPermission(
android.Manifest.permission.BACKUP, "filterAppsEligibleForBackup");
- String callerLogString = "BMS.filterAppsEligibleForBackup";
- TransportClient transportClient =
- mTransportManager.getCurrentTransportClient(callerLogString);
- List<String> eligibleApps = new LinkedList<>();
- for (String packageName : packages) {
- if (AppBackupUtils
- .appIsRunningAndEligibleForBackupWithTransport(
- transportClient, packageName, mPackageManager)) {
- eligibleApps.add(packageName);
+ long oldToken = Binder.clearCallingIdentity();
+ try {
+ String callerLogString = "BMS.filterAppsEligibleForBackup";
+ TransportClient transportClient =
+ mTransportManager.getCurrentTransportClient(callerLogString);
+ List<String> eligibleApps = new LinkedList<>();
+ for (String packageName : packages) {
+ if (AppBackupUtils
+ .appIsRunningAndEligibleForBackupWithTransport(
+ transportClient, packageName, mPackageManager)) {
+ eligibleApps.add(packageName);
+ }
}
+ if (transportClient != null) {
+ mTransportManager.disposeOfTransportClient(transportClient, callerLogString);
+ }
+ return eligibleApps.toArray(new String[eligibleApps.size()]);
+ } finally {
+ Binder.restoreCallingIdentity(oldToken);
}
- if (transportClient != null) {
- mTransportManager.disposeOfTransportClient(transportClient, callerLogString);
- }
- return eligibleApps.toArray(new String[eligibleApps.size()]);
}
@Override
@@ -3514,6 +3524,9 @@ public class RefactoredBackupManagerService implements BackupManagerServiceInter
} else if ("agents".startsWith(arg)) {
dumpAgents(pw);
return;
+ } else if ("transportclients".equals(arg.toLowerCase())) {
+ mTransportManager.dump(pw);
+ return;
}
}
}
@@ -3576,6 +3589,8 @@ public class RefactoredBackupManagerService implements BackupManagerServiceInter
}
}
+ mTransportManager.dump(pw);
+
pw.println("Pending init: " + mPendingInits.size());
for (String s : mPendingInits) {
pw.println(" " + s);
diff --git a/services/backup/java/com/android/server/backup/TransportManager.java b/services/backup/java/com/android/server/backup/TransportManager.java
index 5b901ee2b3da..7e179e5d24f8 100644
--- a/services/backup/java/com/android/server/backup/TransportManager.java
+++ b/services/backup/java/com/android/server/backup/TransportManager.java
@@ -29,6 +29,7 @@ import android.content.pm.ResolveInfo;
import android.os.RemoteException;
import android.os.UserHandle;
import android.util.ArrayMap;
+import android.util.ArraySet;
import android.util.Slog;
import com.android.internal.annotations.GuardedBy;
@@ -42,13 +43,12 @@ import com.android.server.backup.transport.TransportConnectionListener;
import com.android.server.backup.transport.TransportNotAvailableException;
import com.android.server.backup.transport.TransportNotRegisteredException;
+import java.io.PrintWriter;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.function.Consumer;
import java.util.function.Predicate;
-import java.util.stream.Collectors;
-import java.util.stream.Stream;
/** Handles in-memory bookkeeping of all BackupTransport objects. */
public class TransportManager {
@@ -119,10 +119,10 @@ public class TransportManager {
void onPackageChanged(String packageName, String... components) {
// Unfortunately this can't be atomic because we risk a deadlock if
// registerTransportsFromPackage() is put inside the synchronized block
- Set<ComponentName> transportComponents =
- Stream.of(components)
- .map(component -> new ComponentName(packageName, component))
- .collect(Collectors.toSet());
+ Set<ComponentName> transportComponents = new ArraySet<>(components.length);
+ for (String componentName : components) {
+ transportComponents.add(new ComponentName(packageName, componentName));
+ }
synchronized (mTransportLock) {
mRegisteredTransportsDescriptionMap.keySet().removeIf(transportComponents::contains);
}
@@ -151,11 +151,13 @@ public class TransportManager {
*/
String[] getRegisteredTransportNames() {
synchronized (mTransportLock) {
- return mRegisteredTransportsDescriptionMap
- .values()
- .stream()
- .map(transportDescription -> transportDescription.name)
- .toArray(String[]::new);
+ String[] transportNames = new String[mRegisteredTransportsDescriptionMap.size()];
+ int i = 0;
+ for (TransportDescription description : mRegisteredTransportsDescriptionMap.values()) {
+ transportNames[i] = description.name;
+ i++;
+ }
+ return transportNames;
}
}
@@ -632,6 +634,10 @@ public class TransportManager {
!Thread.holdsLock(mTransportLock), "Can't call transport with transport lock held");
}
+ public void dump(PrintWriter pw) {
+ mTransportClientManager.dump(pw);
+ }
+
private static Predicate<ComponentName> fromPackageFilter(String packageName) {
return transportComponent -> packageName.equals(transportComponent.getPackageName());
}
diff --git a/services/backup/java/com/android/server/backup/transport/TransportClient.java b/services/backup/java/com/android/server/backup/transport/TransportClient.java
index 399f338d26b2..7b2e3df67942 100644
--- a/services/backup/java/com/android/server/backup/transport/TransportClient.java
+++ b/services/backup/java/com/android/server/backup/transport/TransportClient.java
@@ -16,6 +16,8 @@
package com.android.server.backup.transport;
+import static com.android.server.backup.transport.TransportUtils.formatMessage;
+
import android.annotation.IntDef;
import android.annotation.Nullable;
import android.annotation.WorkerThread;
@@ -28,6 +30,7 @@ import android.os.Handler;
import android.os.IBinder;
import android.os.Looper;
import android.os.UserHandle;
+import android.text.format.DateFormat;
import android.util.ArrayMap;
import android.util.EventLog;
import android.util.Log;
@@ -41,6 +44,9 @@ import com.android.server.backup.TransportManager;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
+import java.util.Collections;
+import java.util.LinkedList;
+import java.util.List;
import java.util.Map;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutionException;
@@ -65,6 +71,7 @@ import java.util.concurrent.ExecutionException;
*/
public class TransportClient {
private static final String TAG = "TransportClient";
+ private static final int LOG_BUFFER_SIZE = 5;
private final Context mContext;
private final Intent mBindIntent;
@@ -73,6 +80,10 @@ public class TransportClient {
private final Handler mListenerHandler;
private final String mPrefixForLog;
private final Object mStateLock = new Object();
+ private final Object mLogBufferLock = new Object();
+
+ @GuardedBy("mLogBufferLock")
+ private final List<String> mLogBuffer = new LinkedList<>();
@GuardedBy("mStateLock")
private final Map<TransportConnectionListener, String> mListeners = new ArrayMap<>();
@@ -112,7 +123,7 @@ public class TransportClient {
// For logging
String classNameForLog = mTransportComponent.getShortClassName().replaceFirst(".*\\.", "");
- mPrefixForLog = classNameForLog + "#" + mIdentifier + ": ";
+ mPrefixForLog = classNameForLog + "#" + mIdentifier + ":";
}
public ComponentName getTransportComponent() {
@@ -229,7 +240,7 @@ public class TransportClient {
switch (mState) {
case State.UNUSABLE:
- log(Log.DEBUG, caller, "Async connect: UNUSABLE client");
+ log(Log.WARN, caller, "Async connect: UNUSABLE client");
notifyListener(listener, null, caller);
break;
case State.IDLE:
@@ -324,14 +335,14 @@ public class TransportClient {
IBackupTransport transport = mTransport;
if (transport != null) {
- log(Log.DEBUG, caller, "Sync connect: reusing transport");
+ log(Log.INFO, caller, "Sync connect: reusing transport");
return transport;
}
// If it's already UNUSABLE we return straight away, no need to go to main-thread
synchronized (mStateLock) {
if (mState == State.UNUSABLE) {
- log(Log.DEBUG, caller, "Sync connect: UNUSABLE client");
+ log(Log.WARN, caller, "Sync connect: UNUSABLE client");
return null;
}
}
@@ -403,13 +414,16 @@ public class TransportClient {
}
private void notifyListener(
- TransportConnectionListener listener, IBackupTransport transport, String caller) {
- log(Log.VERBOSE, caller, "Notifying listener of transport = " + transport);
+ TransportConnectionListener listener,
+ @Nullable IBackupTransport transport,
+ String caller) {
+ String transportString = (transport != null) ? "IBackupTransport" : "null";
+ log(Log.INFO, "Notifying [" + caller + "] transport = " + transportString);
mListenerHandler.post(() -> listener.onTransportConnectionResult(transport, this));
}
@GuardedBy("mStateLock")
- private void notifyListenersAndClearLocked(IBackupTransport transport) {
+ private void notifyListenersAndClearLocked(@Nullable IBackupTransport transport) {
for (Map.Entry<TransportConnectionListener, String> entry : mListeners.entrySet()) {
TransportConnectionListener listener = entry.getKey();
String caller = entry.getValue();
@@ -509,13 +523,30 @@ public class TransportClient {
}
private void log(int priority, String message) {
- TransportUtils.log(priority, TAG, message);
+ TransportUtils.log(priority, TAG, formatMessage(mPrefixForLog, null, message));
+ saveLogEntry(formatMessage(null, null, message));
}
- private void log(int priority, String caller, String msg) {
- TransportUtils.log(priority, TAG, mPrefixForLog, caller, msg);
- // TODO(brufino): Log in internal list for dump
- // CharSequence time = DateFormat.format("yyyy-MM-dd HH:mm:ss", System.currentTimeMillis());
+ private void log(int priority, String caller, String message) {
+ TransportUtils.log(priority, TAG, formatMessage(mPrefixForLog, caller, message));
+ saveLogEntry(formatMessage(null, caller, message));
+ }
+
+ private void saveLogEntry(String message) {
+ CharSequence time = DateFormat.format("yyyy-MM-dd HH:mm:ss", System.currentTimeMillis());
+ message = time + " " + message;
+ synchronized (mLogBufferLock) {
+ if (mLogBuffer.size() == LOG_BUFFER_SIZE) {
+ mLogBuffer.remove(mLogBuffer.size() - 1);
+ }
+ mLogBuffer.add(0, message);
+ }
+ }
+
+ List<String> getLogBuffer() {
+ synchronized (mLogBufferLock) {
+ return Collections.unmodifiableList(mLogBuffer);
+ }
}
@IntDef({Transition.DOWN, Transition.NO_TRANSITION, Transition.UP})
diff --git a/services/backup/java/com/android/server/backup/transport/TransportClientManager.java b/services/backup/java/com/android/server/backup/transport/TransportClientManager.java
index 1cbe74716b03..1132bce612b7 100644
--- a/services/backup/java/com/android/server/backup/transport/TransportClientManager.java
+++ b/services/backup/java/com/android/server/backup/transport/TransportClientManager.java
@@ -17,19 +17,20 @@
package com.android.server.backup.transport;
import static com.android.server.backup.TransportManager.SERVICE_ACTION_TRANSPORT_HOST;
+import static com.android.server.backup.transport.TransportUtils.formatMessage;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.util.Log;
-
import com.android.server.backup.TransportManager;
+import java.io.PrintWriter;
+import java.util.Map;
+import java.util.WeakHashMap;
/**
* Manages the creation and disposal of {@link TransportClient}s. The only class that should use
* this is {@link TransportManager}, all the other usages should go to {@link TransportManager}.
- *
- * <p>TODO(brufino): Implement pool of TransportClients
*/
public class TransportClientManager {
private static final String TAG = "TransportClientManager";
@@ -37,6 +38,7 @@ public class TransportClientManager {
private final Context mContext;
private final Object mTransportClientsLock = new Object();
private int mTransportClientsCreated = 0;
+ private Map<TransportClient, String> mTransportClientsCallerMap = new WeakHashMap<>();
public TransportClientManager(Context context) {
mContext = context;
@@ -62,8 +64,10 @@ public class TransportClientManager {
bindIntent,
transportComponent,
Integer.toString(mTransportClientsCreated));
+ mTransportClientsCallerMap.put(transportClient, caller);
mTransportClientsCreated++;
- TransportUtils.log(Log.DEBUG, TAG, caller, "Retrieving " + transportClient);
+ TransportUtils.log(
+ Log.DEBUG, TAG, formatMessage(null, caller, "Retrieving " + transportClient));
return transportClient;
}
}
@@ -77,7 +81,25 @@ public class TransportClientManager {
* details.
*/
public void disposeOfTransportClient(TransportClient transportClient, String caller) {
- TransportUtils.log(Log.DEBUG, TAG, caller, "Disposing of " + transportClient);
transportClient.unbind(caller);
+ synchronized (mTransportClientsLock) {
+ TransportUtils.log(
+ Log.DEBUG, TAG, formatMessage(null, caller, "Disposing of " + transportClient));
+ mTransportClientsCallerMap.remove(transportClient);
+ }
+ }
+
+ public void dump(PrintWriter pw) {
+ pw.println("Transport clients created: " + mTransportClientsCreated);
+ synchronized (mTransportClientsLock) {
+ pw.println("Current transport clients: " + mTransportClientsCallerMap.size());
+ for (TransportClient transportClient : mTransportClientsCallerMap.keySet()) {
+ String caller = mTransportClientsCallerMap.get(transportClient);
+ pw.println(" " + transportClient + " [" + caller + "]");
+ for (String logEntry : transportClient.getLogBuffer()) {
+ pw.println(" " + logEntry);
+ }
+ }
+ }
}
}
diff --git a/services/backup/java/com/android/server/backup/transport/TransportUtils.java b/services/backup/java/com/android/server/backup/transport/TransportUtils.java
index 92bba9bf06f0..56b2d44ec420 100644
--- a/services/backup/java/com/android/server/backup/transport/TransportUtils.java
+++ b/services/backup/java/com/android/server/backup/transport/TransportUtils.java
@@ -41,21 +41,20 @@ public class TransportUtils {
}
static void log(int priority, String tag, String message) {
- log(priority, tag, null, message);
- }
-
- static void log(int priority, String tag, @Nullable String caller, String message) {
- log(priority, tag, "", caller, message);
+ if (Log.isLoggable(tag, priority)) {
+ Slog.println(priority, tag, message);
+ }
}
- static void log(
- int priority, String tag, String prefix, @Nullable String caller, String message) {
- if (Log.isLoggable(tag, priority)) {
- if (caller != null) {
- prefix += "[" + caller + "] ";
- }
- Slog.println(priority, tag, prefix + message);
+ static String formatMessage(@Nullable String prefix, @Nullable String caller, String message) {
+ StringBuilder string = new StringBuilder();
+ if (prefix != null) {
+ string.append(prefix).append(" ");
+ }
+ if (caller != null) {
+ string.append("[").append(caller).append("] ");
}
+ return string.append(message).toString();
}
private TransportUtils() {}
diff --git a/services/core/java/com/android/server/BatteryService.java b/services/core/java/com/android/server/BatteryService.java
index 04d292fa1ae4..dc5f5a270748 100644
--- a/services/core/java/com/android/server/BatteryService.java
+++ b/services/core/java/com/android/server/BatteryService.java
@@ -383,16 +383,16 @@ public final class BatteryService extends SystemService {
}
}
- private void update(HealthInfo info) {
+ private void update(android.hardware.health.V2_0.HealthInfo info) {
traceBegin("HealthInfoUpdate");
synchronized (mLock) {
if (!mUpdatesStopped) {
- mHealthInfo = info;
+ mHealthInfo = info.legacy;
// Process the new values.
processValuesLocked(false);
mLock.notifyAll(); // for any waiters on new info
} else {
- copy(mLastHealthInfo, info);
+ copy(mLastHealthInfo, info.legacy);
}
}
traceEnd();
@@ -1010,7 +1010,7 @@ public final class BatteryService extends SystemService {
private final class HealthHalCallback extends IHealthInfoCallback.Stub
implements HealthServiceWrapper.Callback {
- @Override public void healthInfoChanged(HealthInfo props) {
+ @Override public void healthInfoChanged(android.hardware.health.V2_0.HealthInfo props) {
BatteryService.this.update(props);
}
// on new service registered
diff --git a/services/core/java/com/android/server/BluetoothManagerService.java b/services/core/java/com/android/server/BluetoothManagerService.java
index 337406d58f9d..20777901a3aa 100644
--- a/services/core/java/com/android/server/BluetoothManagerService.java
+++ b/services/core/java/com/android/server/BluetoothManagerService.java
@@ -439,10 +439,17 @@ class BluetoothManagerService extends IBluetoothManager.Stub {
Settings.Global.AIRPLANE_MODE_ON, 0) == 1;
}
+ private boolean supportBluetoothPersistedState() {
+ return mContext.getResources().getBoolean(R.bool.config_supportBluetoothPersistedState);
+ }
+
/**
* Returns true if the Bluetooth saved state is "on"
*/
private boolean isBluetoothPersistedStateOn() {
+ if (!supportBluetoothPersistedState()) {
+ return false;
+ }
int state = Settings.Global.getInt(mContentResolver, Settings.Global.BLUETOOTH_ON, -1);
if (DBG) {
Slog.d(TAG, "Bluetooth persisted state: " + state);
@@ -454,6 +461,9 @@ class BluetoothManagerService extends IBluetoothManager.Stub {
* Returns true if the Bluetooth saved state is BLUETOOTH_ON_BLUETOOTH
*/
private boolean isBluetoothPersistedStateOnBluetooth() {
+ if (!supportBluetoothPersistedState()) {
+ return false;
+ }
return Settings.Global.getInt(mContentResolver, Settings.Global.BLUETOOTH_ON,
BLUETOOTH_ON_BLUETOOTH) == BLUETOOTH_ON_BLUETOOTH;
}
diff --git a/services/core/java/com/android/server/ConnectivityService.java b/services/core/java/com/android/server/ConnectivityService.java
index 9574545682c1..c1f4b789e002 100644
--- a/services/core/java/com/android/server/ConnectivityService.java
+++ b/services/core/java/com/android/server/ConnectivityService.java
@@ -63,6 +63,7 @@ import android.net.NetworkConfig;
import android.net.NetworkInfo;
import android.net.NetworkInfo.DetailedState;
import android.net.NetworkMisc;
+import android.net.NetworkPolicyManager;
import android.net.NetworkQuotaInfo;
import android.net.NetworkRequest;
import android.net.NetworkSpecifier;
@@ -1501,15 +1502,12 @@ public class ConnectivityService extends IConnectivityManager.Stub
return true;
}
- private final INetworkPolicyListener mPolicyListener = new INetworkPolicyListener.Stub() {
+ private final INetworkPolicyListener mPolicyListener = new NetworkPolicyManager.Listener() {
@Override
public void onUidRulesChanged(int uid, int uidRules) {
// TODO: notify UID when it has requested targeted updates
}
@Override
- public void onMeteredIfacesChanged(String[] meteredIfaces) {
- }
- @Override
public void onRestrictBackgroundChanged(boolean restrictBackground) {
// TODO: relocate this specific callback in Tethering.
if (restrictBackground) {
@@ -1517,9 +1515,6 @@ public class ConnectivityService extends IConnectivityManager.Stub
mTethering.untetherAll();
}
}
- @Override
- public void onUidPoliciesChanged(int uid, int uidPolicies) {
- }
};
/**
@@ -4990,10 +4985,12 @@ public class ConnectivityService extends IConnectivityManager.Stub
} catch (Exception e) {
loge("Exception setting default network :" + e);
}
+
notifyLockdownVpn(newNetwork);
handleApplyDefaultProxy(newNetwork.linkProperties.getHttpProxy());
updateTcpBufferSizes(newNetwork);
mDnsManager.setDefaultDnsSystemProperties(newNetwork.linkProperties.getDnsServers());
+ notifyIfacesChangedForNetworkStats();
}
private void processListenRequests(NetworkAgentInfo nai, boolean capabilitiesChanged) {
@@ -5567,12 +5564,30 @@ public class ConnectivityService extends IConnectivityManager.Stub
}
/**
+ * Returns the list of all interfaces that could be used by network traffic that does not
+ * explicitly specify a network. This includes the default network, but also all VPNs that are
+ * currently connected.
+ *
+ * Must be called on the handler thread.
+ */
+ private Network[] getDefaultNetworks() {
+ ArrayList<Network> defaultNetworks = new ArrayList<>();
+ NetworkAgentInfo defaultNetwork = getDefaultNetwork();
+ for (NetworkAgentInfo nai : mNetworkAgentInfos.values()) {
+ if (nai.everConnected && (nai == defaultNetwork || nai.isVPN())) {
+ defaultNetworks.add(nai.network);
+ }
+ }
+ return defaultNetworks.toArray(new Network[0]);
+ }
+
+ /**
* Notify NetworkStatsService that the set of active ifaces has changed, or that one of the
* properties tracked by NetworkStatsService on an active iface has changed.
*/
private void notifyIfacesChangedForNetworkStats() {
try {
- mStatsService.forceUpdateIfaces();
+ mStatsService.forceUpdateIfaces(getDefaultNetworks());
} catch (Exception ignored) {
}
}
@@ -5604,7 +5619,7 @@ public class ConnectivityService extends IConnectivityManager.Stub
success = mVpns.get(user).setUnderlyingNetworks(networks);
}
if (success) {
- notifyIfacesChangedForNetworkStats();
+ mHandler.post(() -> notifyIfacesChangedForNetworkStats());
}
return success;
}
diff --git a/services/core/java/com/android/server/ForceAppStandbyTracker.java b/services/core/java/com/android/server/ForceAppStandbyTracker.java
index a75a3675f7f9..a538bde7487e 100644
--- a/services/core/java/com/android/server/ForceAppStandbyTracker.java
+++ b/services/core/java/com/android/server/ForceAppStandbyTracker.java
@@ -737,21 +737,23 @@ public class ForceAppStandbyTracker {
* @return whether alarms should be restricted for a UID package-name.
*/
public boolean areAlarmsRestricted(int uid, @NonNull String packageName) {
- return isRestricted(uid, packageName, /*useTempWhitelistToo=*/ false);
+ return isRestricted(uid, packageName, /*useTempWhitelistToo=*/ false,
+ /* exemptOnBatterySaver =*/ false);
}
/**
* @return whether jobs should be restricted for a UID package-name.
*/
public boolean areJobsRestricted(int uid, @NonNull String packageName) {
- return isRestricted(uid, packageName, /*useTempWhitelistToo=*/ true);
+ return isRestricted(uid, packageName, /*useTempWhitelistToo=*/ true,
+ /* exemptOnBatterySaver =*/ false);
}
/**
* @return whether force-app-standby is effective for a UID package-name.
*/
private boolean isRestricted(int uid, @NonNull String packageName,
- boolean useTempWhitelistToo) {
+ boolean useTempWhitelistToo, boolean exemptOnBatterySaver) {
if (isInForeground(uid)) {
return false;
}
@@ -765,12 +767,13 @@ public class ForceAppStandbyTracker {
ArrayUtils.contains(mTempWhitelistedAppIds, appId)) {
return false;
}
-
- if (mForceAllAppsStandby) {
+ if (mForcedAppStandbyEnabled && isRunAnyRestrictedLocked(uid, packageName)) {
return true;
}
-
- return mForcedAppStandbyEnabled && isRunAnyRestrictedLocked(uid, packageName);
+ if (exemptOnBatterySaver) {
+ return false;
+ }
+ return mForceAllAppsStandby;
}
}
diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java
index 29d33ce777f5..c0c684c41bc5 100644
--- a/services/core/java/com/android/server/am/ActivityManagerService.java
+++ b/services/core/java/com/android/server/am/ActivityManagerService.java
@@ -8601,6 +8601,16 @@ public class ActivityManagerService extends IActivityManager.Stub
}
return false;
}
+
+ @Override
+ public int getPackageUid(String packageName, int flags) {
+ try {
+ return mActivityManagerService.mContext.getPackageManager()
+ .getPackageUid(packageName, flags);
+ } catch (NameNotFoundException nnfe) {
+ return -1;
+ }
+ }
}
class IntentFirewallInterface implements IntentFirewall.AMSInterface {
diff --git a/services/core/java/com/android/server/am/ActivityStack.java b/services/core/java/com/android/server/am/ActivityStack.java
index f496a672e8d7..9d06b0dbab64 100644
--- a/services/core/java/com/android/server/am/ActivityStack.java
+++ b/services/core/java/com/android/server/am/ActivityStack.java
@@ -606,7 +606,7 @@ class ActivityStack<T extends StackWindowController> extends ConfigurationContai
true /* onTop */);
recentStack.moveToFront("setWindowingMode");
// If task moved to docked stack - show recents if needed.
- mService.mWindowManager.showRecentApps(false /* fromHome */);
+ mService.mWindowManager.showRecentApps();
}
wm.continueSurfaceLayout();
}
diff --git a/services/core/java/com/android/server/am/BatteryStatsService.java b/services/core/java/com/android/server/am/BatteryStatsService.java
index 81e8eb0d4136..207aaa76e5b8 100644
--- a/services/core/java/com/android/server/am/BatteryStatsService.java
+++ b/services/core/java/com/android/server/am/BatteryStatsService.java
@@ -40,6 +40,7 @@ import android.os.UserManagerInternal;
import android.os.WorkSource;
import android.os.WorkSource.WorkChain;
import android.os.connectivity.CellularBatteryStats;
+import android.os.connectivity.GpsBatteryStats;
import android.os.health.HealthStatsParceler;
import android.os.health.HealthStatsWriter;
import android.os.health.UidHealthStats;
@@ -594,6 +595,12 @@ public final class BatteryStatsService extends IBatteryStats.Stub
}
}
+ public void noteGpsSignalQuality(int signalLevel) {
+ synchronized (mStats) {
+ mStats.noteGpsSignalQualityLocked(signalLevel);
+ }
+ }
+
public void noteScreenState(int state) {
enforceCallingPermission();
if (DBG) Slog.d(TAG, "begin noteScreenState");
@@ -1448,6 +1455,16 @@ public final class BatteryStatsService extends IBatteryStats.Stub
}
/**
+ * Gets a snapshot of Gps stats
+ * @hide
+ */
+ public GpsBatteryStats getGpsBatteryStats() {
+ synchronized (mStats) {
+ return mStats.getGpsBatteryStats();
+ }
+ }
+
+ /**
* Gets a snapshot of the system health for a particular uid.
*/
@Override
diff --git a/services/core/java/com/android/server/am/GlobalSettingsToPropertiesMapper.java b/services/core/java/com/android/server/am/GlobalSettingsToPropertiesMapper.java
index c9afc17e1eb4..d6c6f96285a6 100644
--- a/services/core/java/com/android/server/am/GlobalSettingsToPropertiesMapper.java
+++ b/services/core/java/com/android/server/am/GlobalSettingsToPropertiesMapper.java
@@ -23,6 +23,7 @@ import android.os.SystemProperties;
import android.provider.Settings;
import android.text.TextUtils;
import android.util.Slog;
+import android.view.ThreadedRenderer;
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.util.Preconditions;
@@ -39,6 +40,7 @@ class GlobalSettingsToPropertiesMapper {
// List mapping entries in the following format:
// {Settings.Global.SETTING_NAME, "system_property_name"},
{Settings.Global.SYS_VDSO, "sys.vdso"},
+ {Settings.Global.FPS_DEVISOR, ThreadedRenderer.DEBUG_FPS_DIVISOR},
};
diff --git a/services/core/java/com/android/server/am/TaskRecord.java b/services/core/java/com/android/server/am/TaskRecord.java
index b131e86d83ed..809f19f64317 100644
--- a/services/core/java/com/android/server/am/TaskRecord.java
+++ b/services/core/java/com/android/server/am/TaskRecord.java
@@ -749,12 +749,7 @@ class TaskRecord extends ConfigurationContainer implements TaskWindowContainerLi
supervisor.handleNonResizableTaskIfNeeded(this, preferredStack.getWindowingMode(),
DEFAULT_DISPLAY, toStack);
- boolean successful = (preferredStack == toStack);
- if (successful && toStack.getWindowingMode() == WINDOWING_MODE_SPLIT_SCREEN_PRIMARY) {
- // If task moved to docked stack - show recents if needed.
- mService.mWindowManager.showRecentApps(false /* fromHome */);
- }
- return successful;
+ return (preferredStack == toStack);
}
/**
diff --git a/services/core/java/com/android/server/am/UserController.java b/services/core/java/com/android/server/am/UserController.java
index 65bebc6c235a..1a47aa5cd777 100644
--- a/services/core/java/com/android/server/am/UserController.java
+++ b/services/core/java/com/android/server/am/UserController.java
@@ -795,11 +795,13 @@ class UserController implements Handler.Callback {
*/
private void stopGuestOrEphemeralUserIfBackground(int oldUserId) {
if (DEBUG_MU) Slog.i(TAG, "Stop guest or ephemeral user if background: " + oldUserId);
- UserState oldUss = mStartedUsers.get(oldUserId);
- if (oldUserId == UserHandle.USER_SYSTEM || oldUserId == mCurrentUserId || oldUss == null
- || oldUss.state == UserState.STATE_STOPPING
- || oldUss.state == UserState.STATE_SHUTDOWN) {
- return;
+ synchronized(mLock) {
+ UserState oldUss = mStartedUsers.get(oldUserId);
+ if (oldUserId == UserHandle.USER_SYSTEM || oldUserId == mCurrentUserId || oldUss == null
+ || oldUss.state == UserState.STATE_STOPPING
+ || oldUss.state == UserState.STATE_SHUTDOWN) {
+ return;
+ }
}
UserInfo userInfo = getUserInfo(oldUserId);
diff --git a/services/core/java/com/android/server/audio/AudioService.java b/services/core/java/com/android/server/audio/AudioService.java
index 799f2a92bc33..a7147206bda2 100644
--- a/services/core/java/com/android/server/audio/AudioService.java
+++ b/services/core/java/com/android/server/audio/AudioService.java
@@ -1047,9 +1047,11 @@ public class AudioService extends IAudioService.Stub
private void checkMuteAffectedStreams() {
// any stream with a min level > 0 is not muteable by definition
+ // STREAM_VOICE_CALL can be muted by applications that has the the MODIFY_PHONE_STATE permission.
for (int i = 0; i < mStreamStates.length; i++) {
final VolumeStreamState vss = mStreamStates[i];
- if (vss.mIndexMin > 0) {
+ if (vss.mIndexMin > 0 &&
+ vss.mStreamType != AudioSystem.STREAM_VOICE_CALL) {
mMuteAffectedStreams &= ~(1 << vss.mStreamType);
}
}
@@ -1412,6 +1414,18 @@ public class AudioService extends IAudioService.Stub
return;
}
+ // If adjust is mute and the stream is STREAM_VOICE_CALL, make sure
+ // that the calling app have the MODIFY_PHONE_STATE permission.
+ if (isMuteAdjust &&
+ streamType == AudioSystem.STREAM_VOICE_CALL &&
+ mContext.checkCallingOrSelfPermission(
+ android.Manifest.permission.MODIFY_PHONE_STATE)
+ != PackageManager.PERMISSION_GRANTED) {
+ Log.w(TAG, "MODIFY_PHONE_STATE Permission Denial: adjustStreamVolume from pid="
+ + Binder.getCallingPid() + ", uid=" + Binder.getCallingUid());
+ return;
+ }
+
// use stream type alias here so that streams with same alias have the same behavior,
// including with regard to silent mode control (e.g the use of STREAM_RING below and in
// checkForRingerModeChange() in place of STREAM_RING or STREAM_NOTIFICATION)
@@ -1712,6 +1726,15 @@ public class AudioService extends IAudioService.Stub
+ " CHANGE_ACCESSIBILITY_VOLUME callingPackage=" + callingPackage);
return;
}
+ if ((streamType == AudioManager.STREAM_VOICE_CALL) &&
+ (index == 0) &&
+ (mContext.checkCallingOrSelfPermission(
+ android.Manifest.permission.MODIFY_PHONE_STATE)
+ != PackageManager.PERMISSION_GRANTED)) {
+ Log.w(TAG, "Trying to call setStreamVolume() for STREAM_VOICE_CALL and index 0 without"
+ + " MODIFY_PHONE_STATE callingPackage=" + callingPackage);
+ return;
+ }
mVolumeLogger.log(new VolumeEvent(VolumeEvent.VOL_SET_STREAM_VOL, streamType,
index/*val1*/, flags/*val2*/, callingPackage));
setStreamVolume(streamType, index, flags, callingPackage, callingPackage,
@@ -4132,22 +4155,30 @@ public class AudioService extends IAudioService.Stub
public int setBluetoothA2dpDeviceConnectionState(BluetoothDevice device, int state, int profile)
{
+ return setBluetoothA2dpDeviceConnectionStateSuppressNoisyIntent(
+ device, state, profile, false /* suppressNoisyIntent */);
+ }
+
+ public int setBluetoothA2dpDeviceConnectionStateSuppressNoisyIntent(BluetoothDevice device,
+ int state, int profile, boolean suppressNoisyIntent)
+ {
if (mAudioHandler.hasMessages(MSG_SET_A2DP_SINK_CONNECTION_STATE, device)) {
return 0;
}
return setBluetoothA2dpDeviceConnectionStateInt(
- device, state, profile, AudioSystem.DEVICE_NONE);
+ device, state, profile, suppressNoisyIntent, AudioSystem.DEVICE_NONE);
}
public int setBluetoothA2dpDeviceConnectionStateInt(
- BluetoothDevice device, int state, int profile, int musicDevice)
+ BluetoothDevice device, int state, int profile, boolean suppressNoisyIntent,
+ int musicDevice)
{
int delay;
if (profile != BluetoothProfile.A2DP && profile != BluetoothProfile.A2DP_SINK) {
throw new IllegalArgumentException("invalid profile " + profile);
}
synchronized (mConnectedDevices) {
- if (profile == BluetoothProfile.A2DP) {
+ if (profile == BluetoothProfile.A2DP && !suppressNoisyIntent) {
int intState = (state == BluetoothA2dp.STATE_CONNECTED) ? 1 : 0;
delay = checkSendBecomingNoisyIntent(AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP,
intState, musicDevice);
@@ -4503,27 +4534,30 @@ public class AudioService extends IAudioService.Stub
if (mStreamType == srcStream.mStreamType) {
return;
}
- synchronized (VolumeStreamState.class) {
- int srcStreamType = srcStream.getStreamType();
- // apply default device volume from source stream to all devices first in case
- // some devices are present in this stream state but not in source stream state
- int index = srcStream.getIndex(AudioSystem.DEVICE_OUT_DEFAULT);
- index = rescaleIndex(index, srcStreamType, mStreamType);
- for (int i = 0; i < mIndexMap.size(); i++) {
- mIndexMap.put(mIndexMap.keyAt(i), index);
- }
- // Now apply actual volume for devices in source stream state
- SparseIntArray srcMap = srcStream.mIndexMap;
- for (int i = 0; i < srcMap.size(); i++) {
- int device = srcMap.keyAt(i);
- index = srcMap.valueAt(i);
+ synchronized (mSettingsLock) {
+ synchronized (VolumeStreamState.class) {
+ int srcStreamType = srcStream.getStreamType();
+ // apply default device volume from source stream to all devices first in case
+ // some devices are present in this stream state but not in source stream state
+ int index = srcStream.getIndex(AudioSystem.DEVICE_OUT_DEFAULT);
index = rescaleIndex(index, srcStreamType, mStreamType);
-
- setIndex(index, device, caller);
+ for (int i = 0; i < mIndexMap.size(); i++) {
+ mIndexMap.put(mIndexMap.keyAt(i), index);
+ }
+ // Now apply actual volume for devices in source stream state
+ SparseIntArray srcMap = srcStream.mIndexMap;
+ for (int i = 0; i < srcMap.size(); i++) {
+ int device = srcMap.keyAt(i);
+ index = srcMap.valueAt(i);
+ index = rescaleIndex(index, srcStreamType, mStreamType);
+
+ setIndex(index, device, caller);
+ }
}
}
}
+ @GuardedBy("mSettingsLock")
public void setAllIndexesToMax() {
synchronized (VolumeStreamState.class) {
for (int i = 0; i < mIndexMap.size(); i++) {
@@ -5397,7 +5431,7 @@ public class AudioService extends IAudioService.Stub
// consistent with audio policy manager state
setBluetoothA2dpDeviceConnectionStateInt(
btDevice, BluetoothA2dp.STATE_DISCONNECTED, BluetoothProfile.A2DP,
- musicDevice);
+ false /* suppressNoisyIntent */, musicDevice);
}
}
}
diff --git a/services/core/java/com/android/server/broadcastradio/hal2/TunerSession.java b/services/core/java/com/android/server/broadcastradio/hal2/TunerSession.java
index e093c9df7c4b..1ae7d20fb3fe 100644
--- a/services/core/java/com/android/server/broadcastradio/hal2/TunerSession.java
+++ b/services/core/java/com/android/server/broadcastradio/hal2/TunerSession.java
@@ -222,7 +222,7 @@ class TunerSession extends ITuner.Stub {
MutableInt halResult = new MutableInt(Result.UNKNOWN_ERROR);
MutableBoolean flagState = new MutableBoolean(false);
try {
- mHwSession.getConfigFlag(flag, (int result, boolean value) -> {
+ mHwSession.isConfigFlagSet(flag, (int result, boolean value) -> {
halResult.value = result;
flagState.value = value;
});
diff --git a/services/core/java/com/android/server/display/LocalDisplayAdapter.java b/services/core/java/com/android/server/display/LocalDisplayAdapter.java
index fc3c1f74ce4f..b7385d85d296 100644
--- a/services/core/java/com/android/server/display/LocalDisplayAdapter.java
+++ b/services/core/java/com/android/server/display/LocalDisplayAdapter.java
@@ -404,7 +404,7 @@ final class LocalDisplayAdapter extends DisplayAdapter {
&& SystemProperties.getBoolean(PROPERTY_EMULATOR_CIRCULAR, false))) {
mInfo.flags |= DisplayDeviceInfo.FLAG_ROUND;
}
- mInfo.displayCutout = parseDefaultDisplayCutout(res);
+ mInfo.displayCutout = DisplayCutout.fromResources(res, mInfo.width);
mInfo.type = Display.TYPE_BUILT_IN;
mInfo.densityDpi = (int)(phys.density * 160 + 0.5f);
mInfo.xDpi = phys.xDpi;
@@ -440,15 +440,6 @@ final class LocalDisplayAdapter extends DisplayAdapter {
return mInfo;
}
- private DisplayCutout parseDefaultDisplayCutout(Resources res) {
- String cutoutString = res.getString(
- com.android.internal.R.string.config_mainBuiltInDisplayCutout);
- if (TextUtils.isEmpty(cutoutString)) {
- return null;
- }
- return DisplayCutout.fromBounds(PathParser.createPathFromPathData(cutoutString));
- }
-
@Override
public Runnable requestDisplayStateLocked(final int state, final int brightness) {
// Assume that the brightness is off if the display is being turned off.
diff --git a/services/core/java/com/android/server/hdmi/DeviceDiscoveryAction.java b/services/core/java/com/android/server/hdmi/DeviceDiscoveryAction.java
index 97a6e850654b..db8dedbf12cc 100644..100755
--- a/services/core/java/com/android/server/hdmi/DeviceDiscoveryAction.java
+++ b/services/core/java/com/android/server/hdmi/DeviceDiscoveryAction.java
@@ -228,12 +228,20 @@ final class DeviceDiscoveryAction extends HdmiCecFeatureAction {
if (cmd.getOpcode() == Constants.MESSAGE_SET_OSD_NAME) {
handleSetOsdName(cmd);
return true;
+ } else if ((cmd.getOpcode() == Constants.MESSAGE_FEATURE_ABORT) &&
+ ((cmd.getParams()[0] & 0xFF) == Constants.MESSAGE_GIVE_OSD_NAME)) {
+ handleSetOsdName(cmd);
+ return true;
}
return false;
case STATE_WAITING_FOR_VENDOR_ID:
if (cmd.getOpcode() == Constants.MESSAGE_DEVICE_VENDOR_ID) {
handleVendorId(cmd);
return true;
+ } else if ((cmd.getOpcode() == Constants.MESSAGE_FEATURE_ABORT) &&
+ ((cmd.getParams()[0] & 0xFF) == Constants.MESSAGE_GIVE_DEVICE_VENDOR_ID)) {
+ handleVendorId(cmd);
+ return true;
}
return false;
case STATE_WAITING_FOR_DEVICE_POLLING:
@@ -281,7 +289,11 @@ final class DeviceDiscoveryAction extends HdmiCecFeatureAction {
String displayName = null;
try {
- displayName = new String(cmd.getParams(), "US-ASCII");
+ if (cmd.getOpcode() == Constants.MESSAGE_FEATURE_ABORT) {
+ displayName = HdmiUtils.getDefaultDeviceName(current.mLogicalAddress);
+ } else {
+ displayName = new String(cmd.getParams(), "US-ASCII");
+ }
} catch (UnsupportedEncodingException e) {
Slog.w(TAG, "Failed to decode display name: " + cmd.toString());
// If failed to get display name, use the default name of device.
@@ -302,9 +314,12 @@ final class DeviceDiscoveryAction extends HdmiCecFeatureAction {
return;
}
- byte[] params = cmd.getParams();
- int vendorId = HdmiUtils.threeBytesToInt(params);
- current.mVendorId = vendorId;
+ if (cmd.getOpcode() != Constants.MESSAGE_FEATURE_ABORT) {
+ byte[] params = cmd.getParams();
+ int vendorId = HdmiUtils.threeBytesToInt(params);
+ current.mVendorId = vendorId;
+ }
+
increaseProcessedDeviceCount();
checkAndProceedStage();
}
diff --git a/services/core/java/com/android/server/hdmi/HdmiCecLocalDeviceTv.java b/services/core/java/com/android/server/hdmi/HdmiCecLocalDeviceTv.java
index 81bccdc7dfaa..1e09383db56d 100644
--- a/services/core/java/com/android/server/hdmi/HdmiCecLocalDeviceTv.java
+++ b/services/core/java/com/android/server/hdmi/HdmiCecLocalDeviceTv.java
@@ -698,10 +698,9 @@ final class HdmiCecLocalDeviceTv extends HdmiCecLocalDevice {
protected boolean handleReportAudioStatus(HdmiCecMessage message) {
assertRunOnServiceThread();
- byte params[] = message.getParams();
- int mute = params[0] & 0x80;
- int volume = params[0] & 0x7F;
- setAudioStatus(mute == 0x80, volume);
+ boolean mute = HdmiUtils.isAudioStatusMute(message);
+ int volume = HdmiUtils.getAudioStatusVolume(message);
+ setAudioStatus(mute, volume);
return true;
}
@@ -1004,6 +1003,9 @@ final class HdmiCecLocalDeviceTv extends HdmiCecLocalDevice {
}
void setAudioStatus(boolean mute, int volume) {
+ if (!isSystemAudioActivated()) {
+ return;
+ }
synchronized (mLock) {
mSystemAudioMute = mute;
mSystemAudioVolume = volume;
@@ -1019,6 +1021,10 @@ final class HdmiCecLocalDeviceTv extends HdmiCecLocalDevice {
@ServiceThreadOnly
void changeVolume(int curVolume, int delta, int maxVolume) {
assertRunOnServiceThread();
+ if (getAvrDeviceInfo() == null) {
+ // On initialization process, getAvrDeviceInfo() may return null and cause exception
+ return;
+ }
if (delta == 0 || !isSystemAudioActivated()) {
return;
}
@@ -1048,6 +1054,10 @@ final class HdmiCecLocalDeviceTv extends HdmiCecLocalDevice {
@ServiceThreadOnly
void changeMute(boolean mute) {
assertRunOnServiceThread();
+ if (getAvrDeviceInfo() == null) {
+ // On initialization process, getAvrDeviceInfo() may return null and cause exception
+ return;
+ }
HdmiLogger.debug("[A]:Change mute:%b", mute);
synchronized (mLock) {
if (mSystemAudioMute == mute) {
diff --git a/services/core/java/com/android/server/hdmi/HdmiControlService.java b/services/core/java/com/android/server/hdmi/HdmiControlService.java
index 807b1b19f870..3d079ccb0cad 100644
--- a/services/core/java/com/android/server/hdmi/HdmiControlService.java
+++ b/services/core/java/com/android/server/hdmi/HdmiControlService.java
@@ -989,8 +989,12 @@ public final class HdmiControlService extends SystemService {
}
// FLAG_HDMI_SYSTEM_AUDIO_VOLUME prevents audio manager from announcing
// volume change notification back to hdmi control service.
- audioManager.setStreamVolume(AudioManager.STREAM_MUSIC, volume,
- AudioManager.FLAG_SHOW_UI | AudioManager.FLAG_HDMI_SYSTEM_AUDIO_VOLUME);
+ int flag = AudioManager.FLAG_HDMI_SYSTEM_AUDIO_VOLUME;
+ if (0 <= volume && volume <= 100) {
+ Slog.i(TAG, "volume: " + volume);
+ flag |= AudioManager.FLAG_SHOW_UI;
+ audioManager.setStreamVolume(AudioManager.STREAM_MUSIC, volume, flag);
+ }
}
}
diff --git a/services/core/java/com/android/server/hdmi/HdmiUtils.java b/services/core/java/com/android/server/hdmi/HdmiUtils.java
index 8b1641187ac8..4ac3bba73e25 100644
--- a/services/core/java/com/android/server/hdmi/HdmiUtils.java
+++ b/services/core/java/com/android/server/hdmi/HdmiUtils.java
@@ -152,6 +152,32 @@ final class HdmiUtils {
}
/**
+ * Parse the <Report Audio Status> message and check if it is mute
+ *
+ * @param cmd the CEC message to parse
+ * @return true if the given parameter has [MUTE]
+ */
+ static boolean isAudioStatusMute(HdmiCecMessage cmd) {
+ byte params[] = cmd.getParams();
+ return (params[0] & 0x80) == 0x80;
+ }
+
+ /**
+ * Parse the <Report Audio Status> message and extract the volume
+ *
+ * @param cmd the CEC message to parse
+ * @return device's volume. Constants.UNKNOWN_VOLUME in case it is out of range
+ */
+ static int getAudioStatusVolume(HdmiCecMessage cmd) {
+ byte params[] = cmd.getParams();
+ int volume = params[0] & 0x7F;
+ if (volume < 0x00 || 0x64 < volume) {
+ volume = Constants.UNKNOWN_VOLUME;
+ }
+ return volume;
+ }
+
+ /**
* Convert integer array to list of {@link Integer}.
*
* <p>The result is immutable.
diff --git a/services/core/java/com/android/server/hdmi/SystemAudioStatusAction.java b/services/core/java/com/android/server/hdmi/SystemAudioStatusAction.java
index cab8439b6f92..d41a36ca031f 100644
--- a/services/core/java/com/android/server/hdmi/SystemAudioStatusAction.java
+++ b/services/core/java/com/android/server/hdmi/SystemAudioStatusAction.java
@@ -92,8 +92,8 @@ final class SystemAudioStatusAction extends HdmiCecFeatureAction {
private void handleReportAudioStatus(HdmiCecMessage cmd) {
byte[] params = cmd.getParams();
- boolean mute = (params[0] & 0x80) == 0x80;
- int volume = params[0] & 0x7F;
+ boolean mute = HdmiUtils.isAudioStatusMute(cmd);
+ int volume = HdmiUtils.getAudioStatusVolume(cmd);
tv().setAudioStatus(mute, volume);
if (!(tv().isSystemAudioActivated() ^ mute)) {
diff --git a/services/core/java/com/android/server/hdmi/VolumeControlAction.java b/services/core/java/com/android/server/hdmi/VolumeControlAction.java
index cd38b1fb2ac6..0011387f1c28 100644
--- a/services/core/java/com/android/server/hdmi/VolumeControlAction.java
+++ b/services/core/java/com/android/server/hdmi/VolumeControlAction.java
@@ -139,8 +139,8 @@ final class VolumeControlAction extends HdmiCecFeatureAction {
private boolean handleReportAudioStatus(HdmiCecMessage cmd) {
byte params[] = cmd.getParams();
- boolean mute = (params[0] & 0x80) == 0x80;
- int volume = params[0] & 0x7F;
+ boolean mute = HdmiUtils.isAudioStatusMute(cmd);
+ int volume = HdmiUtils.getAudioStatusVolume(cmd);
mLastAvrVolume = volume;
mLastAvrMute = mute;
if (shouldUpdateAudioVolume(mute)) {
diff --git a/services/core/java/com/android/server/job/controllers/ConnectivityController.java b/services/core/java/com/android/server/job/controllers/ConnectivityController.java
index 03fd7b3fffd9..373d87d971b8 100644
--- a/services/core/java/com/android/server/job/controllers/ConnectivityController.java
+++ b/services/core/java/com/android/server/job/controllers/ConnectivityController.java
@@ -16,6 +16,10 @@
package com.android.server.job.controllers;
+import static android.net.NetworkCapabilities.LINK_BANDWIDTH_UNSPECIFIED;
+import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_CONGESTED;
+import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_METERED;
+
import android.app.job.JobInfo;
import android.content.Context;
import android.net.ConnectivityManager;
@@ -35,6 +39,7 @@ import android.util.Slog;
import android.util.proto.ProtoOutputStream;
import com.android.internal.annotations.GuardedBy;
+import com.android.internal.annotations.VisibleForTesting;
import com.android.server.job.JobSchedulerService;
import com.android.server.job.JobServiceContext;
import com.android.server.job.StateChangedListener;
@@ -62,15 +67,15 @@ public final class ConnectivityController extends StateController implements
private final ArraySet<JobStatus> mTrackedJobs = new ArraySet<>();
/** Singleton. */
- private static ConnectivityController mSingleton;
+ private static ConnectivityController sSingleton;
private static Object sCreationLock = new Object();
public static ConnectivityController get(JobSchedulerService jms) {
synchronized (sCreationLock) {
- if (mSingleton == null) {
- mSingleton = new ConnectivityController(jms, jms.getContext(), jms.getLock());
+ if (sSingleton == null) {
+ sSingleton = new ConnectivityController(jms, jms.getContext(), jms.getLock());
}
- return mSingleton;
+ return sSingleton;
}
}
@@ -105,37 +110,29 @@ public final class ConnectivityController extends StateController implements
}
/**
- * Test to see if running the given job on the given network is sane.
+ * Test to see if running the given job on the given network is insane.
* <p>
* For example, if a job is trying to send 10MB over a 128Kbps EDGE
* connection, it would take 10.4 minutes, and has no chance of succeeding
* before the job times out, so we'd be insane to try running it.
*/
- private boolean isSane(JobStatus jobStatus, NetworkCapabilities capabilities) {
+ @SuppressWarnings("unused")
+ private static boolean isInsane(JobStatus jobStatus, Network network,
+ NetworkCapabilities capabilities) {
final long estimatedBytes = jobStatus.getEstimatedNetworkBytes();
if (estimatedBytes == JobInfo.NETWORK_BYTES_UNKNOWN) {
// We don't know how large the job is; cross our fingers!
- return true;
- }
- if (capabilities == null) {
- // We don't know what the network is like; cross our fingers!
- return true;
+ return false;
}
// We don't ask developers to differentiate between upstream/downstream
// in their size estimates, so test against the slowest link direction.
- final long downstream = capabilities.getLinkDownstreamBandwidthKbps();
- final long upstream = capabilities.getLinkUpstreamBandwidthKbps();
- final long slowest;
- if (downstream > 0 && upstream > 0) {
- slowest = Math.min(downstream, upstream);
- } else if (downstream > 0) {
- slowest = downstream;
- } else if (upstream > 0) {
- slowest = upstream;
- } else {
+ final long slowest = NetworkCapabilities.minBandwidth(
+ capabilities.getLinkDownstreamBandwidthKbps(),
+ capabilities.getLinkUpstreamBandwidthKbps());
+ if (slowest == LINK_BANDWIDTH_UNSPECIFIED) {
// We don't know what the network is like; cross our fingers!
- return true;
+ return false;
}
final long estimatedMillis = ((estimatedBytes * DateUtils.SECOND_IN_MILLIS)
@@ -144,28 +141,87 @@ public final class ConnectivityController extends StateController implements
// If we'd never finish before the timeout, we'd be insane!
Slog.w(TAG, "Estimated " + estimatedBytes + " bytes over " + slowest
+ " kbps network would take " + estimatedMillis + "ms; that's insane!");
+ return true;
+ } else {
return false;
+ }
+ }
+
+ @SuppressWarnings("unused")
+ private static boolean isCongestionDelayed(JobStatus jobStatus, Network network,
+ NetworkCapabilities capabilities) {
+ // If network is congested, and job is less than 50% through the
+ // developer-requested window, then we're okay delaying the job.
+ if (!capabilities.hasCapability(NET_CAPABILITY_NOT_CONGESTED)) {
+ return jobStatus.getFractionRunTime() < 0.5;
} else {
- return true;
+ return false;
}
}
+ @SuppressWarnings("unused")
+ private static boolean isStrictSatisfied(JobStatus jobStatus, Network network,
+ NetworkCapabilities capabilities) {
+ return jobStatus.getJob().getRequiredNetwork().networkCapabilities
+ .satisfiedByNetworkCapabilities(capabilities);
+ }
+
+ @SuppressWarnings("unused")
+ private static boolean isRelaxedSatisfied(JobStatus jobStatus, Network network,
+ NetworkCapabilities capabilities) {
+ // Only consider doing this for prefetching jobs
+ if ((jobStatus.getJob().getFlags() & JobInfo.FLAG_IS_PREFETCH) == 0) {
+ return false;
+ }
+
+ // See if we match after relaxing any unmetered request
+ final NetworkCapabilities relaxed = new NetworkCapabilities(
+ jobStatus.getJob().getRequiredNetwork().networkCapabilities)
+ .removeCapability(NET_CAPABILITY_NOT_METERED);
+ if (relaxed.satisfiedByNetworkCapabilities(capabilities)) {
+ // TODO: treat this as "maybe" response; need to check quotas
+ return jobStatus.getFractionRunTime() > 0.5;
+ } else {
+ return false;
+ }
+ }
+
+ @VisibleForTesting
+ static boolean isSatisfied(JobStatus jobStatus, Network network,
+ NetworkCapabilities capabilities) {
+ // Zeroth, we gotta have a network to think about being satisfied
+ if (network == null || capabilities == null) return false;
+
+ // First, are we insane?
+ if (isInsane(jobStatus, network, capabilities)) return false;
+
+ // Second, is the network congested?
+ if (isCongestionDelayed(jobStatus, network, capabilities)) return false;
+
+ // Third, is the network a strict match?
+ if (isStrictSatisfied(jobStatus, network, capabilities)) return true;
+
+ // Third, is the network a relaxed match?
+ if (isRelaxedSatisfied(jobStatus, network, capabilities)) return true;
+
+ return false;
+ }
+
private boolean updateConstraintsSatisfied(JobStatus jobStatus) {
// TODO: consider matching against non-active networks
final int jobUid = jobStatus.getSourceUid();
final boolean ignoreBlocked = (jobStatus.getFlags() & JobInfo.FLAG_WILL_BE_FOREGROUND) != 0;
+
final Network network = mConnManager.getActiveNetworkForUid(jobUid, ignoreBlocked);
final NetworkInfo info = mConnManager.getNetworkInfoForUid(network, jobUid, ignoreBlocked);
final NetworkCapabilities capabilities = mConnManager.getNetworkCapabilities(network);
final boolean connected = (info != null) && info.isConnected();
- final boolean satisfied = jobStatus.getJob().getRequiredNetwork().networkCapabilities
- .satisfiedByNetworkCapabilities(capabilities);
- final boolean sane = isSane(jobStatus, capabilities);
+ final boolean satisfied = isSatisfied(jobStatus, network, capabilities);
final boolean changed = jobStatus
- .setConnectivityConstraintSatisfied(connected && satisfied && sane);
+ .setConnectivityConstraintSatisfied(connected && satisfied);
// Pass along the evaluated network for job to use; prevents race
// conditions as default routes change over time, and opens the door to
@@ -181,8 +237,7 @@ public final class ConnectivityController extends StateController implements
if (DEBUG) {
Slog.i(TAG, "Connectivity " + (changed ? "CHANGED" : "unchanged")
+ " for " + jobStatus + ": connected=" + connected
- + " satisfied=" + satisfied
- + " sane=" + sane);
+ + " satisfied=" + satisfied);
}
return changed;
}
@@ -244,7 +299,7 @@ public final class ConnectivityController extends StateController implements
}
};
- private final INetworkPolicyListener mNetPolicyListener = new INetworkPolicyListener.Stub() {
+ private final INetworkPolicyListener mNetPolicyListener = new NetworkPolicyManager.Listener() {
@Override
public void onUidRulesChanged(int uid, int uidRules) {
if (DEBUG) {
@@ -254,11 +309,6 @@ public final class ConnectivityController extends StateController implements
}
@Override
- public void onMeteredIfacesChanged(String[] meteredIfaces) {
- // We track this via our NetworkCallback
- }
-
- @Override
public void onRestrictBackgroundChanged(boolean restrictBackground) {
if (DEBUG) {
Slog.v(TAG, "Background restriction change to " + restrictBackground);
diff --git a/services/core/java/com/android/server/job/controllers/JobStatus.java b/services/core/java/com/android/server/job/controllers/JobStatus.java
index 8f68713945ca..0f5cb0a38c83 100644
--- a/services/core/java/com/android/server/job/controllers/JobStatus.java
+++ b/services/core/java/com/android/server/job/controllers/JobStatus.java
@@ -24,6 +24,7 @@ import android.app.job.JobInfo;
import android.app.job.JobWorkItem;
import android.content.ClipData;
import android.content.ComponentName;
+import android.content.pm.PackageManagerInternal;
import android.net.Network;
import android.net.Uri;
import android.os.RemoteException;
@@ -96,6 +97,7 @@ public final class JobStatus {
final JobInfo job;
/** Uid of the package requesting this job. */
final int callingUid;
+ final int targetSdkVersion;
final String batteryName;
final String sourcePackageName;
@@ -243,12 +245,13 @@ public final class JobStatus {
return callingUid;
}
- private JobStatus(JobInfo job, int callingUid, String sourcePackageName,
+ private JobStatus(JobInfo job, int callingUid, int targetSdkVersion, String sourcePackageName,
int sourceUserId, int standbyBucket, long heartbeat, String tag, int numFailures,
long earliestRunTimeElapsedMillis, long latestRunTimeElapsedMillis,
long lastSuccessfulRunTime, long lastFailedRunTime) {
this.job = job;
this.callingUid = callingUid;
+ this.targetSdkVersion = targetSdkVersion;
this.standbyBucket = standbyBucket;
this.baseHeartbeat = heartbeat;
@@ -307,7 +310,7 @@ public final class JobStatus {
/** Copy constructor: used specifically when cloning JobStatus objects for persistence,
* so we preserve RTC window bounds if the source object has them. */
public JobStatus(JobStatus jobStatus) {
- this(jobStatus.getJob(), jobStatus.getUid(),
+ this(jobStatus.getJob(), jobStatus.getUid(), jobStatus.targetSdkVersion,
jobStatus.getSourcePackageName(), jobStatus.getSourceUserId(),
jobStatus.getStandbyBucket(), jobStatus.getBaseHeartbeat(),
jobStatus.getSourceTag(), jobStatus.getNumFailures(),
@@ -334,7 +337,7 @@ public final class JobStatus {
long earliestRunTimeElapsedMillis, long latestRunTimeElapsedMillis,
long lastSuccessfulRunTime, long lastFailedRunTime,
Pair<Long, Long> persistedExecutionTimesUTC) {
- this(job, callingUid, sourcePkgName, sourceUserId,
+ this(job, callingUid, resolveTargetSdkVersion(job), sourcePkgName, sourceUserId,
standbyBucket, baseHeartbeat,
sourceTag, 0,
earliestRunTimeElapsedMillis, latestRunTimeElapsedMillis,
@@ -357,7 +360,7 @@ public final class JobStatus {
long newEarliestRuntimeElapsedMillis,
long newLatestRuntimeElapsedMillis, int backoffAttempt,
long lastSuccessfulRunTime, long lastFailedRunTime) {
- this(rescheduling.job, rescheduling.getUid(),
+ this(rescheduling.job, rescheduling.getUid(), resolveTargetSdkVersion(rescheduling.job),
rescheduling.getSourcePackageName(), rescheduling.getSourceUserId(),
rescheduling.getStandbyBucket(), newBaseHeartbeat,
rescheduling.getSourceTag(), backoffAttempt, newEarliestRuntimeElapsedMillis,
@@ -392,7 +395,7 @@ public final class JobStatus {
sourceUserId, elapsedNow);
JobSchedulerInternal js = LocalServices.getService(JobSchedulerInternal.class);
long currentHeartbeat = js != null ? js.currentHeartbeat() : 0;
- return new JobStatus(job, callingUid, sourcePkg, sourceUserId,
+ return new JobStatus(job, callingUid, resolveTargetSdkVersion(job), sourcePkg, sourceUserId,
standbyBucket, currentHeartbeat, tag, 0,
earliestRunTimeElapsedMillis, latestRunTimeElapsedMillis,
0 /* lastSuccessfulRunTime */, 0 /* lastFailedRunTime */);
@@ -539,6 +542,10 @@ public final class JobStatus {
return job.getId();
}
+ public int getTargetSdkVersion() {
+ return targetSdkVersion;
+ }
+
public void printUniqueId(PrintWriter pw) {
UserHandle.formatUid(pw, callingUid);
pw.print("/");
@@ -713,6 +720,37 @@ public final class JobStatus {
return latestRunTimeElapsedMillis;
}
+ /**
+ * Return the fractional position of "now" within the "run time" window of
+ * this job.
+ * <p>
+ * For example, if the earliest run time was 10 minutes ago, and the latest
+ * run time is 30 minutes from now, this would return 0.25.
+ * <p>
+ * If the job has no window defined, returns 1. When only an earliest or
+ * latest time is defined, it's treated as an infinitely small window at
+ * that time.
+ */
+ public float getFractionRunTime() {
+ final long now = JobSchedulerService.sElapsedRealtimeClock.millis();
+ if (earliestRunTimeElapsedMillis == 0 && latestRunTimeElapsedMillis == Long.MAX_VALUE) {
+ return 1;
+ } else if (earliestRunTimeElapsedMillis == 0) {
+ return now >= latestRunTimeElapsedMillis ? 1 : 0;
+ } else if (latestRunTimeElapsedMillis == Long.MAX_VALUE) {
+ return now >= earliestRunTimeElapsedMillis ? 1 : 0;
+ } else {
+ if (now <= earliestRunTimeElapsedMillis) {
+ return 0;
+ } else if (now >= latestRunTimeElapsedMillis) {
+ return 1;
+ } else {
+ return (float) (now - earliestRunTimeElapsedMillis)
+ / (float) (latestRunTimeElapsedMillis - earliestRunTimeElapsedMillis);
+ }
+ }
+ }
+
public Pair<Long, Long> getPersistedUtcTimes() {
return mPersistedUtcTimes;
}
@@ -1091,6 +1129,11 @@ public final class JobStatus {
}
}
+ private static int resolveTargetSdkVersion(JobInfo job) {
+ return LocalServices.getService(PackageManagerInternal.class)
+ .getPackageTargetSdkVersion(job.getService().getPackageName());
+ }
+
// Dumpsys infrastructure
public void dump(PrintWriter pw, String prefix, boolean full, long elapsedRealtimeMillis) {
pw.print(prefix); UserHandle.formatUid(pw, callingUid);
diff --git a/services/core/java/com/android/server/location/GnssLocationProvider.java b/services/core/java/com/android/server/location/GnssLocationProvider.java
index 6dc5403acc99..48d275cc483f 100644
--- a/services/core/java/com/android/server/location/GnssLocationProvider.java
+++ b/services/core/java/com/android/server/location/GnssLocationProvider.java
@@ -827,7 +827,7 @@ public class GnssLocationProvider implements LocationProviderInterface {
return isEnabled();
}
};
- mGnssMetrics = new GnssMetrics();
+ mGnssMetrics = new GnssMetrics(mBatteryStats);
}
/**
diff --git a/services/core/java/com/android/server/locksettings/recoverablekeystore/KeySyncTask.java b/services/core/java/com/android/server/locksettings/recoverablekeystore/KeySyncTask.java
index a29e1be0fdca..724073a87a70 100644
--- a/services/core/java/com/android/server/locksettings/recoverablekeystore/KeySyncTask.java
+++ b/services/core/java/com/android/server/locksettings/recoverablekeystore/KeySyncTask.java
@@ -228,6 +228,10 @@ public class KeySyncTask implements Runnable {
counterId = generateAndStoreCounterId(recoveryAgentUid);
}
}
+
+ // TODO: make sure the same counter id is used during recovery and remove temporary fix.
+ counterId = 1L;
+
byte[] vaultParams = KeySyncUtils.packVaultParams(
publicKey,
counterId,
@@ -263,12 +267,16 @@ public class KeySyncTask implements Runnable {
// If application keys are not updated, snapshot will not be created on next unlock.
mRecoverableKeyStoreDb.setShouldCreateSnapshot(mUserId, recoveryAgentUid, false);
- // TODO: use Builder.
- mRecoverySnapshotStorage.put(recoveryAgentUid, new KeychainSnapshot(
- snapshotVersion,
- /*recoveryMetadata=*/ metadataList,
- /*applicationKeyBlobs=*/ createApplicationKeyEntries(encryptedApplicationKeys),
- /*encryptedRecoveryKeyblob=*/ encryptedRecoveryKey));
+ mRecoverySnapshotStorage.put(recoveryAgentUid, new KeychainSnapshot.Builder()
+ .setSnapshotVersion(snapshotVersion)
+ .setMaxAttempts(TRUSTED_HARDWARE_MAX_ATTEMPTS)
+ .setCounterId(counterId)
+ .setTrustedHardwarePublicKey(SecureBox.encodePublicKey(publicKey))
+ .setServerParams(vaultHandle)
+ .setKeychainProtectionParams(metadataList)
+ .setWrappedApplicationKeys(createApplicationKeyEntries(encryptedApplicationKeys))
+ .setEncryptedRecoveryKeyBlob(encryptedRecoveryKey)
+ .build());
mSnapshotListenersStorage.recoverySnapshotAvailable(recoveryAgentUid);
}
diff --git a/services/core/java/com/android/server/locksettings/recoverablekeystore/KeySyncUtils.java b/services/core/java/com/android/server/locksettings/recoverablekeystore/KeySyncUtils.java
index 219f6e10938e..89e2debec9d2 100644
--- a/services/core/java/com/android/server/locksettings/recoverablekeystore/KeySyncUtils.java
+++ b/services/core/java/com/android/server/locksettings/recoverablekeystore/KeySyncUtils.java
@@ -300,7 +300,7 @@ public class KeySyncUtils {
.put(SecureBox.encodePublicKey(thmPublicKey))
.putLong(counterId)
.putInt(maxAttempts)
- .put(new byte[VAULT_HANDLE_LENGTH_BYTES]) // TODO: replace with real vaultHandle
+ .put(vaultHandle)
.array();
}
diff --git a/services/core/java/com/android/server/net/NetworkIdentitySet.java b/services/core/java/com/android/server/net/NetworkIdentitySet.java
index ee00fdc33367..68cd5e7aed78 100644
--- a/services/core/java/com/android/server/net/NetworkIdentitySet.java
+++ b/services/core/java/com/android/server/net/NetworkIdentitySet.java
@@ -39,6 +39,7 @@ public class NetworkIdentitySet extends HashSet<NetworkIdentity> implements
private static final int VERSION_ADD_ROAMING = 2;
private static final int VERSION_ADD_NETWORK_ID = 3;
private static final int VERSION_ADD_METERED = 4;
+ private static final int VERSION_ADD_DEFAULT_NETWORK = 5;
public NetworkIdentitySet() {
}
@@ -76,12 +77,20 @@ public class NetworkIdentitySet extends HashSet<NetworkIdentity> implements
metered = (type == TYPE_MOBILE);
}
- add(new NetworkIdentity(type, subType, subscriberId, networkId, roaming, metered));
+ final boolean defaultNetwork;
+ if (version >= VERSION_ADD_DEFAULT_NETWORK) {
+ defaultNetwork = in.readBoolean();
+ } else {
+ defaultNetwork = true;
+ }
+
+ add(new NetworkIdentity(type, subType, subscriberId, networkId, roaming, metered,
+ defaultNetwork));
}
}
public void writeToStream(DataOutputStream out) throws IOException {
- out.writeInt(VERSION_ADD_METERED);
+ out.writeInt(VERSION_ADD_DEFAULT_NETWORK);
out.writeInt(size());
for (NetworkIdentity ident : this) {
out.writeInt(ident.getType());
@@ -90,6 +99,7 @@ public class NetworkIdentitySet extends HashSet<NetworkIdentity> implements
writeOptionalString(out, ident.getNetworkId());
out.writeBoolean(ident.getRoaming());
out.writeBoolean(ident.getMetered());
+ out.writeBoolean(ident.getDefaultNetwork());
}
}
@@ -119,6 +129,20 @@ public class NetworkIdentitySet extends HashSet<NetworkIdentity> implements
return false;
}
+ /** @return whether any {@link NetworkIdentity} in this set is considered on the default
+ network. */
+ public boolean areAllMembersOnDefaultNetwork() {
+ if (isEmpty()) {
+ return true;
+ }
+ for (NetworkIdentity ident : this) {
+ if (!ident.getDefaultNetwork()) {
+ return false;
+ }
+ }
+ return true;
+ }
+
private static void writeOptionalString(DataOutputStream out, String value) throws IOException {
if (value != null) {
out.writeByte(1);
diff --git a/services/core/java/com/android/server/net/NetworkPolicyManagerInternal.java b/services/core/java/com/android/server/net/NetworkPolicyManagerInternal.java
index 7934a9682426..971ac8b922ef 100644
--- a/services/core/java/com/android/server/net/NetworkPolicyManagerInternal.java
+++ b/services/core/java/com/android/server/net/NetworkPolicyManagerInternal.java
@@ -16,6 +16,9 @@
package com.android.server.net;
+import android.net.Network;
+import android.telephony.SubscriptionPlan;
+
/**
* Network Policy Manager local system service interface.
*
@@ -47,4 +50,25 @@ public abstract class NetworkPolicyManagerInternal {
* @param added Denotes whether the {@param appId} has been added or removed from the whitelist.
*/
public abstract void onTempPowerSaveWhitelistChange(int appId, boolean added);
+
+ /**
+ * Return the active {@link SubscriptionPlan} for the given network.
+ */
+ public abstract SubscriptionPlan getSubscriptionPlan(Network network);
+
+ public static final int QUOTA_TYPE_JOBS = 1;
+ public static final int QUOTA_TYPE_MULTIPATH = 2;
+
+ /**
+ * Return the daily quota (in bytes) that can be opportunistically used on
+ * the given network to improve the end user experience. It's called
+ * "opportunistic" because it's traffic that would typically not use the
+ * given network.
+ */
+ public abstract long getSubscriptionOpportunisticQuota(Network network, int quotaType);
+
+ /**
+ * Informs that admin data is loaded and available.
+ */
+ public abstract void onAdminDataAvailable();
}
diff --git a/services/core/java/com/android/server/net/NetworkPolicyManagerService.java b/services/core/java/com/android/server/net/NetworkPolicyManagerService.java
index ff9b2fd4ae2d..e406d51ac823 100644
--- a/services/core/java/com/android/server/net/NetworkPolicyManagerService.java
+++ b/services/core/java/com/android/server/net/NetworkPolicyManagerService.java
@@ -34,6 +34,7 @@ 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.NetworkCapabilities.TRANSPORT_CELLULAR;
import static android.net.NetworkPolicy.LIMIT_DISABLED;
import static android.net.NetworkPolicy.SNOOZE_NEVER;
import static android.net.NetworkPolicy.WARNING_DISABLED;
@@ -69,6 +70,7 @@ import static android.net.TrafficStats.MB_IN_BYTES;
import static android.telephony.CarrierConfigManager.ACTION_CARRIER_CONFIG_CHANGED;
import static android.telephony.CarrierConfigManager.DATA_CYCLE_THRESHOLD_DISABLED;
import static android.telephony.CarrierConfigManager.DATA_CYCLE_USE_PLATFORM_DEFAULT;
+import static android.telephony.SubscriptionManager.INVALID_SUBSCRIPTION_ID;
import static android.text.format.DateUtils.DAY_IN_MILLIS;
import static com.android.internal.util.ArrayUtils.appendInt;
@@ -97,6 +99,7 @@ import static org.xmlpull.v1.XmlPullParser.START_TAG;
import android.Manifest;
import android.annotation.IntDef;
+import android.annotation.NonNull;
import android.annotation.Nullable;
import android.app.ActivityManager;
import android.app.ActivityManagerInternal;
@@ -134,8 +137,10 @@ import android.net.NetworkPolicy;
import android.net.NetworkPolicyManager;
import android.net.NetworkQuotaInfo;
import android.net.NetworkRequest;
+import android.net.NetworkSpecifier;
import android.net.NetworkState;
import android.net.NetworkTemplate;
+import android.net.StringNetworkSpecifier;
import android.net.TrafficStats;
import android.net.wifi.WifiConfiguration;
import android.net.wifi.WifiManager;
@@ -174,6 +179,7 @@ import android.text.format.Formatter;
import android.util.ArrayMap;
import android.util.ArraySet;
import android.util.AtomicFile;
+import android.util.DataUnit;
import android.util.Log;
import android.util.NtpTrustedTime;
import android.util.Pair;
@@ -182,6 +188,7 @@ import android.util.Slog;
import android.util.SparseArray;
import android.util.SparseBooleanArray;
import android.util.SparseIntArray;
+import android.util.SparseLongArray;
import android.util.TrustedTime;
import android.util.Xml;
@@ -192,6 +199,7 @@ import com.android.internal.messages.nano.SystemMessageProto.SystemMessage;
import com.android.internal.notification.SystemNotificationChannels;
import com.android.internal.telephony.PhoneConstants;
import com.android.internal.util.ArrayUtils;
+import com.android.internal.util.ConcurrentUtils;
import com.android.internal.util.DumpUtils;
import com.android.internal.util.FastXmlSerializer;
import com.android.internal.util.IndentingPrintWriter;
@@ -200,8 +208,10 @@ import com.android.server.EventLogTags;
import com.android.server.LocalServices;
import com.android.server.ServiceThread;
import com.android.server.SystemConfig;
+import com.android.server.SystemService;
import libcore.io.IoUtils;
+import libcore.util.EmptyArray;
import org.xmlpull.v1.XmlPullParser;
import org.xmlpull.v1.XmlSerializer;
@@ -219,7 +229,6 @@ import java.nio.charset.StandardCharsets;
import java.time.ZoneId;
import java.time.ZonedDateTime;
import java.util.ArrayList;
-import java.util.Arrays;
import java.util.Calendar;
import java.util.List;
import java.util.Objects;
@@ -278,6 +287,8 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub {
public static final int TYPE_LIMIT = SystemMessage.NOTE_NET_LIMIT;
@VisibleForTesting
public static final int TYPE_LIMIT_SNOOZED = SystemMessage.NOTE_NET_LIMIT_SNOOZED;
+ @VisibleForTesting
+ public static final int TYPE_RAPID = SystemMessage.NOTE_NET_RAPID;
private static final String TAG_POLICY_LIST = "policy-list";
private static final String TAG_NETWORK_POLICY = "network-policy";
@@ -323,6 +334,11 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub {
private static final long TIME_CACHE_MAX_AGE = DAY_IN_MILLIS;
+ /**
+ * Indicates the maximum wait time for admin data to be available;
+ */
+ private static final long WAIT_FOR_ADMIN_DATA_TIMEOUT_MS = 10_000;
+
private static final int MSG_RULES_CHANGED = 1;
private static final int MSG_METERED_IFACES_CHANGED = 2;
private static final int MSG_LIMIT_REACHED = 5;
@@ -332,6 +348,7 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub {
private static final int MSG_REMOVE_INTERFACE_QUOTA = 11;
private static final int MSG_POLICIES_CHANGED = 13;
private static final int MSG_RESET_FIREWALL_RULES_BY_UID = 15;
+ private static final int MSG_SUBSCRIPTION_OVERRIDE = 16;
private static final int UID_MSG_STATE_CHANGED = 100;
private static final int UID_MSG_GONE = 101;
@@ -373,6 +390,8 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub {
private final boolean mSuppressDefaultPolicy;
+ private final CountDownLatch mAdminDataAvailableLatch = new CountDownLatch(1);
+
/** Defined network policies. */
@GuardedBy("mNetworkPoliciesSecondLock")
final ArrayMap<NetworkTemplate, NetworkPolicy> mNetworkPolicy = new ArrayMap<>();
@@ -384,6 +403,10 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub {
@GuardedBy("mNetworkPoliciesSecondLock")
final SparseArray<String> mSubscriptionPlansOwner = new SparseArray<>();
+ /** Map from subId to daily opportunistic quota. */
+ @GuardedBy("mNetworkPoliciesSecondLock")
+ final SparseLongArray mSubscriptionOpportunisticQuota = new SparseLongArray();
+
/** Defined UID policies. */
@GuardedBy("mUidRulesFirstLock") final SparseIntArray mUidPolicy = new SparseIntArray();
/** Currently derived rules for each UID. */
@@ -453,6 +476,10 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub {
@GuardedBy("mNetworkPoliciesSecondLock")
private final SparseBooleanArray mNetworkMetered = new SparseBooleanArray();
+ /** Map from netId to subId as of last update */
+ @GuardedBy("mNetworkPoliciesSecondLock")
+ private final SparseIntArray mNetIdToSubId = new SparseIntArray();
+
private final RemoteCallbackList<INetworkPolicyListener>
mListeners = new RemoteCallbackList<>();
@@ -653,6 +680,8 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub {
mSystemReady = true;
+ waitForAdminData();
+
// read policy from disk
readPolicyAL();
@@ -984,6 +1013,13 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub {
}
};
+ @VisibleForTesting
+ public void updateNotifications() {
+ synchronized (mNetworkPoliciesSecondLock) {
+ updateNotificationsNL();
+ }
+ }
+
/**
* Check {@link NetworkPolicy} against current {@link INetworkStatsService}
* to show visible notifications as needed.
@@ -1028,6 +1064,44 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub {
}
}
+ // Alert the user about heavy recent data usage that might result in
+ // going over their carrier limit.
+ for (int i = 0; i < mNetIdToSubId.size(); i++) {
+ final int subId = mNetIdToSubId.valueAt(i);
+ final SubscriptionPlan plan = getPrimarySubscriptionPlanLocked(subId);
+ if (plan == null) continue;
+
+ final long limitBytes = plan.getDataLimitBytes();
+ if (limitBytes == SubscriptionPlan.BYTES_UNKNOWN) {
+ // Ignore missing limits
+ } else if (limitBytes == SubscriptionPlan.BYTES_UNLIMITED) {
+ // Unlimited data; no rapid usage alerting
+ } else {
+ // Warn if average usage over last 4 days is on track to blow
+ // pretty far past the plan limits.
+ final long recentDuration = TimeUnit.DAYS.toMillis(4);
+ final long end = RecurrenceRule.sClock.millis();
+ final long start = end - recentDuration;
+
+ final NetworkTemplate template = NetworkTemplate.buildTemplateMobileAll(
+ mContext.getSystemService(TelephonyManager.class).getSubscriberId(subId));
+ final long recentBytes = getTotalBytes(template, start, end);
+
+ final Pair<ZonedDateTime, ZonedDateTime> cycle = plan.cycleIterator().next();
+ final long cycleDuration = cycle.second.toInstant().toEpochMilli()
+ - cycle.first.toInstant().toEpochMilli();
+
+ final long projectedBytes = (recentBytes * cycleDuration) / recentDuration;
+ final long alertBytes = (limitBytes * 3) / 2;
+ if (projectedBytes > alertBytes) {
+ final NetworkPolicy policy = new NetworkPolicy(template, plan.getCycleRule(),
+ NetworkPolicy.WARNING_DISABLED, NetworkPolicy.LIMIT_DISABLED,
+ NetworkPolicy.SNOOZE_NEVER, NetworkPolicy.SNOOZE_NEVER, true, true);
+ enqueueNotification(policy, TYPE_RAPID, 0);
+ }
+ }
+ }
+
// cancel stale notifications that we didn't renew above
for (int i = beforeNotifs.size()-1; i >= 0; i--) {
final NotificationId notificationId = beforeNotifs.valueAt(i);
@@ -1049,11 +1123,12 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub {
final SubscriptionManager sub = SubscriptionManager.from(mContext);
// Mobile template is relevant when any active subscriber matches
- final int[] subIds = sub.getActiveSubscriptionIdList();
+ final int[] subIds = ArrayUtils.defeatNullable(sub.getActiveSubscriptionIdList());
for (int subId : subIds) {
final String subscriberId = tele.getSubscriberId(subId);
final NetworkIdentity probeIdent = new NetworkIdentity(TYPE_MOBILE,
- TelephonyManager.NETWORK_TYPE_UNKNOWN, subscriberId, null, false, true);
+ TelephonyManager.NETWORK_TYPE_UNKNOWN, subscriberId, null, false, true,
+ true);
if (template.matches(probeIdent)) {
return true;
}
@@ -1186,6 +1261,21 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub {
mContext, 0, intent, PendingIntent.FLAG_UPDATE_CURRENT));
break;
}
+ case TYPE_RAPID: {
+ final CharSequence title = res.getText(R.string.data_usage_rapid_title);
+ body = res.getText(R.string.data_usage_rapid_body);
+
+ builder.setOngoing(true);
+ builder.setSmallIcon(R.drawable.stat_notify_error);
+ builder.setTicker(title);
+ builder.setContentTitle(title);
+ builder.setContentText(body);
+
+ final Intent intent = buildViewDataUsageIntent(res, policy.template);
+ builder.setContentIntent(PendingIntent.getActivity(
+ mContext, 0, intent, PendingIntent.FLAG_UPDATE_CURRENT));
+ break;
+ }
}
// TODO: move to NotificationManager once we can mock it
@@ -1239,6 +1329,11 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub {
}
};
+ @VisibleForTesting
+ public void updateNetworks() {
+ mConnReceiver.onReceive(null, null);
+ }
+
/**
* Update mobile policies with data cycle information from {@link CarrierConfigManager}
* if necessary.
@@ -1254,7 +1349,7 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub {
// find and update the mobile NetworkPolicy for this subscriber id
final NetworkIdentity probeIdent = new NetworkIdentity(TYPE_MOBILE,
- TelephonyManager.NETWORK_TYPE_UNKNOWN, subscriberId, null, false, true);
+ TelephonyManager.NETWORK_TYPE_UNKNOWN, subscriberId, null, false, true, true);
for (int i = mNetworkPolicy.size() - 1; i >= 0; i--) {
final NetworkTemplate template = mNetworkPolicy.keyAt(i);
if (template.matches(probeIdent)) {
@@ -1457,11 +1552,12 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub {
final SubscriptionManager sm = SubscriptionManager.from(mContext);
final TelephonyManager tm = TelephonyManager.from(mContext);
- final int[] subIds = sm.getActiveSubscriptionIdList();
+ final int[] subIds = ArrayUtils.defeatNullable(sm.getActiveSubscriptionIdList());
for (int subId : subIds) {
final String subscriberId = tm.getSubscriberId(subId);
final NetworkIdentity probeIdent = new NetworkIdentity(TYPE_MOBILE,
- TelephonyManager.NETWORK_TYPE_UNKNOWN, subscriberId, null, false, true);
+ TelephonyManager.NETWORK_TYPE_UNKNOWN, subscriberId, null, false, true,
+ true);
// Template is matched when subscriber id matches.
if (template.matches(probeIdent)) {
tm.setPolicyDataEnabled(enabled, subId);
@@ -1496,7 +1592,7 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub {
final NetworkState[] states;
try {
- states = mConnManager.getAllNetworkState();
+ states = defeatNullable(mConnManager.getAllNetworkState());
} catch (RemoteException e) {
// ignored; service lives in system_server
return;
@@ -1504,10 +1600,15 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub {
// First, generate identities of all connected networks so we can
// quickly compare them against all defined policies below.
+ mNetIdToSubId.clear();
final ArrayMap<NetworkState, NetworkIdentity> identified = new ArrayMap<>();
for (NetworkState state : states) {
+ if (state.network != null) {
+ mNetIdToSubId.put(state.network.netId, parseSubId(state));
+ }
if (state.networkInfo != null && state.networkInfo.isConnected()) {
- final NetworkIdentity ident = NetworkIdentity.buildNetworkIdentity(mContext, state);
+ final NetworkIdentity ident = NetworkIdentity.buildNetworkIdentity(mContext, state,
+ true);
identified.put(state, ident);
}
}
@@ -1607,6 +1708,42 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub {
}
mMeteredIfaces = newMeteredIfaces;
+ // Finally, calculate our opportunistic quotas
+ // TODO: add experiments support to disable or tweak ratios
+ mSubscriptionOpportunisticQuota.clear();
+ for (NetworkState state : states) {
+ if (state.network == null) continue;
+ final int subId = getSubIdLocked(state.network);
+ final SubscriptionPlan plan = getPrimarySubscriptionPlanLocked(subId);
+ if (plan == null) continue;
+
+ // By default assume we have no quota
+ long quotaBytes = 0;
+
+ final long limitBytes = plan.getDataLimitBytes();
+ if (limitBytes == SubscriptionPlan.BYTES_UNKNOWN) {
+ // Ignore missing limits
+ } else if (limitBytes == SubscriptionPlan.BYTES_UNLIMITED) {
+ // Unlimited data; let's use 20MiB/day (600MiB/month)
+ quotaBytes = DataUnit.MEBIBYTES.toBytes(20);
+ } else {
+ // Limited data; let's only use 10% of remaining budget
+ final Pair<ZonedDateTime, ZonedDateTime> cycle = plan.cycleIterator().next();
+ final long start = cycle.first.toInstant().toEpochMilli();
+ final long end = cycle.second.toInstant().toEpochMilli();
+ final long totalBytes = getTotalBytes(
+ NetworkTemplate.buildTemplateMobileAll(state.subscriberId), start, end);
+ final long remainingBytes = limitBytes - totalBytes;
+ final long remainingDays = Math.min(1, (end - RecurrenceRule.sClock.millis())
+ / TimeUnit.DAYS.toMillis(1));
+ if (remainingBytes > 0) {
+ quotaBytes = (remainingBytes / remainingDays) / 10;
+ }
+ }
+
+ mSubscriptionOpportunisticQuota.put(subId, quotaBytes);
+ }
+
final String[] meteredIfaces = mMeteredIfaces.toArray(new String[mMeteredIfaces.size()]);
mHandler.obtainMessage(MSG_METERED_IFACES_CHANGED, meteredIfaces).sendToTarget();
@@ -1624,7 +1761,7 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub {
final TelephonyManager tele = TelephonyManager.from(mContext);
final SubscriptionManager sub = SubscriptionManager.from(mContext);
- final int[] subIds = sub.getActiveSubscriptionIdList();
+ final int[] subIds = ArrayUtils.defeatNullable(sub.getActiveSubscriptionIdList());
for (int subId : subIds) {
final String subscriberId = tele.getSubscriberId(subId);
ensureActiveMobilePolicyAL(subId, subscriberId);
@@ -1642,7 +1779,7 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub {
private boolean ensureActiveMobilePolicyAL(int subId, String subscriberId) {
// Poke around to see if we already have a policy
final NetworkIdentity probeIdent = new NetworkIdentity(TYPE_MOBILE,
- TelephonyManager.NETWORK_TYPE_UNKNOWN, subscriberId, null, false, true);
+ TelephonyManager.NETWORK_TYPE_UNKNOWN, subscriberId, null, false, true, true);
for (int i = mNetworkPolicy.size() - 1; i >= 0; i--) {
final NetworkTemplate template = mNetworkPolicy.keyAt(i);
if (template.matches(probeIdent)) {
@@ -2815,6 +2952,27 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub {
}
@Override
+ public void setSubscriptionOverride(int subId, int overrideMask, int overrideValue,
+ long timeoutMillis, String callingPackage) {
+ enforceSubscriptionPlanAccess(subId, Binder.getCallingUid(), callingPackage);
+
+ // We can only override when carrier told us about plans
+ synchronized (mNetworkPoliciesSecondLock) {
+ if (ArrayUtils.isEmpty(mSubscriptionPlans.get(subId))) {
+ throw new IllegalStateException(
+ "Must provide SubscriptionPlan information before overriding");
+ }
+ }
+
+ mHandler.sendMessage(mHandler.obtainMessage(MSG_SUBSCRIPTION_OVERRIDE,
+ overrideMask, overrideValue, subId));
+ if (timeoutMillis > 0) {
+ mHandler.sendMessageDelayed(mHandler.obtainMessage(MSG_SUBSCRIPTION_OVERRIDE,
+ overrideMask, 0, subId), timeoutMillis);
+ }
+ }
+
+ @Override
protected void dump(FileDescriptor fd, PrintWriter writer, String[] args) {
if (!DumpUtils.checkDumpPermission(mContext, TAG, writer)) return;
@@ -3819,6 +3977,16 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub {
}
}
+ private void dispatchSubscriptionOverride(INetworkPolicyListener listener, int subId,
+ int overrideMask, int overrideValue) {
+ if (listener != null) {
+ try {
+ listener.onSubscriptionOverride(subId, overrideMask, overrideValue);
+ } catch (RemoteException ignored) {
+ }
+ }
+ }
+
private final Handler.Callback mHandlerCallback = new Handler.Callback() {
@Override
public boolean handleMessage(Message msg) {
@@ -3922,6 +4090,18 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub {
resetUidFirewallRules(msg.arg1);
return true;
}
+ case MSG_SUBSCRIPTION_OVERRIDE: {
+ final int overrideMask = msg.arg1;
+ final int overrideValue = msg.arg2;
+ final int subId = (int) msg.obj;
+ final int length = mListeners.beginBroadcast();
+ for (int i = 0; i < length; i++) {
+ final INetworkPolicyListener listener = mListeners.getBroadcastItem(i);
+ dispatchSubscriptionOverride(listener, subId, overrideMask, overrideValue);
+ }
+ mListeners.finishBroadcast();
+ return true;
+ }
default: {
return false;
}
@@ -4404,12 +4584,72 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub {
updateRulesForTempWhitelistChangeUL(appId);
}
}
+
+ @Override
+ public SubscriptionPlan getSubscriptionPlan(Network network) {
+ synchronized (mNetworkPoliciesSecondLock) {
+ final int subId = getSubIdLocked(network);
+ return getPrimarySubscriptionPlanLocked(subId);
+ }
+ }
+
+ @Override
+ public long getSubscriptionOpportunisticQuota(Network network, int quotaType) {
+ synchronized (mNetworkPoliciesSecondLock) {
+ // TODO: handle splitting quota between use-cases
+ return mSubscriptionOpportunisticQuota.get(getSubIdLocked(network));
+ }
+ }
+
+ @Override
+ public void onAdminDataAvailable() {
+ mAdminDataAvailableLatch.countDown();
+ }
+ }
+
+ private int parseSubId(NetworkState state) {
+ // TODO: moved to using a legitimate NetworkSpecifier instead of string parsing
+ int subId = INVALID_SUBSCRIPTION_ID;
+ if (state != null && state.networkCapabilities != null
+ && state.networkCapabilities.hasTransport(TRANSPORT_CELLULAR)) {
+ NetworkSpecifier spec = state.networkCapabilities.getNetworkSpecifier();
+ if (spec instanceof StringNetworkSpecifier) {
+ try {
+ subId = Integer.parseInt(((StringNetworkSpecifier) spec).specifier);
+ } catch (NumberFormatException e) {
+ }
+ }
+ }
+ return subId;
+ }
+
+ private int getSubIdLocked(Network network) {
+ return mNetIdToSubId.get(network.netId, INVALID_SUBSCRIPTION_ID);
+ }
+
+ private SubscriptionPlan getPrimarySubscriptionPlanLocked(int subId) {
+ final SubscriptionPlan[] plans = mSubscriptionPlans.get(subId);
+ return ArrayUtils.isEmpty(plans) ? null : plans[0];
+ }
+
+ /**
+ * This will only ever be called once - during device boot.
+ */
+ private void waitForAdminData() {
+ if (mContext.getPackageManager().hasSystemFeature(PackageManager.FEATURE_DEVICE_ADMIN)) {
+ ConcurrentUtils.waitForCountDownNoInterrupt(mAdminDataAvailableLatch,
+ WAIT_FOR_ADMIN_DATA_TIMEOUT_MS, "Wait for admin data");
+ }
}
private static boolean hasRule(int uidRules, int rule) {
return (uidRules & rule) != 0;
}
+ private static @NonNull NetworkState[] defeatNullable(@Nullable NetworkState[] val) {
+ return (val != null) ? val : new NetworkState[0];
+ }
+
private class NotificationId {
private final String mTag;
private final int mId;
diff --git a/services/core/java/com/android/server/net/NetworkStatsCollection.java b/services/core/java/com/android/server/net/NetworkStatsCollection.java
index 4ceb592af055..961a45177897 100644
--- a/services/core/java/com/android/server/net/NetworkStatsCollection.java
+++ b/services/core/java/com/android/server/net/NetworkStatsCollection.java
@@ -17,6 +17,8 @@
package com.android.server.net;
import static android.net.NetworkStats.IFACE_ALL;
+import static android.net.NetworkStats.DEFAULT_NETWORK_NO;
+import static android.net.NetworkStats.DEFAULT_NETWORK_YES;
import static android.net.NetworkStats.METERED_NO;
import static android.net.NetworkStats.METERED_YES;
import static android.net.NetworkStats.ROAMING_NO;
@@ -364,6 +366,8 @@ public class NetworkStatsCollection implements FileRotator.Reader {
entry.uid = key.uid;
entry.set = key.set;
entry.tag = key.tag;
+ entry.defaultNetwork = key.ident.areAllMembersOnDefaultNetwork() ?
+ DEFAULT_NETWORK_YES : DEFAULT_NETWORK_NO;
entry.metered = key.ident.isAnyMemberMetered() ? METERED_YES : METERED_NO;
entry.roaming = key.ident.isAnyMemberRoaming() ? ROAMING_YES : ROAMING_NO;
entry.rxBytes = historyEntry.rxBytes;
diff --git a/services/core/java/com/android/server/net/NetworkStatsService.java b/services/core/java/com/android/server/net/NetworkStatsService.java
index db61ef5cd9b9..78fd4b49237a 100644
--- a/services/core/java/com/android/server/net/NetworkStatsService.java
+++ b/services/core/java/com/android/server/net/NetworkStatsService.java
@@ -25,6 +25,7 @@ import static android.content.Intent.ACTION_USER_REMOVED;
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.DEFAULT_NETWORK_ALL;
import static android.net.NetworkStats.IFACE_ALL;
import static android.net.NetworkStats.METERED_ALL;
import static android.net.NetworkStats.ROAMING_ALL;
@@ -83,6 +84,7 @@ import android.net.INetworkManagementEventObserver;
import android.net.INetworkStatsService;
import android.net.INetworkStatsSession;
import android.net.LinkProperties;
+import android.net.Network;
import android.net.NetworkCapabilities;
import android.net.NetworkIdentity;
import android.net.NetworkInfo;
@@ -231,14 +233,24 @@ public class NetworkStatsService extends INetworkStatsService.Stub {
private final Object mStatsLock = new Object();
/** Set of currently active ifaces. */
+ @GuardedBy("mStatsLock")
private final ArrayMap<String, NetworkIdentitySet> mActiveIfaces = new ArrayMap<>();
+
/** Set of currently active ifaces for UID stats. */
+ @GuardedBy("mStatsLock")
private final ArrayMap<String, NetworkIdentitySet> mActiveUidIfaces = new ArrayMap<>();
+
/** Current default active iface. */
private String mActiveIface;
+
/** Set of any ifaces associated with mobile networks since boot. */
+ @GuardedBy("mStatsLock")
private String[] mMobileIfaces = new String[0];
+ /** Set of all ifaces currently used by traffic that does not explicitly specify a Network. */
+ @GuardedBy("mStatsLock")
+ private Network[] mDefaultNetworks = new Network[0];
+
private final DropBoxNonMonotonicObserver mNonMonotonicObserver =
new DropBoxNonMonotonicObserver();
@@ -666,9 +678,9 @@ public class NetworkStatsService extends INetworkStatsService.Stub {
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));
+ stats.addValues(new NetworkStats.Entry(IFACE_ALL, UID_ALL, SET_ALL, TAG_NONE,
+ METERED_ALL, ROAMING_ALL, DEFAULT_NETWORK_ALL, entry.rxBytes, entry.rxPackets,
+ entry.txBytes, entry.txPackets, entry.operations));
return stats;
}
@@ -779,13 +791,13 @@ public class NetworkStatsService extends INetworkStatsService.Stub {
}
@Override
- public void forceUpdateIfaces() {
+ public void forceUpdateIfaces(Network[] defaultNetworks) {
mContext.enforceCallingOrSelfPermission(READ_NETWORK_USAGE_HISTORY, TAG);
assertBandwidthControlEnabled();
final long token = Binder.clearCallingIdentity();
try {
- updateIfaces();
+ updateIfaces(defaultNetworks);
} finally {
Binder.restoreCallingIdentity(token);
}
@@ -996,11 +1008,11 @@ public class NetworkStatsService extends INetworkStatsService.Stub {
}
};
- private void updateIfaces() {
+ private void updateIfaces(Network[] defaultNetworks) {
synchronized (mStatsLock) {
mWakeLock.acquire();
try {
- updateIfacesLocked();
+ updateIfacesLocked(defaultNetworks);
} finally {
mWakeLock.release();
}
@@ -1013,7 +1025,7 @@ public class NetworkStatsService extends INetworkStatsService.Stub {
* are active on a single {@code iface}, they are combined under a single
* {@link NetworkIdentitySet}.
*/
- private void updateIfacesLocked() {
+ private void updateIfacesLocked(Network[] defaultNetworks) {
if (!mSystemReady) return;
if (LOGV) Slog.v(TAG, "updateIfacesLocked()");
@@ -1040,12 +1052,18 @@ public class NetworkStatsService extends INetworkStatsService.Stub {
// Rebuild active interfaces based on connected networks
mActiveIfaces.clear();
mActiveUidIfaces.clear();
+ if (defaultNetworks != null) {
+ // Caller is ConnectivityService. Update the list of default networks.
+ mDefaultNetworks = defaultNetworks;
+ }
final ArraySet<String> mobileIfaces = new ArraySet<>();
for (NetworkState state : states) {
if (state.networkInfo.isConnected()) {
final boolean isMobile = isNetworkTypeMobile(state.networkInfo.getType());
- final NetworkIdentity ident = NetworkIdentity.buildNetworkIdentity(mContext, state);
+ final boolean isDefault = ArrayUtils.contains(mDefaultNetworks, state.network);
+ final NetworkIdentity ident = NetworkIdentity.buildNetworkIdentity(mContext, state,
+ isDefault);
// Traffic occurring on the base interface is always counted for
// both total usage and UID details.
@@ -1065,7 +1083,8 @@ public class NetworkStatsService extends INetworkStatsService.Stub {
// Copy the identify from IMS one but mark it as metered.
NetworkIdentity vtIdent = new NetworkIdentity(ident.getType(),
ident.getSubType(), ident.getSubscriberId(), ident.getNetworkId(),
- ident.getRoaming(), true);
+ ident.getRoaming(), true /* metered */,
+ true /* onDefaultNetwork */);
findOrCreateNetworkIdentitySet(mActiveIfaces, VT_INTERFACE).add(vtIdent);
findOrCreateNetworkIdentitySet(mActiveUidIfaces, VT_INTERFACE).add(vtIdent);
}
@@ -1511,7 +1530,7 @@ public class NetworkStatsService extends INetworkStatsService.Stub {
return true;
}
case MSG_UPDATE_IFACES: {
- mService.updateIfaces();
+ mService.updateIfaces(null);
return true;
}
case MSG_REGISTER_GLOBAL_ALERT: {
diff --git a/services/core/java/com/android/server/net/watchlist/NetworkWatchlistService.java b/services/core/java/com/android/server/net/watchlist/NetworkWatchlistService.java
index 3bcc36f0ba2c..239ddbeb5f86 100644
--- a/services/core/java/com/android/server/net/watchlist/NetworkWatchlistService.java
+++ b/services/core/java/com/android/server/net/watchlist/NetworkWatchlistService.java
@@ -17,15 +17,11 @@
package com.android.server.net.watchlist;
import android.content.Context;
-import android.content.pm.PackageManager;
-import android.content.pm.PackageManager.NameNotFoundException;
import android.net.IIpConnectivityMetrics;
import android.net.INetdEventCallback;
-import android.net.NetworkWatchlistManager;
import android.net.metrics.IpConnectivityLog;
import android.os.Binder;
import android.os.Process;
-import android.os.SharedMemory;
import android.os.RemoteException;
import android.os.ServiceManager;
import android.os.SystemProperties;
@@ -42,9 +38,7 @@ import com.android.server.ServiceThread;
import com.android.server.SystemService;
import java.io.FileDescriptor;
-import java.io.IOException;
import java.io.PrintWriter;
-import java.util.List;
/**
* Implementation of network watchlist service.
@@ -99,7 +93,7 @@ public class NetworkWatchlistService extends INetworkWatchlistManager.Stub {
private volatile boolean mIsLoggingEnabled = false;
private final Object mLoggingSwitchLock = new Object();
- private final WatchlistSettings mSettings;
+ private final WatchlistConfig mConfig;
private final Context mContext;
// Separate thread to handle expensive watchlist logging work.
@@ -112,7 +106,7 @@ public class NetworkWatchlistService extends INetworkWatchlistManager.Stub {
public NetworkWatchlistService(Context context) {
mContext = context;
- mSettings = WatchlistSettings.getInstance();
+ mConfig = WatchlistConfig.getInstance();
mHandlerThread = new ServiceThread(TAG, Process.THREAD_PRIORITY_BACKGROUND,
/* allowIo */ false);
mHandlerThread.start();
@@ -126,7 +120,7 @@ public class NetworkWatchlistService extends INetworkWatchlistManager.Stub {
NetworkWatchlistService(Context context, ServiceThread handlerThread,
WatchlistLoggingHandler handler, IIpConnectivityMetrics ipConnectivityMetrics) {
mContext = context;
- mSettings = WatchlistSettings.getInstance();
+ mConfig = WatchlistConfig.getInstance();
mHandlerThread = handlerThread;
mNetworkWatchlistHandler = handler;
mIpConnectivityMetrics = ipConnectivityMetrics;
@@ -228,7 +222,7 @@ public class NetworkWatchlistService extends INetworkWatchlistManager.Stub {
public void reloadWatchlist() throws RemoteException {
enforceWatchlistLoggingPermission();
Slog.i(TAG, "Reloading watchlist");
- mSettings.reloadSettings();
+ mConfig.reloadConfig();
}
@Override
@@ -240,7 +234,7 @@ public class NetworkWatchlistService extends INetworkWatchlistManager.Stub {
@Override
protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
if (!DumpUtils.checkDumpPermission(mContext, TAG, pw)) return;
- mSettings.dump(fd, pw, args);
+ mConfig.dump(fd, pw, args);
}
}
diff --git a/services/core/java/com/android/server/net/watchlist/PrivacyUtils.java b/services/core/java/com/android/server/net/watchlist/PrivacyUtils.java
new file mode 100644
index 000000000000..c1231fa342e7
--- /dev/null
+++ b/services/core/java/com/android/server/net/watchlist/PrivacyUtils.java
@@ -0,0 +1,103 @@
+/*
+ * Copyright 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.net.watchlist;
+
+import android.privacy.DifferentialPrivacyEncoder;
+import android.privacy.internal.longitudinalreporting.LongitudinalReportingConfig;
+import android.privacy.internal.longitudinalreporting.LongitudinalReportingEncoder;
+
+import com.android.internal.annotations.VisibleForTesting;
+
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+/**
+ * Helper class to apply differential privacy to watchlist reports.
+ */
+class PrivacyUtils {
+
+ private static final String TAG = "PrivacyUtils";
+
+ /**
+ * Parameters used for encoding watchlist reports.
+ * These numbers are optimal parameters for protecting privacy with good utility.
+ *
+ * TODO: Add links to explain the math behind.
+ */
+ private static final String ENCODER_ID_PREFIX = "watchlist_encoder:";
+ private static final double PROB_F = 0.469;
+ private static final double PROB_P = 0.28;
+ private static final double PROB_Q = 1.0;
+
+ private PrivacyUtils() {
+ }
+
+ /**
+ * Get insecure DP encoder.
+ * Should not apply it directly on real data as seed is not randomized.
+ */
+ @VisibleForTesting
+ static DifferentialPrivacyEncoder createInsecureDPEncoderForTest(String appDigest) {
+ final LongitudinalReportingConfig config = createLongitudinalReportingConfig(appDigest);
+ return LongitudinalReportingEncoder.createInsecureEncoderForTest(config);
+ }
+
+ /**
+ * Get secure encoder to encode watchlist.
+ *
+ * Warning: If you use the same user secret and app digest, then you will get the same
+ * PRR result.
+ */
+ @VisibleForTesting
+ static DifferentialPrivacyEncoder createSecureDPEncoder(byte[] userSecret,
+ String appDigest) {
+ final LongitudinalReportingConfig config = createLongitudinalReportingConfig(appDigest);
+ return LongitudinalReportingEncoder.createEncoder(config, userSecret);
+ }
+
+ /**
+ * Get DP config for encoding watchlist reports.
+ */
+ private static LongitudinalReportingConfig createLongitudinalReportingConfig(String appDigest) {
+ return new LongitudinalReportingConfig(ENCODER_ID_PREFIX + appDigest, PROB_F, PROB_P,
+ PROB_Q);
+ }
+
+ /**
+ * Create a map that stores appDigest, encoded_visitedWatchlist pairs.
+ */
+ @VisibleForTesting
+ static Map<String, Boolean> createDpEncodedReportMap(boolean isSecure, byte[] userSecret,
+ List<String> appDigestList, WatchlistReportDbHelper.AggregatedResult aggregatedResult) {
+ final int appDigestListSize = appDigestList.size();
+ final HashMap<String, Boolean> resultMap = new HashMap<>(appDigestListSize);
+ for (int i = 0; i < appDigestListSize; i++) {
+ final String appDigest = appDigestList.get(i);
+ // Each app needs to have different PRR result, hence we use appDigest as encoder Id.
+ final DifferentialPrivacyEncoder encoder = isSecure
+ ? createSecureDPEncoder(userSecret, appDigest)
+ : createInsecureDPEncoderForTest(appDigest);
+ final boolean visitedWatchlist = aggregatedResult.appDigestList.contains(appDigest);
+ // Get the least significant bit of first byte, and set result to True if it is 1
+ boolean encodedVisitedWatchlist = ((int) encoder.encodeBoolean(visitedWatchlist)[0]
+ & 0x1) == 0x1;
+ resultMap.put(appDigest, encodedVisitedWatchlist);
+ }
+ return resultMap;
+ }
+}
diff --git a/services/core/java/com/android/server/net/watchlist/ReportEncoder.java b/services/core/java/com/android/server/net/watchlist/ReportEncoder.java
new file mode 100644
index 000000000000..5d7ff5a751aa
--- /dev/null
+++ b/services/core/java/com/android/server/net/watchlist/ReportEncoder.java
@@ -0,0 +1,126 @@
+/*
+ * Copyright 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.net.watchlist;
+
+import android.annotation.Nullable;
+import android.util.Log;
+
+import com.android.internal.annotations.VisibleForTesting;
+import com.android.internal.util.HexDump;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+import java.util.Map;
+
+/**
+ * Helper class to encode and generate serialized DP encoded watchlist report.
+ *
+ * <p>Serialized report data structure:
+ * [4 bytes magic number][4_bytes_report_version_code][32_bytes_watchlist_hash]
+ * [app_1_digest_byte_array][app_1_encoded_visited_cnc_byte]
+ * [app_2_digest_byte_array][app_2_encoded_visited_cnc_byte]
+ * ...
+ *
+ * Total size: 4 + 4 + 32 + (32+1)*N, where N = number of digests
+ */
+class ReportEncoder {
+
+ private static final String TAG = "ReportEncoder";
+
+ // Report header magic number
+ private static final byte[] MAGIC_NUMBER = {(byte) 0x8D, (byte) 0x37, (byte) 0x0A, (byte) 0xAC};
+ // Report version number, as file format / parameters can be changed in later version, we need
+ // to have versioning on watchlist report format
+ private static final byte[] REPORT_VERSION = {(byte) 0x00, (byte) 0x01};
+
+ private static final int WATCHLIST_HASH_SIZE = 32;
+ private static final int APP_DIGEST_SIZE = 32;
+
+ /**
+ * Apply DP on watchlist results, and generate a serialized watchlist report ready to store
+ * in DropBox.
+ */
+ static byte[] encodeWatchlistReport(WatchlistConfig config, byte[] userSecret,
+ List<String> appDigestList, WatchlistReportDbHelper.AggregatedResult aggregatedResult) {
+ Map<String, Boolean> resultMap = PrivacyUtils.createDpEncodedReportMap(
+ config.isConfigSecure(), userSecret, appDigestList, aggregatedResult);
+ return serializeReport(config, resultMap);
+ }
+
+ /**
+ * Convert DP encoded watchlist report into byte[] format.
+ * TODO: Serialize it using protobuf
+ *
+ * @param encodedReportMap DP encoded watchlist report.
+ * @return Watchlist report in byte[] format, which will be shared in Dropbox. Null if
+ * watchlist report cannot be generated.
+ */
+ @Nullable
+ @VisibleForTesting
+ static byte[] serializeReport(WatchlistConfig config,
+ Map<String, Boolean> encodedReportMap) {
+ // TODO: Handle watchlist config changed case
+ final byte[] watchlistHash = config.getWatchlistConfigHash();
+ if (watchlistHash == null) {
+ Log.e(TAG, "No watchlist hash");
+ return null;
+ }
+ if (watchlistHash.length != WATCHLIST_HASH_SIZE) {
+ Log.e(TAG, "Unexpected hash length");
+ return null;
+ }
+ final int reportMapSize = encodedReportMap.size();
+ final byte[] outputReport =
+ new byte[MAGIC_NUMBER.length + REPORT_VERSION.length + WATCHLIST_HASH_SIZE
+ + reportMapSize * (APP_DIGEST_SIZE + /* Result */ 1)];
+ final List<String> sortedKeys = new ArrayList(encodedReportMap.keySet());
+ Collections.sort(sortedKeys);
+
+ int offset = 0;
+
+ // Set magic number to report
+ System.arraycopy(MAGIC_NUMBER, 0, outputReport, offset, MAGIC_NUMBER.length);
+ offset += MAGIC_NUMBER.length;
+
+ // Set report version to report
+ System.arraycopy(REPORT_VERSION, 0, outputReport, offset, REPORT_VERSION.length);
+ offset += REPORT_VERSION.length;
+
+ // Set watchlist hash to report
+ System.arraycopy(watchlistHash, 0, outputReport, offset, watchlistHash.length);
+ offset += watchlistHash.length;
+
+ // Set app digest, encoded_isPha pair to report
+ for (int i = 0; i < reportMapSize; i++) {
+ String key = sortedKeys.get(i);
+ byte[] digest = HexDump.hexStringToByteArray(key);
+ boolean isPha = encodedReportMap.get(key);
+ System.arraycopy(digest, 0, outputReport, offset, APP_DIGEST_SIZE);
+ offset += digest.length;
+ outputReport[offset] = (byte) (isPha ? 1 : 0);
+ offset += 1;
+ }
+ if (outputReport.length != offset) {
+ Log.e(TAG, "Watchlist report size does not match! Offset: " + offset + ", report size: "
+ + outputReport.length);
+
+ }
+ return outputReport;
+ }
+}
diff --git a/services/core/java/com/android/server/net/watchlist/WatchlistConfig.java b/services/core/java/com/android/server/net/watchlist/WatchlistConfig.java
new file mode 100644
index 000000000000..fbf11fce08eb
--- /dev/null
+++ b/services/core/java/com/android/server/net/watchlist/WatchlistConfig.java
@@ -0,0 +1,245 @@
+/*
+ * 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.net.watchlist;
+
+import android.util.AtomicFile;
+import android.util.Log;
+import android.util.Slog;
+import android.util.Xml;
+
+import com.android.internal.annotations.VisibleForTesting;
+import com.android.internal.util.HexDump;
+import com.android.internal.util.XmlUtils;
+
+import org.xmlpull.v1.XmlPullParser;
+import org.xmlpull.v1.XmlPullParserException;
+
+import java.io.File;
+import java.io.FileDescriptor;
+import java.io.FileInputStream;
+import java.io.IOException;
+import java.io.PrintWriter;
+import java.nio.charset.StandardCharsets;
+import java.security.MessageDigest;
+import java.security.NoSuchAlgorithmException;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.zip.CRC32;
+
+/**
+ * Class for watchlist config operations, like setting watchlist, query if a domain
+ * exists in watchlist.
+ */
+class WatchlistConfig {
+ private static final String TAG = "WatchlistConfig";
+
+ // Watchlist config that pushed by ConfigUpdater.
+ private static final String NETWORK_WATCHLIST_DB_PATH =
+ "/data/misc/network_watchlist/network_watchlist.xml";
+
+ // Hash for null / unknown config, a 32 byte array filled with content 0x00
+ private static final byte[] UNKNOWN_CONFIG_HASH = new byte[32];
+
+ private static class XmlTags {
+ private static final String WATCHLIST_CONFIG = "watchlist-config";
+ private static final String SHA256_DOMAIN = "sha256-domain";
+ private static final String CRC32_DOMAIN = "crc32-domain";
+ private static final String SHA256_IP = "sha256-ip";
+ private static final String CRC32_IP = "crc32-ip";
+ private static final String HASH = "hash";
+ }
+
+ private static class CrcShaDigests {
+ final HarmfulDigests crc32Digests;
+ final HarmfulDigests sha256Digests;
+
+ public CrcShaDigests(HarmfulDigests crc32Digests, HarmfulDigests sha256Digests) {
+ this.crc32Digests = crc32Digests;
+ this.sha256Digests = sha256Digests;
+ }
+ }
+
+ /*
+ * This is always true unless watchlist is being set by adb command, then it will be false
+ * until next reboot.
+ */
+ private boolean mIsSecureConfig = true;
+
+ private final static WatchlistConfig sInstance = new WatchlistConfig();
+ private final File mXmlFile;
+
+ private volatile CrcShaDigests mDomainDigests;
+ private volatile CrcShaDigests mIpDigests;
+
+ public static WatchlistConfig getInstance() {
+ return sInstance;
+ }
+
+ private WatchlistConfig() {
+ this(new File(NETWORK_WATCHLIST_DB_PATH));
+ }
+
+ @VisibleForTesting
+ protected WatchlistConfig(File xmlFile) {
+ mXmlFile = xmlFile;
+ reloadConfig();
+ }
+
+ /**
+ * Reload watchlist by reading config file.
+ */
+ public void reloadConfig() {
+ try (FileInputStream stream = new FileInputStream(mXmlFile)){
+ final List<byte[]> crc32DomainList = new ArrayList<>();
+ final List<byte[]> sha256DomainList = new ArrayList<>();
+ final List<byte[]> crc32IpList = new ArrayList<>();
+ final List<byte[]> sha256IpList = new ArrayList<>();
+
+ XmlPullParser parser = Xml.newPullParser();
+ parser.setInput(stream, StandardCharsets.UTF_8.name());
+ parser.nextTag();
+ parser.require(XmlPullParser.START_TAG, null, XmlTags.WATCHLIST_CONFIG);
+ while (parser.nextTag() == XmlPullParser.START_TAG) {
+ String tagName = parser.getName();
+ switch (tagName) {
+ case XmlTags.CRC32_DOMAIN:
+ parseHashes(parser, tagName, crc32DomainList);
+ break;
+ case XmlTags.CRC32_IP:
+ parseHashes(parser, tagName, crc32IpList);
+ break;
+ case XmlTags.SHA256_DOMAIN:
+ parseHashes(parser, tagName, sha256DomainList);
+ break;
+ case XmlTags.SHA256_IP:
+ parseHashes(parser, tagName, sha256IpList);
+ break;
+ default:
+ Log.w(TAG, "Unknown element: " + parser.getName());
+ XmlUtils.skipCurrentTag(parser);
+ }
+ }
+ parser.require(XmlPullParser.END_TAG, null, XmlTags.WATCHLIST_CONFIG);
+ mDomainDigests = new CrcShaDigests(new HarmfulDigests(crc32DomainList),
+ new HarmfulDigests(sha256DomainList));
+ mIpDigests = new CrcShaDigests(new HarmfulDigests(crc32IpList),
+ new HarmfulDigests(sha256IpList));
+ Log.i(TAG, "Reload watchlist done");
+ } catch (IllegalStateException | NullPointerException | NumberFormatException |
+ XmlPullParserException | IOException | IndexOutOfBoundsException e) {
+ Slog.e(TAG, "Failed parsing xml", e);
+ }
+ }
+
+ private void parseHashes(XmlPullParser parser, String tagName, List<byte[]> hashList)
+ throws IOException, XmlPullParserException {
+ parser.require(XmlPullParser.START_TAG, null, tagName);
+ // Get all the hashes for this tag
+ while (parser.nextTag() == XmlPullParser.START_TAG) {
+ parser.require(XmlPullParser.START_TAG, null, XmlTags.HASH);
+ byte[] hash = HexDump.hexStringToByteArray(parser.nextText());
+ parser.require(XmlPullParser.END_TAG, null, XmlTags.HASH);
+ hashList.add(hash);
+ }
+ parser.require(XmlPullParser.END_TAG, null, tagName);
+ }
+
+ public boolean containsDomain(String domain) {
+ final CrcShaDigests domainDigests = mDomainDigests;
+ if (domainDigests == null) {
+ Slog.wtf(TAG, "domainDigests should not be null");
+ return false;
+ }
+ // First it does a quick CRC32 check.
+ final byte[] crc32 = getCrc32(domain);
+ if (!domainDigests.crc32Digests.contains(crc32)) {
+ return false;
+ }
+ // Now we do a slow SHA256 check.
+ final byte[] sha256 = getSha256(domain);
+ return domainDigests.sha256Digests.contains(sha256);
+ }
+
+ public boolean containsIp(String ip) {
+ final CrcShaDigests ipDigests = mIpDigests;
+ if (ipDigests == null) {
+ Slog.wtf(TAG, "ipDigests should not be null");
+ return false;
+ }
+ // First it does a quick CRC32 check.
+ final byte[] crc32 = getCrc32(ip);
+ if (!ipDigests.crc32Digests.contains(crc32)) {
+ return false;
+ }
+ // Now we do a slow SHA256 check.
+ final byte[] sha256 = getSha256(ip);
+ return ipDigests.sha256Digests.contains(sha256);
+ }
+
+
+ /** Get CRC32 of a string
+ *
+ * TODO: Review if we should use CRC32 or other algorithms
+ */
+ private byte[] getCrc32(String str) {
+ final CRC32 crc = new CRC32();
+ crc.update(str.getBytes());
+ final long tmp = crc.getValue();
+ return new byte[]{(byte) (tmp >> 24 & 255), (byte) (tmp >> 16 & 255),
+ (byte) (tmp >> 8 & 255), (byte) (tmp & 255)};
+ }
+
+ /** Get SHA256 of a string */
+ private byte[] getSha256(String str) {
+ MessageDigest messageDigest;
+ try {
+ messageDigest = MessageDigest.getInstance("SHA256");
+ } catch (NoSuchAlgorithmException e) {
+ /* can't happen */
+ return null;
+ }
+ messageDigest.update(str.getBytes());
+ return messageDigest.digest();
+ }
+
+ public boolean isConfigSecure() {
+ return mIsSecureConfig;
+ }
+
+ public byte[] getWatchlistConfigHash() {
+ if (!mXmlFile.exists()) {
+ return UNKNOWN_CONFIG_HASH;
+ }
+ try {
+ return DigestUtils.getSha256Hash(mXmlFile);
+ } catch (IOException | NoSuchAlgorithmException e) {
+ Log.e(TAG, "Unable to get watchlist config hash", e);
+ }
+ return UNKNOWN_CONFIG_HASH;
+ }
+
+ public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
+ pw.println("Domain CRC32 digest list:");
+ mDomainDigests.crc32Digests.dump(fd, pw, args);
+ pw.println("Domain SHA256 digest list:");
+ mDomainDigests.sha256Digests.dump(fd, pw, args);
+ pw.println("Ip CRC32 digest list:");
+ mIpDigests.crc32Digests.dump(fd, pw, args);
+ pw.println("Ip SHA256 digest list:");
+ mIpDigests.sha256Digests.dump(fd, pw, args);
+ }
+}
diff --git a/services/core/java/com/android/server/net/watchlist/WatchlistLoggingHandler.java b/services/core/java/com/android/server/net/watchlist/WatchlistLoggingHandler.java
index 2247558476c4..ee0049be8584 100644
--- a/services/core/java/com/android/server/net/watchlist/WatchlistLoggingHandler.java
+++ b/services/core/java/com/android/server/net/watchlist/WatchlistLoggingHandler.java
@@ -16,8 +16,10 @@
package com.android.server.net.watchlist;
+import android.annotation.Nullable;
import android.content.ContentResolver;
import android.content.Context;
+import android.content.pm.ApplicationInfo;
import android.content.pm.PackageManager;
import android.content.pm.PackageManager.NameNotFoundException;
import android.os.Bundle;
@@ -30,14 +32,19 @@ import android.provider.Settings;
import android.text.TextUtils;
import android.util.Slog;
+import com.android.internal.annotations.GuardedBy;
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.util.ArrayUtils;
+import com.android.internal.util.HexDump;
import java.io.File;
import java.io.IOException;
import java.security.NoSuchAlgorithmException;
import java.util.ArrayList;
import java.util.HashMap;
+import java.util.HashSet;
+import java.util.List;
+import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.TimeUnit;
/**
@@ -57,14 +64,17 @@ class WatchlistLoggingHandler extends Handler {
private static final String DROPBOX_TAG = "network_watchlist_report";
private final Context mContext;
+ private final @Nullable DropBoxManager mDropBoxManager;
private final ContentResolver mResolver;
private final PackageManager mPm;
private final WatchlistReportDbHelper mDbHelper;
+ private final WatchlistConfig mConfig;
private final WatchlistSettings mSettings;
// A cache for uid and apk digest mapping.
// As uid won't be reused until reboot, it's safe to assume uid is unique per signature and app.
// TODO: Use more efficient data structure.
- private final HashMap<Integer, byte[]> mCachedUidDigestMap = new HashMap<>();
+ private final ConcurrentHashMap<Integer, byte[]> mCachedUidDigestMap =
+ new ConcurrentHashMap<>();
private interface WatchlistEventKeys {
String HOST = "host";
@@ -79,7 +89,9 @@ class WatchlistLoggingHandler extends Handler {
mPm = mContext.getPackageManager();
mResolver = mContext.getContentResolver();
mDbHelper = WatchlistReportDbHelper.getInstance(context);
+ mConfig = WatchlistConfig.getInstance();
mSettings = WatchlistSettings.getInstance();
+ mDropBoxManager = mContext.getSystemService(DropBoxManager.class);
}
@Override
@@ -162,69 +174,88 @@ class WatchlistLoggingHandler extends Handler {
}
private void tryAggregateRecords() {
- if (shouldReportNetworkWatchlist()) {
- Slog.i(TAG, "Start aggregating watchlist records.");
- final DropBoxManager dbox = mContext.getSystemService(DropBoxManager.class);
- if (dbox != null && !dbox.isTagEnabled(DROPBOX_TAG)) {
- final WatchlistReportDbHelper.AggregatedResult aggregatedResult =
- mDbHelper.getAggregatedRecords();
- final byte[] encodedResult = encodeAggregatedResult(aggregatedResult);
- if (encodedResult != null) {
- addEncodedReportToDropBox(encodedResult);
- }
- }
- mDbHelper.cleanup();
- Settings.Global.putLong(mResolver, Settings.Global.NETWORK_WATCHLIST_LAST_REPORT_TIME,
- System.currentTimeMillis());
- } else {
+ // Check if it's necessary to generate watchlist report now.
+ if (!shouldReportNetworkWatchlist()) {
Slog.i(TAG, "No need to aggregate record yet.");
+ return;
}
+ Slog.i(TAG, "Start aggregating watchlist records.");
+ if (mDropBoxManager != null && mDropBoxManager.isTagEnabled(DROPBOX_TAG)) {
+ Settings.Global.putLong(mResolver,
+ Settings.Global.NETWORK_WATCHLIST_LAST_REPORT_TIME,
+ System.currentTimeMillis());
+ final WatchlistReportDbHelper.AggregatedResult aggregatedResult =
+ mDbHelper.getAggregatedRecords();
+ // Get all digests for watchlist report, it should include all installed
+ // application digests and previously recorded app digests.
+ final List<String> digestsForReport = getAllDigestsForReport(aggregatedResult);
+ final byte[] secretKey = mSettings.getPrivacySecretKey();
+ final byte[] encodedResult = ReportEncoder.encodeWatchlistReport(mConfig,
+ secretKey, digestsForReport, aggregatedResult);
+ if (encodedResult != null) {
+ addEncodedReportToDropBox(encodedResult);
+ }
+ }
+ mDbHelper.cleanup();
}
- private byte[] encodeAggregatedResult(
- WatchlistReportDbHelper.AggregatedResult aggregatedResult) {
- // TODO: Encode results using differential privacy.
- return null;
+ /**
+ * Get all digests for watchlist report.
+ * It should include:
+ * (1) All installed app digests. We need this because we need to ensure after DP we don't know
+ * if an app is really visited C&C site.
+ * (2) App digests that previously recorded in database.
+ */
+ private List<String> getAllDigestsForReport(WatchlistReportDbHelper.AggregatedResult record) {
+ // Step 1: Get all installed application digests.
+ final List<ApplicationInfo> apps = mContext.getPackageManager().getInstalledApplications(
+ PackageManager.MATCH_ANY_USER | PackageManager.MATCH_ALL);
+ final HashSet<String> result = new HashSet<>(apps.size() + record.appDigestCNCList.size());
+ final int size = apps.size();
+ for (int i = 0; i < size; i++) {
+ byte[] digest = getDigestFromUid(apps.get(i).uid);
+ result.add(HexDump.toHexString(digest));
+ }
+ // Step 2: Add all digests from records
+ result.addAll(record.appDigestCNCList.keySet());
+ return new ArrayList<>(result);
}
private void addEncodedReportToDropBox(byte[] encodedReport) {
- final DropBoxManager dbox = mContext.getSystemService(DropBoxManager.class);
- dbox.addData(DROPBOX_TAG, encodedReport, 0);
+ mDropBoxManager.addData(DROPBOX_TAG, encodedReport, 0);
}
/**
* Get app digest from app uid.
+ * Return null if system cannot get digest from uid.
*/
+ @Nullable
private byte[] getDigestFromUid(int uid) {
- final byte[] cachedDigest = mCachedUidDigestMap.get(uid);
- if (cachedDigest != null) {
- return cachedDigest;
- }
- final String[] packageNames = mPm.getPackagesForUid(uid);
- final int userId = UserHandle.getUserId(uid);
- if (!ArrayUtils.isEmpty(packageNames)) {
- for (String packageName : packageNames) {
- try {
- final String apkPath = mPm.getPackageInfoAsUser(packageName,
- PackageManager.MATCH_DIRECT_BOOT_AWARE
- | PackageManager.MATCH_DIRECT_BOOT_UNAWARE, userId)
- .applicationInfo.publicSourceDir;
- if (TextUtils.isEmpty(apkPath)) {
- Slog.w(TAG, "Cannot find apkPath for " + packageName);
- continue;
+ return mCachedUidDigestMap.computeIfAbsent(uid, key -> {
+ final String[] packageNames = mPm.getPackagesForUid(key);
+ final int userId = UserHandle.getUserId(uid);
+ if (!ArrayUtils.isEmpty(packageNames)) {
+ for (String packageName : packageNames) {
+ try {
+ final String apkPath = mPm.getPackageInfoAsUser(packageName,
+ PackageManager.MATCH_DIRECT_BOOT_AWARE
+ | PackageManager.MATCH_DIRECT_BOOT_UNAWARE, userId)
+ .applicationInfo.publicSourceDir;
+ if (TextUtils.isEmpty(apkPath)) {
+ Slog.w(TAG, "Cannot find apkPath for " + packageName);
+ continue;
+ }
+ return DigestUtils.getSha256Hash(new File(apkPath));
+ } catch (NameNotFoundException | NoSuchAlgorithmException | IOException e) {
+ Slog.e(TAG, "Should not happen", e);
+ return null;
}
- final byte[] digest = DigestUtils.getSha256Hash(new File(apkPath));
- mCachedUidDigestMap.put(uid, digest);
- return digest;
- } catch (NameNotFoundException | NoSuchAlgorithmException | IOException e) {
- Slog.e(TAG, "Should not happen", e);
- return null;
}
+ } else {
+ Slog.e(TAG, "Should not happen");
}
- } else {
- Slog.e(TAG, "Should not happen");
- }
- return null;
+ return null;
+ });
}
/**
@@ -247,7 +278,7 @@ class WatchlistLoggingHandler extends Handler {
if (ipAddr == null) {
return false;
}
- return mSettings.containsIp(ipAddr);
+ return mConfig.containsIp(ipAddr);
}
/** Search if the host is in watchlist */
@@ -255,7 +286,7 @@ class WatchlistLoggingHandler extends Handler {
if (host == null) {
return false;
}
- return mSettings.containsDomain(host);
+ return mConfig.containsDomain(host);
}
/**
diff --git a/services/core/java/com/android/server/net/watchlist/WatchlistReportDbHelper.java b/services/core/java/com/android/server/net/watchlist/WatchlistReportDbHelper.java
index 838aa53938fa..9559685c8870 100644
--- a/services/core/java/com/android/server/net/watchlist/WatchlistReportDbHelper.java
+++ b/services/core/java/com/android/server/net/watchlist/WatchlistReportDbHelper.java
@@ -76,13 +76,20 @@ class WatchlistReportDbHelper extends SQLiteOpenHelper {
*/
public static class AggregatedResult {
// A list of digests that visited c&c domain or ip before.
- Set<String> appDigestList;
+ final Set<String> appDigestList;
// The c&c domain or ip visited before.
- String cncDomainVisited;
+ final String cncDomainVisited;
// A list of app digests and c&c domain visited.
- HashMap<String, String> appDigestCNCList;
+ final HashMap<String, String> appDigestCNCList;
+
+ public AggregatedResult(Set<String> appDigestList, String cncDomainVisited,
+ HashMap<String, String> appDigestCNCList) {
+ this.appDigestList = appDigestList;
+ this.cncDomainVisited = cncDomainVisited;
+ this.appDigestCNCList = appDigestCNCList;
+ }
}
static File getSystemWatchlistDbFile() {
@@ -151,23 +158,21 @@ class WatchlistReportDbHelper extends SQLiteOpenHelper {
if (c == null || c.getCount() == 0) {
return null;
}
- final AggregatedResult result = new AggregatedResult();
- result.cncDomainVisited = null;
- // After aggregation, each digest maximum will have only 1 record.
- result.appDigestList = new HashSet<>();
- result.appDigestCNCList = new HashMap<>();
+ final HashSet<String> appDigestList = new HashSet<>();
+ final HashMap<String, String> appDigestCNCList = new HashMap<>();
+ String cncDomainVisited = null;
while (c.moveToNext()) {
// We use hex string here as byte[] cannot be a key in HashMap.
String digestHexStr = HexDump.toHexString(c.getBlob(INDEX_DIGEST));
String cncDomain = c.getString(INDEX_CNC_DOMAIN);
- result.appDigestList.add(digestHexStr);
- if (result.cncDomainVisited != null) {
- result.cncDomainVisited = cncDomain;
+ appDigestList.add(digestHexStr);
+ if (cncDomainVisited != null) {
+ cncDomainVisited = cncDomain;
}
- result.appDigestCNCList.put(digestHexStr, cncDomain);
+ appDigestCNCList.put(digestHexStr, cncDomain);
}
- return result;
+ return new AggregatedResult(appDigestList, cncDomainVisited, appDigestCNCList);
} finally {
if (c != null) {
c.close();
diff --git a/services/core/java/com/android/server/net/watchlist/WatchlistSettings.java b/services/core/java/com/android/server/net/watchlist/WatchlistSettings.java
index 70002ea21aff..b78fe4d2cca7 100644
--- a/services/core/java/com/android/server/net/watchlist/WatchlistSettings.java
+++ b/services/core/java/com/android/server/net/watchlist/WatchlistSettings.java
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2017 The Android Open Source Project
+ * Copyright 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.
@@ -22,7 +22,6 @@ import android.util.Log;
import android.util.Slog;
import android.util.Xml;
-import com.android.internal.annotations.GuardedBy;
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.util.FastXmlSerializer;
import com.android.internal.util.HexDump;
@@ -35,199 +34,126 @@ import org.xmlpull.v1.XmlSerializer;
import java.io.File;
import java.io.FileDescriptor;
import java.io.FileInputStream;
-import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.PrintWriter;
import java.nio.charset.StandardCharsets;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
+import java.security.SecureRandom;
import java.util.ArrayList;
import java.util.List;
import java.util.zip.CRC32;
/**
- * A util class to do watchlist settings operations, like setting watchlist, query if a domain
- * exists in watchlist.
+ * Class for handling watchlist settings operations, like getting differential privacy secret key.
+ * Unlike WatchlistConfig, which will read configs that pushed from ConfigUpdater only, this class
+ * can read and write all settings for watchlist operations.
*/
class WatchlistSettings {
- private static final String TAG = "WatchlistSettings";
- // Watchlist config that pushed by ConfigUpdater.
- private static final String NETWORK_WATCHLIST_DB_PATH =
- "/data/misc/network_watchlist/network_watchlist.xml";
-
- private static class XmlTags {
- private static final String WATCHLIST_SETTINGS = "watchlist-settings";
- private static final String SHA256_DOMAIN = "sha256-domain";
- private static final String CRC32_DOMAIN = "crc32-domain";
- private static final String SHA256_IP = "sha256-ip";
- private static final String CRC32_IP = "crc32-ip";
- private static final String HASH = "hash";
- }
+ private static final String TAG = "WatchlistSettings";
- private static class CrcShaDigests {
- final HarmfulDigests crc32Digests;
- final HarmfulDigests sha256Digests;
-
- public CrcShaDigests(HarmfulDigests crc32Digests, HarmfulDigests sha256Digests) {
- this.crc32Digests = crc32Digests;
- this.sha256Digests = sha256Digests;
- }
- }
+ private static final String FILE_NAME = "watchlist_settings.xml";
+ // Rappor requires min entropy input size = 48 bytes
+ private static final int SECRET_KEY_LENGTH = 48;
private final static WatchlistSettings sInstance = new WatchlistSettings();
private final AtomicFile mXmlFile;
- private volatile CrcShaDigests mDomainDigests;
- private volatile CrcShaDigests mIpDigests;
+ private byte[] mPrivacySecretKey = null;
public static WatchlistSettings getInstance() {
return sInstance;
}
private WatchlistSettings() {
- this(new File(NETWORK_WATCHLIST_DB_PATH));
+ this(getSystemWatchlistFile());
+ }
+
+ static File getSystemWatchlistFile() {
+ return new File(Environment.getDataSystemDirectory(), FILE_NAME);
}
@VisibleForTesting
protected WatchlistSettings(File xmlFile) {
mXmlFile = new AtomicFile(xmlFile);
reloadSettings();
+ if (mPrivacySecretKey == null) {
+ // Generate a new secret key and save settings
+ mPrivacySecretKey = generatePrivacySecretKey();
+ saveSettings();
+ }
}
public void reloadSettings() {
try (FileInputStream stream = mXmlFile.openRead()){
-
- final List<byte[]> crc32DomainList = new ArrayList<>();
- final List<byte[]> sha256DomainList = new ArrayList<>();
- final List<byte[]> crc32IpList = new ArrayList<>();
- final List<byte[]> sha256IpList = new ArrayList<>();
-
XmlPullParser parser = Xml.newPullParser();
parser.setInput(stream, StandardCharsets.UTF_8.name());
- parser.nextTag();
- parser.require(XmlPullParser.START_TAG, null, XmlTags.WATCHLIST_SETTINGS);
- while (parser.nextTag() == XmlPullParser.START_TAG) {
- String tagName = parser.getName();
- switch (tagName) {
- case XmlTags.CRC32_DOMAIN:
- parseHash(parser, tagName, crc32DomainList);
- break;
- case XmlTags.CRC32_IP:
- parseHash(parser, tagName, crc32IpList);
- break;
- case XmlTags.SHA256_DOMAIN:
- parseHash(parser, tagName, sha256DomainList);
- break;
- case XmlTags.SHA256_IP:
- parseHash(parser, tagName, sha256IpList);
- break;
- default:
- Log.w(TAG, "Unknown element: " + parser.getName());
- XmlUtils.skipCurrentTag(parser);
+ XmlUtils.beginDocument(parser, "network-watchlist-settings");
+ final int outerDepth = parser.getDepth();
+ while (XmlUtils.nextElementWithin(parser, outerDepth)) {
+ if (parser.getName().equals("secret-key")) {
+ mPrivacySecretKey = parseSecretKey(parser);
}
}
- parser.require(XmlPullParser.END_TAG, null, XmlTags.WATCHLIST_SETTINGS);
- writeSettingsToMemory(crc32DomainList, sha256DomainList, crc32IpList, sha256IpList);
- Log.i(TAG, "Reload watchlist done");
+ Log.i(TAG, "Reload watchlist settings done");
} catch (IllegalStateException | NullPointerException | NumberFormatException |
XmlPullParserException | IOException | IndexOutOfBoundsException e) {
Slog.e(TAG, "Failed parsing xml", e);
}
}
- private void parseHash(XmlPullParser parser, String tagName, List<byte[]> hashSet)
+ private byte[] parseSecretKey(XmlPullParser parser)
throws IOException, XmlPullParserException {
- parser.require(XmlPullParser.START_TAG, null, tagName);
- while (parser.nextTag() == XmlPullParser.START_TAG) {
- parser.require(XmlPullParser.START_TAG, null, XmlTags.HASH);
- byte[] hash = HexDump.hexStringToByteArray(parser.nextText());
- parser.require(XmlPullParser.END_TAG, null, XmlTags.HASH);
- hashSet.add(hash);
+ parser.require(XmlPullParser.START_TAG, null, "secret-key");
+ byte[] key = HexDump.hexStringToByteArray(parser.nextText());
+ parser.require(XmlPullParser.END_TAG, null, "secret-key");
+ if (key == null || key.length != SECRET_KEY_LENGTH) {
+ Log.e(TAG, "Unable to parse secret key");
+ return null;
}
- parser.require(XmlPullParser.END_TAG, null, tagName);
+ return key;
}
/**
- * Write network watchlist settings to memory.
+ * Get DP secret key.
+ * Make sure it is not exported or logged in anywhere.
*/
- public void writeSettingsToMemory(List<byte[]> newCrc32DomainList,
- List<byte[]> newSha256DomainList,
- List<byte[]> newCrc32IpList,
- List<byte[]> newSha256IpList) {
- mDomainDigests = new CrcShaDigests(new HarmfulDigests(newCrc32DomainList),
- new HarmfulDigests(newSha256DomainList));
- mIpDigests = new CrcShaDigests(new HarmfulDigests(newCrc32IpList),
- new HarmfulDigests(newSha256IpList));
+ synchronized byte[] getPrivacySecretKey() {
+ final byte[] key = new byte[SECRET_KEY_LENGTH];
+ System.arraycopy(mPrivacySecretKey, 0, key, 0, SECRET_KEY_LENGTH);
+ return key;
}
- public boolean containsDomain(String domain) {
- final CrcShaDigests domainDigests = mDomainDigests;
- if (domainDigests == null) {
- Slog.wtf(TAG, "domainDigests should not be null");
- return false;
- }
- // First it does a quick CRC32 check.
- final byte[] crc32 = getCrc32(domain);
- if (!domainDigests.crc32Digests.contains(crc32)) {
- return false;
- }
- // Now we do a slow SHA256 check.
- final byte[] sha256 = getSha256(domain);
- return domainDigests.sha256Digests.contains(sha256);
+ private byte[] generatePrivacySecretKey() {
+ final byte[] key = new byte[SECRET_KEY_LENGTH];
+ (new SecureRandom()).nextBytes(key);
+ return key;
}
- public boolean containsIp(String ip) {
- final CrcShaDigests ipDigests = mIpDigests;
- if (ipDigests == null) {
- Slog.wtf(TAG, "ipDigests should not be null");
- return false;
- }
- // First it does a quick CRC32 check.
- final byte[] crc32 = getCrc32(ip);
- if (!ipDigests.crc32Digests.contains(crc32)) {
- return false;
+ private void saveSettings() {
+ FileOutputStream stream;
+ try {
+ stream = mXmlFile.startWrite();
+ } catch (IOException e) {
+ Log.w(TAG, "Failed to write display settings: " + e);
+ return;
}
- // Now we do a slow SHA256 check.
- final byte[] sha256 = getSha256(ip);
- return ipDigests.sha256Digests.contains(sha256);
- }
-
-
- /** Get CRC32 of a string
- *
- * TODO: Review if we should use CRC32 or other algorithms
- */
- private byte[] getCrc32(String str) {
- final CRC32 crc = new CRC32();
- crc.update(str.getBytes());
- final long tmp = crc.getValue();
- return new byte[]{(byte) (tmp >> 24 & 255), (byte) (tmp >> 16 & 255),
- (byte) (tmp >> 8 & 255), (byte) (tmp & 255)};
- }
-
- /** Get SHA256 of a string */
- private byte[] getSha256(String str) {
- MessageDigest messageDigest;
try {
- messageDigest = MessageDigest.getInstance("SHA256");
- } catch (NoSuchAlgorithmException e) {
- /* can't happen */
- return null;
+ XmlSerializer out = new FastXmlSerializer();
+ out.setOutput(stream, StandardCharsets.UTF_8.name());
+ out.startDocument(null, true);
+ out.startTag(null, "network-watchlist-settings");
+ out.startTag(null, "secret-key");
+ out.text(HexDump.toHexString(mPrivacySecretKey));
+ out.endTag(null, "secret-key");
+ out.endTag(null, "network-watchlist-settings");
+ out.endDocument();
+ mXmlFile.finishWrite(stream);
+ } catch (IOException e) {
+ Log.w(TAG, "Failed to write display settings, restoring backup.", e);
+ mXmlFile.failWrite(stream);
}
- messageDigest.update(str.getBytes());
- return messageDigest.digest();
- }
-
- public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
- pw.println("Domain CRC32 digest list:");
- mDomainDigests.crc32Digests.dump(fd, pw, args);
- pw.println("Domain SHA256 digest list:");
- mDomainDigests.sha256Digests.dump(fd, pw, args);
- pw.println("Ip CRC32 digest list:");
- mIpDigests.crc32Digests.dump(fd, pw, args);
- pw.println("Ip SHA256 digest list:");
- mIpDigests.sha256Digests.dump(fd, pw, args);
}
}
diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java
index dd374fe76b2a..2585cf3d7fa5 100644
--- a/services/core/java/com/android/server/pm/PackageManagerService.java
+++ b/services/core/java/com/android/server/pm/PackageManagerService.java
@@ -18900,6 +18900,14 @@ Slog.e("TODD",
return Build.VERSION_CODES.CUR_DEVELOPMENT;
}
+ private int getPackageTargetSdkVersionLockedLPr(String packageName) {
+ final PackageParser.Package p = mPackages.get(packageName);
+ if (p != null) {
+ return p.applicationInfo.targetSdkVersion;
+ }
+ return Build.VERSION_CODES.CUR_DEVELOPMENT;
+ }
+
@Override
public void addPreferredActivity(IntentFilter filter, int match,
ComponentName[] set, ComponentName activity, int userId) {
@@ -23419,6 +23427,13 @@ Slog.v(TAG, ":: stepped forward, applying functor at tag " + parser.getName());
}
@Override
+ public int getPackageTargetSdkVersion(String packageName) {
+ synchronized (mPackages) {
+ return getPackageTargetSdkVersionLockedLPr(packageName);
+ }
+ }
+
+ @Override
public boolean canAccessInstantApps(int callingUid, int userId) {
return PackageManagerService.this.canViewInstantApps(callingUid, userId);
}
diff --git a/services/core/java/com/android/server/policy/PhoneWindowManager.java b/services/core/java/com/android/server/policy/PhoneWindowManager.java
index 88e4270ad07e..63449976587e 100644
--- a/services/core/java/com/android/server/policy/PhoneWindowManager.java
+++ b/services/core/java/com/android/server/policy/PhoneWindowManager.java
@@ -850,7 +850,7 @@ public class PhoneWindowManager implements WindowManagerPolicy {
dispatchMediaKeyRepeatWithWakeLock((KeyEvent)msg.obj);
break;
case MSG_DISPATCH_SHOW_RECENTS:
- showRecentApps(false, msg.arg1 != 0);
+ showRecentApps(false);
break;
case MSG_DISPATCH_SHOW_GLOBAL_ACTIONS:
showGlobalActionsInternal();
@@ -3817,7 +3817,7 @@ public class PhoneWindowManager implements WindowManagerPolicy {
final int shiftlessModifiers = event.getModifiers() & ~KeyEvent.META_SHIFT_MASK;
if (KeyEvent.metaStateHasModifiers(shiftlessModifiers, KeyEvent.META_ALT_ON)) {
mRecentAppsHeldModifiers = shiftlessModifiers;
- showRecentApps(true, false);
+ showRecentApps(true);
return -1;
}
}
@@ -4164,16 +4164,16 @@ public class PhoneWindowManager implements WindowManagerPolicy {
}
@Override
- public void showRecentApps(boolean fromHome) {
+ public void showRecentApps() {
mHandler.removeMessages(MSG_DISPATCH_SHOW_RECENTS);
- mHandler.obtainMessage(MSG_DISPATCH_SHOW_RECENTS, fromHome ? 1 : 0, 0).sendToTarget();
+ mHandler.obtainMessage(MSG_DISPATCH_SHOW_RECENTS).sendToTarget();
}
- private void showRecentApps(boolean triggeredFromAltTab, boolean fromHome) {
+ private void showRecentApps(boolean triggeredFromAltTab) {
mPreloadedRecentApps = false; // preloading no longer needs to be canceled
StatusBarManagerInternal statusbar = getStatusBarManagerInternal();
if (statusbar != null) {
- statusbar.showRecentApps(triggeredFromAltTab, fromHome);
+ statusbar.showRecentApps(triggeredFromAltTab);
}
}
diff --git a/services/core/java/com/android/server/policy/WindowManagerPolicy.java b/services/core/java/com/android/server/policy/WindowManagerPolicy.java
index c05dd2af3e5b..e9c4c5c8138f 100644
--- a/services/core/java/com/android/server/policy/WindowManagerPolicy.java
+++ b/services/core/java/com/android/server/policy/WindowManagerPolicy.java
@@ -1571,7 +1571,7 @@ public interface WindowManagerPolicy extends WindowManagerPolicyConstants {
* Show the recents task list app.
* @hide
*/
- public void showRecentApps(boolean fromHome);
+ public void showRecentApps();
/**
* Show the global actions dialog.
diff --git a/services/core/java/com/android/server/stats/StatsCompanionService.java b/services/core/java/com/android/server/stats/StatsCompanionService.java
index 2f5e2f8665f9..4cb5e089bd83 100644
--- a/services/core/java/com/android/server/stats/StatsCompanionService.java
+++ b/services/core/java/com/android/server/stats/StatsCompanionService.java
@@ -28,6 +28,7 @@ import android.content.pm.UserInfo;
import android.net.NetworkStats;
import android.net.wifi.IWifiManager;
import android.net.wifi.WifiActivityEnergyInfo;
+import android.os.SystemClock;
import android.telephony.ModemActivityInfo;
import android.telephony.TelephonyManager;
import android.os.BatteryStatsInternal;
@@ -621,6 +622,20 @@ public class StatsCompanionService extends IStatsCompanionService.Stub {
}
break;
}
+ case StatsLog.CPU_SUSPEND_TIME: {
+ List<StatsLogEventWrapper> ret = new ArrayList();
+ StatsLogEventWrapper e = new StatsLogEventWrapper(tagId, 1);
+ e.writeLong(SystemClock.elapsedRealtime());
+ ret.add(e);
+ break;
+ }
+ case StatsLog.CPU_IDLE_TIME: {
+ List<StatsLogEventWrapper> ret = new ArrayList();
+ StatsLogEventWrapper e = new StatsLogEventWrapper(tagId, 1);
+ e.writeLong(SystemClock.uptimeMillis());
+ ret.add(e);
+ break;
+ }
default:
Slog.w(TAG, "No such tagId data as " + tagId);
return null;
diff --git a/services/core/java/com/android/server/statusbar/StatusBarManagerInternal.java b/services/core/java/com/android/server/statusbar/StatusBarManagerInternal.java
index 3792bc6777ed..b5d0c60efae8 100644
--- a/services/core/java/com/android/server/statusbar/StatusBarManagerInternal.java
+++ b/services/core/java/com/android/server/statusbar/StatusBarManagerInternal.java
@@ -30,7 +30,7 @@ public interface StatusBarManagerInternal {
void cancelPreloadRecentApps();
- void showRecentApps(boolean triggeredFromAltTab, boolean fromHome);
+ void showRecentApps(boolean triggeredFromAltTab);
void hideRecentApps(boolean triggeredFromAltTab, boolean triggeredFromHomeKey);
diff --git a/services/core/java/com/android/server/statusbar/StatusBarManagerService.java b/services/core/java/com/android/server/statusbar/StatusBarManagerService.java
index c7c03b48a778..79d3dbbe8c83 100644
--- a/services/core/java/com/android/server/statusbar/StatusBarManagerService.java
+++ b/services/core/java/com/android/server/statusbar/StatusBarManagerService.java
@@ -282,10 +282,10 @@ public class StatusBarManagerService extends IStatusBarService.Stub {
}
@Override
- public void showRecentApps(boolean triggeredFromAltTab, boolean fromHome) {
+ public void showRecentApps(boolean triggeredFromAltTab) {
if (mBar != null) {
try {
- mBar.showRecentApps(triggeredFromAltTab, fromHome);
+ mBar.showRecentApps(triggeredFromAltTab);
} catch (RemoteException ex) {}
}
}
diff --git a/services/core/java/com/android/server/vr/VrManagerService.java b/services/core/java/com/android/server/vr/VrManagerService.java
index de723c6701d3..d84fbc53c5f9 100644
--- a/services/core/java/com/android/server/vr/VrManagerService.java
+++ b/services/core/java/com/android/server/vr/VrManagerService.java
@@ -185,6 +185,14 @@ public class VrManagerService extends SystemService
ComponentName component = null;
synchronized (mLock) {
component = ((mCurrentVrService == null) ? null : mCurrentVrService.getComponent());
+
+ // If the VrCore main service was disconnected or the binding died we'll rebind
+ // automatically. Call focusedActivityChanged() once we rebind.
+ if (component != null && component.equals(event.component) &&
+ (event.event == LogEvent.EVENT_DISCONNECTED ||
+ event.event == LogEvent.EVENT_BINDING_DIED)) {
+ callFocusedActivityChangedLocked();
+ }
}
// If not on an AIO device and we permanently stopped trying to connect to the
@@ -980,16 +988,7 @@ public class VrManagerService extends SystemService
oldVrServicePackage, oldUserId);
if (mCurrentVrService != null && sendUpdatedCaller) {
- final ComponentName c = mCurrentVrModeComponent;
- final boolean b = running2dInVr;
- final int pid = processId;
- mCurrentVrService.sendEvent(new PendingEvent() {
- @Override
- public void runEvent(IInterface service) throws RemoteException {
- IVrListener l = (IVrListener) service;
- l.focusedActivityChanged(c, b, pid);
- }
- });
+ callFocusedActivityChangedLocked();
}
if (!nothingChanged) {
@@ -1002,6 +1001,23 @@ public class VrManagerService extends SystemService
}
}
+ private void callFocusedActivityChangedLocked() {
+ final ComponentName c = mCurrentVrModeComponent;
+ final boolean b = mRunning2dInVr;
+ final int pid = mVrAppProcessId;
+ mCurrentVrService.sendEvent(new PendingEvent() {
+ @Override
+ public void runEvent(IInterface service) throws RemoteException {
+ // Under specific (and unlikely) timing scenarios, when VrCore
+ // crashes and is rebound, focusedActivityChanged() may be
+ // called a 2nd time with the same arguments. IVrListeners
+ // should make sure to handle that scenario gracefully.
+ IVrListener l = (IVrListener) service;
+ l.focusedActivityChanged(c, b, pid);
+ }
+ });
+ }
+
private boolean isDefaultAllowed(String packageName) {
PackageManager pm = mContext.getPackageManager();
diff --git a/services/core/java/com/android/server/wm/DisplayContent.java b/services/core/java/com/android/server/wm/DisplayContent.java
index 3997c56eec07..6dc384a8831e 100644
--- a/services/core/java/com/android/server/wm/DisplayContent.java
+++ b/services/core/java/com/android/server/wm/DisplayContent.java
@@ -49,6 +49,7 @@ import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_KEYGUARD;
import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION;
import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_STARTING;
import static android.view.WindowManager.LayoutParams.TYPE_BOOT_PROGRESS;
+import static android.view.WindowManager.LayoutParams.TYPE_DOCK_DIVIDER;
import static android.view.WindowManager.LayoutParams.TYPE_DRAWN_APPLICATION;
import static android.view.WindowManager.LayoutParams.TYPE_DREAM;
import static android.view.WindowManager.LayoutParams.TYPE_INPUT_METHOD;
@@ -3180,6 +3181,21 @@ class DisplayContent extends WindowContainer<DisplayContent.DisplayChildWindowCo
*/
SurfaceControl mAppAnimationLayer = null;
+ /**
+ * Given that the split-screen divider does not have an AppWindowToken, it
+ * will have to live inside of a "NonAppWindowContainer", in particular
+ * {@link DisplayContent#mAboveAppWindowsContainers}. However, in visual Z order
+ * it will need to be interleaved with some of our children, appearing on top of
+ * both docked stacks but underneath any assistant stacks.
+ *
+ * To solve this problem we have this anchor control, which will always exist so
+ * we can always assign it the correct value in our {@link #assignChildLayers}.
+ * Likewise since it always exists, {@link AboveAppWindowContainers} can always
+ * assign the divider a layer relative to it. This way we prevent linking lifecycle
+ * events between the two containers.
+ */
+ SurfaceControl mSplitScreenDividerAnchor = null;
+
// Cached reference to some special stacks we tend to get a lot so we don't need to loop
// through the list to find them.
private TaskStack mHomeStack = null;
@@ -3496,37 +3512,39 @@ class DisplayContent extends WindowContainer<DisplayContent.DisplayChildWindowCo
@Override
void assignChildLayers(SurfaceControl.Transaction t) {
- int layer = 0;
- // We allow stacks to change visual order from the AM specified order due to
- // Z-boosting during animations. However we must take care to ensure TaskStacks
- // which are marked as alwaysOnTop remain that way.
- for (int i = 0; i < mChildren.size(); i++) {
- final TaskStack s = mChildren.get(i);
- s.assignChildLayers();
- if (!s.needsZBoost() && !s.isAlwaysOnTop()) {
- s.assignLayer(t, layer++);
+ final int HOME_STACK_STATE = 0;
+ final int NORMAL_STACK_STATE = 1;
+ final int ALWAYS_ON_TOP_STATE = 2;
+
+ int layer = 0;
+ for (int state = 0; state <= ALWAYS_ON_TOP_STATE; state++) {
+ for (int i = 0; i < mChildren.size(); i++) {
+ final TaskStack s = mChildren.get(i);
+ if (state == HOME_STACK_STATE && s.isActivityTypeHome()) {
+ s.assignLayer(t, layer++);
+ } else if (state == NORMAL_STACK_STATE && !s.isActivityTypeHome()
+ && !s.isAlwaysOnTop()) {
+ s.assignLayer(t, layer++);
+ if (s.inSplitScreenWindowingMode() && mSplitScreenDividerAnchor != null) {
+ t.setLayer(mSplitScreenDividerAnchor, layer++);
+ }
+ } else if (state == ALWAYS_ON_TOP_STATE && s.isAlwaysOnTop()) {
+ s.assignLayer(t, layer++);
+ }
}
- }
- for (int i = 0; i < mChildren.size(); i++) {
- final TaskStack s = mChildren.get(i);
- if (s.needsZBoost() && !s.isAlwaysOnTop()) {
- s.assignLayer(t, layer++);
+ // The appropriate place for App-Transitions to occur is right
+ // above all other animations but still below things in the Picture-and-Picture
+ // windowing mode.
+ if (state == NORMAL_STACK_STATE && mAppAnimationLayer != null) {
+ t.setLayer(mAppAnimationLayer, layer++);
}
}
for (int i = 0; i < mChildren.size(); i++) {
final TaskStack s = mChildren.get(i);
- if (s.isAlwaysOnTop()) {
- s.assignLayer(t, layer++);
- }
+ s.assignChildLayers(t);
}
- // The appropriate place for App-Transitions to occur is right
- // above all other animations but still below things in the Picture-and-Picture
- // windowing mode.
- if (mAppAnimationLayer != null) {
- t.setLayer(mAppAnimationLayer, layer++);
- }
}
@Override
@@ -3534,6 +3552,10 @@ class DisplayContent extends WindowContainer<DisplayContent.DisplayChildWindowCo
return mAppAnimationLayer;
}
+ SurfaceControl getSplitScreenDividerAnchor() {
+ return mSplitScreenDividerAnchor;
+ }
+
@Override
void onParentSet() {
super.onParentSet();
@@ -3541,11 +3563,18 @@ class DisplayContent extends WindowContainer<DisplayContent.DisplayChildWindowCo
mAppAnimationLayer = makeChildSurface(null)
.setName("animationLayer")
.build();
- getPendingTransaction().show(mAppAnimationLayer);
+ mSplitScreenDividerAnchor = makeChildSurface(null)
+ .setName("splitScreenDividerAnchor")
+ .build();
+ getPendingTransaction()
+ .show(mAppAnimationLayer)
+ .show(mSplitScreenDividerAnchor);
scheduleAnimation();
} else {
mAppAnimationLayer.destroy();
mAppAnimationLayer = null;
+ mSplitScreenDividerAnchor.destroy();
+ mSplitScreenDividerAnchor = null;
}
}
}
@@ -3560,6 +3589,12 @@ class DisplayContent extends WindowContainer<DisplayContent.DisplayChildWindowCo
&& imeContainer.getSurfaceControl() != null;
for (int j = 0; j < mChildren.size(); ++j) {
final WindowToken wt = mChildren.get(j);
+
+ // See {@link mSplitScreenDividerAnchor}
+ if (wt.windowType == TYPE_DOCK_DIVIDER) {
+ wt.assignRelativeLayer(t, mTaskStackContainers.getSplitScreenDividerAnchor(), 1);
+ continue;
+ }
wt.assignLayer(t, j);
wt.assignChildLayers(t);
@@ -3697,6 +3732,13 @@ class DisplayContent extends WindowContainer<DisplayContent.DisplayChildWindowCo
.setParent(mOverlayLayer);
}
+ /**
+ * Reparents the given surface to mOverlayLayer.
+ */
+ void reparentToOverlay(Transaction transaction, SurfaceControl surface) {
+ transaction.reparent(surface, mOverlayLayer.getHandle());
+ }
+
void applyMagnificationSpec(MagnificationSpec spec) {
applyMagnificationSpec(getPendingTransaction(), spec);
getPendingTransaction().apply();
diff --git a/services/core/java/com/android/server/wm/DockedStackDividerController.java b/services/core/java/com/android/server/wm/DockedStackDividerController.java
index 36e5d100edb6..7ae1f24b0cd6 100644
--- a/services/core/java/com/android/server/wm/DockedStackDividerController.java
+++ b/services/core/java/com/android/server/wm/DockedStackDividerController.java
@@ -607,7 +607,7 @@ public class DockedStackDividerController {
if (wasMinimized && mMinimizedDock && containsAppInDockedStack(openingApps)
&& appTransition != TRANSIT_NONE &&
!AppTransition.isKeyguardGoingAwayTransit(appTransition)) {
- mService.showRecentApps(true /* fromHome */);
+ mService.showRecentApps();
}
}
diff --git a/services/core/java/com/android/server/wm/DragDropController.java b/services/core/java/com/android/server/wm/DragDropController.java
index 0171b56ffc47..d55a64926504 100644
--- a/services/core/java/com/android/server/wm/DragDropController.java
+++ b/services/core/java/com/android/server/wm/DragDropController.java
@@ -18,12 +18,10 @@ package com.android.server.wm;
import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_DRAG;
import static com.android.server.wm.WindowManagerDebugConfig.SHOW_LIGHT_TRANSACTIONS;
-import static com.android.server.wm.WindowManagerDebugConfig.SHOW_TRANSACTIONS;
import static com.android.server.wm.WindowManagerDebugConfig.TAG_WM;
import android.annotation.NonNull;
import android.content.ClipData;
-import android.graphics.PixelFormat;
import android.os.Binder;
import android.os.Handler;
import android.os.IBinder;
@@ -32,8 +30,8 @@ import android.os.Message;
import android.util.Slog;
import android.view.Display;
import android.view.IWindow;
-import android.view.Surface;
import android.view.SurfaceControl;
+import android.view.SurfaceControl.Transaction;
import android.view.SurfaceSession;
import android.view.View;
@@ -50,10 +48,9 @@ class DragDropController {
private static final long DRAG_TIMEOUT_MS = 5000;
// Messages for Handler.
- private static final int MSG_DRAG_START_TIMEOUT = 0;
- static final int MSG_DRAG_END_TIMEOUT = 1;
- static final int MSG_TEAR_DOWN_DRAG_AND_DROP_INPUT = 2;
- static final int MSG_ANIMATION_END = 3;
+ static final int MSG_DRAG_END_TIMEOUT = 0;
+ static final int MSG_TEAR_DOWN_DRAG_AND_DROP_INPUT = 1;
+ static final int MSG_ANIMATION_END = 2;
/**
* Drag state per operation.
@@ -95,87 +92,35 @@ class DragDropController {
mDragState.sendDragStartedIfNeededLocked(window);
}
- IBinder prepareDrag(SurfaceSession session, int callerPid,
- int callerUid, IWindow window, int flags, int width, int height, Surface outSurface) {
+ IBinder performDrag(SurfaceSession session, int callerPid, int callerUid, IWindow window,
+ int flags, SurfaceControl surface, int touchSource, float touchX, float touchY,
+ float thumbCenterX, float thumbCenterY, ClipData data) {
if (DEBUG_DRAG) {
- Slog.d(TAG_WM, "prepare drag surface: w=" + width + " h=" + height
- + " flags=" + Integer.toHexString(flags) + " win=" + window
- + " asbinder=" + window.asBinder());
- }
-
- if (width <= 0 || height <= 0) {
- Slog.w(TAG_WM, "width and height of drag shadow must be positive");
- return null;
- }
-
- synchronized (mService.mWindowMap) {
- if (dragDropActiveLocked()) {
- Slog.w(TAG_WM, "Drag already in progress");
- return null;
- }
-
- // TODO(multi-display): support other displays
- final DisplayContent displayContent =
- mService.getDefaultDisplayContentLocked();
- final Display display = displayContent.getDisplay();
-
- final SurfaceControl surface = new SurfaceControl.Builder(session)
- .setName("drag surface")
- .setSize(width, height)
- .setFormat(PixelFormat.TRANSLUCENT)
- .build();
- surface.setLayerStack(display.getLayerStack());
- float alpha = 1;
- if ((flags & View.DRAG_FLAG_OPAQUE) == 0) {
- alpha = DRAG_SHADOW_ALPHA_TRANSPARENT;
- }
- surface.setAlpha(alpha);
-
- if (SHOW_TRANSACTIONS)
- Slog.i(TAG_WM, " DRAG " + surface + ": CREATE");
- outSurface.copyFrom(surface);
- final IBinder winBinder = window.asBinder();
- IBinder token = new Binder();
- mDragState = new DragState(mService, this, token, surface, flags, winBinder);
- mDragState.mPid = callerPid;
- mDragState.mUid = callerUid;
- mDragState.mOriginalAlpha = alpha;
- token = mDragState.mToken = new Binder();
-
- // 5 second timeout for this window to actually begin the drag
- sendTimeoutMessage(MSG_DRAG_START_TIMEOUT, winBinder);
- return token;
- }
- }
-
- boolean performDrag(IWindow window, IBinder dragToken,
- int touchSource, float touchX, float touchY, float thumbCenterX, float thumbCenterY,
- ClipData data) {
- if (DEBUG_DRAG) {
- Slog.d(TAG_WM, "perform drag: win=" + window + " data=" + data);
+ Slog.d(TAG_WM, "perform drag: win=" + window + " surface=" + surface + " flags=" +
+ Integer.toHexString(flags) + " data=" + data);
}
+ final IBinder dragToken = new Binder();
final boolean callbackResult = mCallback.get().prePerformDrag(window, dragToken,
touchSource, touchX, touchY, thumbCenterX, thumbCenterY, data);
try {
synchronized (mService.mWindowMap) {
- mHandler.removeMessages(MSG_DRAG_START_TIMEOUT, window.asBinder());
try {
if (!callbackResult) {
- return false;
+ Slog.w(TAG_WM, "IDragDropCallback rejects the performDrag request");
+ return null;
}
- Preconditions.checkState(
- mDragState != null, "performDrag() without prepareDrag()");
- Preconditions.checkState(
- mDragState.mToken == dragToken,
- "performDrag() does not match prepareDrag()");
+ if (dragDropActiveLocked()) {
+ Slog.w(TAG_WM, "Drag already in progress");
+ return null;
+ }
final WindowState callingWin = mService.windowForClientLocked(
null, window, false);
if (callingWin == null) {
Slog.w(TAG_WM, "Bad requesting window " + window);
- return false; // !!! TODO: throw here?
+ return null; // !!! TODO: throw here?
}
// !!! TODO: if input is not still focused on the initiating window, fail
@@ -188,18 +133,31 @@ class DragDropController {
// !!! FIXME: put all this heavy stuff onto the mHandler looper, as well as
// the actual drag event dispatch stuff in the dragstate
+ // !!! TODO(multi-display): support other displays
+
final DisplayContent displayContent = callingWin.getDisplayContent();
if (displayContent == null) {
Slog.w(TAG_WM, "display content is null");
- return false;
+ return null;
}
+ final float alpha = (flags & View.DRAG_FLAG_OPAQUE) == 0 ?
+ DRAG_SHADOW_ALPHA_TRANSPARENT : 1;
+ final IBinder winBinder = window.asBinder();
+ IBinder token = new Binder();
+ mDragState = new DragState(mService, this, token, surface, flags, winBinder);
+ surface = null;
+ mDragState.mPid = callerPid;
+ mDragState.mUid = callerUid;
+ mDragState.mOriginalAlpha = alpha;
+ mDragState.mToken = dragToken;
+
final Display display = displayContent.getDisplay();
mDragState.register(display);
if (!mService.mInputManager.transferTouchFocus(callingWin.mInputChannel,
mDragState.getInputChannel())) {
Slog.e(TAG_WM, "Unable to transfer touch focus");
- return false;
+ return null;
}
mDragState.mDisplayContent = displayContent;
@@ -213,28 +171,31 @@ class DragDropController {
// Make the surface visible at the proper location
final SurfaceControl surfaceControl = mDragState.mSurfaceControl;
if (SHOW_LIGHT_TRANSACTIONS) Slog.i(TAG_WM, ">>> OPEN TRANSACTION performDrag");
- mService.openSurfaceTransaction();
- try {
- surfaceControl.setPosition(touchX - thumbCenterX,
- touchY - thumbCenterY);
- surfaceControl.setLayer(mDragState.getDragLayerLocked());
- surfaceControl.setLayerStack(display.getLayerStack());
- surfaceControl.show();
- } finally {
- mService.closeSurfaceTransaction("performDrag");
- if (SHOW_LIGHT_TRANSACTIONS) {
- Slog.i(TAG_WM, "<<< CLOSE TRANSACTION performDrag");
- }
+
+ final SurfaceControl.Transaction transaction =
+ callingWin.getPendingTransaction();
+ transaction.setAlpha(surfaceControl, mDragState.mOriginalAlpha);
+ transaction.setPosition(
+ surfaceControl, touchX - thumbCenterX, touchY - thumbCenterY);
+ transaction.show(surfaceControl);
+ displayContent.reparentToOverlay(transaction, surfaceControl);
+ callingWin.scheduleAnimation();
+
+ if (SHOW_LIGHT_TRANSACTIONS) {
+ Slog.i(TAG_WM, "<<< CLOSE TRANSACTION performDrag");
}
mDragState.notifyLocationLocked(touchX, touchY);
} finally {
+ if (surface != null) {
+ surface.release();
+ }
if (mDragState != null && !mDragState.isInProgress()) {
mDragState.closeLocked();
}
}
}
- return true; // success!
+ return dragToken; // success!
} finally {
mCallback.get().postPerformDrag();
}
@@ -385,21 +346,6 @@ class DragDropController {
@Override
public void handleMessage(Message msg) {
switch (msg.what) {
- case MSG_DRAG_START_TIMEOUT: {
- IBinder win = (IBinder) msg.obj;
- if (DEBUG_DRAG) {
- Slog.w(TAG_WM, "Timeout starting drag by win " + win);
- }
-
- synchronized (mService.mWindowMap) {
- // !!! TODO: ANR the app that has failed to start the drag in time
- if (mDragState != null) {
- mDragState.closeLocked();
- }
- }
- break;
- }
-
case MSG_DRAG_END_TIMEOUT: {
final IBinder win = (IBinder) msg.obj;
if (DEBUG_DRAG) {
diff --git a/services/core/java/com/android/server/wm/Session.java b/services/core/java/com/android/server/wm/Session.java
index 334be336e199..04ae38ec33b1 100644
--- a/services/core/java/com/android/server/wm/Session.java
+++ b/services/core/java/com/android/server/wm/Session.java
@@ -51,6 +51,7 @@ import android.view.IWindowSession;
import android.view.IWindowSessionCallback;
import android.view.InputChannel;
import android.view.Surface;
+import android.view.SurfaceControl;
import android.view.SurfaceSession;
import android.view.WindowManager;
@@ -308,30 +309,22 @@ class Session extends IWindowSession.Stub implements IBinder.DeathRecipient {
}
/* Drag/drop */
+
@Override
- public IBinder prepareDrag(IWindow window, int flags, int width, int height,
- Surface outSurface) {
+ public IBinder performDrag(IWindow window, int flags, SurfaceControl surface, int touchSource,
+ float touchX, float touchY, float thumbCenterX, float thumbCenterY, ClipData data) {
final int callerPid = Binder.getCallingPid();
final int callerUid = Binder.getCallingUid();
final long ident = Binder.clearCallingIdentity();
try {
- return mDragDropController.prepareDrag(
- mSurfaceSession, callerPid, callerUid, window, flags, width, height,
- outSurface);
+ return mDragDropController.performDrag(mSurfaceSession, callerPid, callerUid, window,
+ flags, surface, touchSource, touchX, touchY, thumbCenterX, thumbCenterY, data);
} finally {
Binder.restoreCallingIdentity(ident);
}
}
@Override
- public boolean performDrag(IWindow window, IBinder dragToken,
- int touchSource, float touchX, float touchY, float thumbCenterX, float thumbCenterY,
- ClipData data) {
- return mDragDropController.performDrag(window, dragToken, touchSource,
- touchX, touchY, thumbCenterX, thumbCenterY, data);
- }
-
- @Override
public void reportDropResult(IWindow window, boolean consumed) {
final long ident = Binder.clearCallingIdentity();
try {
diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java
index 53086f714a79..de1e7ecb2bb9 100644
--- a/services/core/java/com/android/server/wm/WindowManagerService.java
+++ b/services/core/java/com/android/server/wm/WindowManagerService.java
@@ -5967,8 +5967,8 @@ public class WindowManagerService extends IWindowManager.Stub
mPolicy.lockNow(options);
}
- public void showRecentApps(boolean fromHome) {
- mPolicy.showRecentApps(fromHome);
+ public void showRecentApps() {
+ mPolicy.showRecentApps();
}
@Override
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/BaseIDevicePolicyManager.java b/services/devicepolicy/java/com/android/server/devicepolicy/BaseIDevicePolicyManager.java
index 384b416b0201..7a0b1bf46fcf 100644
--- a/services/devicepolicy/java/com/android/server/devicepolicy/BaseIDevicePolicyManager.java
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/BaseIDevicePolicyManager.java
@@ -39,12 +39,6 @@ import java.util.List;
*/
abstract class BaseIDevicePolicyManager extends IDevicePolicyManager.Stub {
/**
- * To be called by {@link DevicePolicyManagerService#Lifecycle} when the service is started.
- *
- * @see {@link SystemService#onStart}.
- */
- abstract void handleStart();
- /**
* To be called by {@link DevicePolicyManagerService#Lifecycle} during the various boot phases.
*
* @see {@link SystemService#onBootPhase}.
@@ -126,4 +120,19 @@ abstract class BaseIDevicePolicyManager extends IDevicePolicyManager.Stub {
public String getEndUserSessionMessage(ComponentName admin) {
return null;
}
+
+ @Override
+ public void setPrintingEnabled(ComponentName admin, boolean enabled) {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public boolean isPrintingEnabled() {
+ return true;
+ }
+
+ @Override
+ public CharSequence getPrintingDisabledReason() {
+ return null;
+ }
}
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
index cb4f5c1177df..8d91288aa9f2 100644
--- a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
@@ -74,6 +74,7 @@ import android.annotation.UserIdInt;
import android.app.Activity;
import android.app.ActivityManager;
import android.app.ActivityManagerInternal;
+import android.app.ActivityThread;
import android.app.AlarmManager;
import android.app.AppGlobals;
import android.app.IActivityManager;
@@ -197,8 +198,10 @@ import com.android.internal.util.Preconditions;
import com.android.internal.util.XmlUtils;
import com.android.internal.widget.LockPatternUtils;
import com.android.server.LocalServices;
+import com.android.server.SystemServerInitThreadPool;
import com.android.server.SystemService;
import com.android.server.devicepolicy.DevicePolicyManagerService.ActiveAdmin.TrustAgentInfo;
+import com.android.server.net.NetworkPolicyManagerInternal;
import com.android.server.pm.UserRestrictionsUtils;
import com.google.android.collect.Sets;
@@ -285,6 +288,8 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
private static final String TAG_PASSWORD_VALIDITY = "password-validity";
+ private static final String TAG_PRINTING_ENABLED = "printing-enabled";
+
private static final int REQUEST_EXPIRE_PASSWORD = 5571;
private static final long MS_PER_DAY = TimeUnit.DAYS.toMillis(1);
@@ -508,7 +513,6 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
@Override
public void onStart() {
publishBinderService(Context.DEVICE_POLICY_SERVICE, mService);
- mService.handleStart();
}
@Override
@@ -589,6 +593,8 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
long mPasswordTokenHandle = 0;
+ boolean mPrintingEnabled = true;
+
public DevicePolicyData(int userHandle) {
mUserHandle = userHandle;
}
@@ -648,14 +654,14 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
}
if (Intent.ACTION_USER_ADDED.equals(action)) {
- sendUserAddedOrRemovedCommand(DeviceAdminReceiver.ACTION_USER_ADDED, userHandle);
+ sendDeviceOwnerUserCommand(DeviceAdminReceiver.ACTION_USER_ADDED, userHandle);
synchronized (DevicePolicyManagerService.this) {
// It might take a while for the user to become affiliated. Make security
// and network logging unavailable in the meantime.
maybePauseDeviceWideLoggingLocked();
}
} else if (Intent.ACTION_USER_REMOVED.equals(action)) {
- sendUserAddedOrRemovedCommand(DeviceAdminReceiver.ACTION_USER_REMOVED, userHandle);
+ sendDeviceOwnerUserCommand(DeviceAdminReceiver.ACTION_USER_REMOVED, userHandle);
synchronized (DevicePolicyManagerService.this) {
// Check whether the user is affiliated, *before* removing its data.
boolean isRemovedUserAffiliated = isUserAffiliatedWithDeviceLocked(userHandle);
@@ -669,12 +675,17 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
}
}
} else if (Intent.ACTION_USER_STARTED.equals(action)) {
+ sendDeviceOwnerUserCommand(DeviceAdminReceiver.ACTION_USER_STARTED, userHandle);
synchronized (DevicePolicyManagerService.this) {
maybeSendAdminEnabledBroadcastLocked(userHandle);
// Reset the policy data
mUserData.remove(userHandle);
}
handlePackagesChanged(null /* check all admins */, userHandle);
+ } else if (Intent.ACTION_USER_STOPPED.equals(action)) {
+ sendDeviceOwnerUserCommand(DeviceAdminReceiver.ACTION_USER_STOPPED, userHandle);
+ } else if (Intent.ACTION_USER_SWITCHED.equals(action)) {
+ sendDeviceOwnerUserCommand(DeviceAdminReceiver.ACTION_USER_SWITCHED, userHandle);
} else if (Intent.ACTION_USER_UNLOCKED.equals(action)) {
synchronized (DevicePolicyManagerService.this) {
maybeSendAdminEnabledBroadcastLocked(userHandle);
@@ -683,7 +694,7 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
handlePackagesChanged(null /* check all admins */, userHandle);
} else if (Intent.ACTION_PACKAGE_CHANGED.equals(action)
|| (Intent.ACTION_PACKAGE_ADDED.equals(action)
- && intent.getBooleanExtra(Intent.EXTRA_REPLACING, false))) {
+ && intent.getBooleanExtra(Intent.EXTRA_REPLACING, false))) {
handlePackagesChanged(intent.getData().getSchemeSpecificPart(), userHandle);
} else if (Intent.ACTION_PACKAGE_REMOVED.equals(action)
&& !intent.getBooleanExtra(Intent.EXTRA_REPLACING, false)) {
@@ -693,7 +704,7 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
}
}
- private void sendUserAddedOrRemovedCommand(String action, int userHandle) {
+ private void sendDeviceOwnerUserCommand(String action, int userHandle) {
synchronized (DevicePolicyManagerService.this) {
ActiveAdmin deviceOwner = getDeviceOwnerAdminLocked();
if (deviceOwner != null) {
@@ -1733,6 +1744,10 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
return LocalServices.getService(UsageStatsManagerInternal.class);
}
+ NetworkPolicyManagerInternal getNetworkPolicyManagerInternal() {
+ return LocalServices.getService(NetworkPolicyManagerInternal.class);
+ }
+
NotificationManager getNotificationManager() {
return mContext.getSystemService(NotificationManager.class);
}
@@ -1986,6 +2001,10 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
KeyChainConnection keyChainBindAsUser(UserHandle user) throws InterruptedException {
return KeyChain.bindAsUser(mContext, user);
}
+
+ void postOnSystemServerInitThreadPool(Runnable runnable) {
+ SystemServerInitThreadPool.get().submit(runnable, LOG_TAG);
+ }
}
/**
@@ -2041,6 +2060,8 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
filter.addAction(Intent.ACTION_USER_ADDED);
filter.addAction(Intent.ACTION_USER_REMOVED);
filter.addAction(Intent.ACTION_USER_STARTED);
+ filter.addAction(Intent.ACTION_USER_STOPPED);
+ filter.addAction(Intent.ACTION_USER_SWITCHED);
filter.addAction(Intent.ACTION_USER_UNLOCKED);
filter.setPriority(IntentFilter.SYSTEM_HIGH_PRIORITY);
mContext.registerReceiverAsUser(mReceiver, UserHandle.ALL, filter, null, mHandler);
@@ -2880,6 +2901,12 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
out.endTag(null, TAG_CURRENT_INPUT_METHOD_SET);
}
+ if (!policy.mPrintingEnabled) {
+ out.startTag(null, TAG_PRINTING_ENABLED);
+ out.attribute(null, ATTR_VALUE, Boolean.toString(policy.mPrintingEnabled));
+ out.endTag(null, TAG_PRINTING_ENABLED);
+ }
+
for (final String cert : policy.mOwnerInstalledCaCerts) {
out.startTag(null, TAG_OWNER_INSTALLED_CA_CERT);
out.attribute(null, ATTR_ALIAS, cert);
@@ -3098,6 +3125,9 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
policy.mCurrentInputMethodSet = true;
} else if (TAG_OWNER_INSTALLED_CA_CERT.equals(tag)) {
policy.mOwnerInstalledCaCerts.add(parser.getAttributeValue(null, ATTR_ALIAS));
+ } else if (TAG_PRINTING_ENABLED.equals(tag)) {
+ String enabled = parser.getAttributeValue(null, ATTR_VALUE);
+ policy.mPrintingEnabled = Boolean.toString(true).equals(enabled);
} else {
Slog.w(LOG_TAG, "Unknown tag: " + tag);
XmlUtils.skipCurrentTag(parser);
@@ -3218,6 +3248,7 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
switch (phase) {
case SystemService.PHASE_LOCK_SETTINGS_READY:
onLockSettingsReady();
+ loadAdminDataAsync();
break;
case SystemService.PHASE_BOOT_COMPLETED:
ensureDeviceOwnerUserStarted(); // TODO Consider better place to do this.
@@ -3286,11 +3317,6 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
}
@Override
- void handleStart() {
- pushActiveAdminPackages();
- }
-
- @Override
void handleStartUser(int userId) {
updateScreenCaptureDisabledInWindowManager(userId,
getScreenCaptureDisabled(null, userId));
@@ -3472,6 +3498,14 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
}
}
+ private void loadAdminDataAsync() {
+ mInjector.postOnSystemServerInitThreadPool(() -> {
+ pushActiveAdminPackages();
+ mUsageStatsManagerInternal.onAdminDataAvailable();
+ mInjector.getNetworkPolicyManagerInternal().onAdminDataAvailable();
+ });
+ }
+
private void pushActiveAdminPackages() {
synchronized (this) {
final List<UserInfo> users = mUserManager.getUsers();
@@ -12274,4 +12308,93 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
return deviceOwner.endUserSessionMessage;
}
}
+
+ private boolean hasPrinting() {
+ return mInjector.getPackageManager().hasSystemFeature(PackageManager.FEATURE_PRINTING);
+ }
+
+ @Override
+ public void setPrintingEnabled(ComponentName admin, boolean enabled) {
+ if (!mHasFeature || !hasPrinting()) {
+ return;
+ }
+ Preconditions.checkNotNull(admin, "Admin cannot be null.");
+ enforceProfileOrDeviceOwner(admin);
+ synchronized (this) {
+ final int userHandle = mInjector.userHandleGetCallingUserId();
+ DevicePolicyData policy = getUserData(userHandle);
+ if (policy.mPrintingEnabled != enabled) {
+ policy.mPrintingEnabled = enabled;
+ saveSettingsLocked(userHandle);
+ }
+ }
+ }
+
+ /**
+ * Returns whether printing is enabled for current user.
+ * @hide
+ */
+ @Override
+ public boolean isPrintingEnabled() {
+ if (!hasPrinting()) {
+ return false;
+ }
+ if (!mHasFeature) {
+ return true;
+ }
+ synchronized (this) {
+ final int userHandle = mInjector.userHandleGetCallingUserId();
+ DevicePolicyData policy = getUserData(userHandle);
+ return policy.mPrintingEnabled;
+ }
+ }
+
+ /**
+ * Returns text of error message if printing is disabled.
+ * Only to be called by Print Service.
+ * @hide
+ */
+ @Override
+ public CharSequence getPrintingDisabledReason() {
+ if (!hasPrinting() || !mHasFeature) {
+ Log.e(LOG_TAG, "no printing or no management");
+ return null;
+ }
+ synchronized (this) {
+ final int userHandle = mInjector.userHandleGetCallingUserId();
+ DevicePolicyData policy = getUserData(userHandle);
+ if (policy.mPrintingEnabled) {
+ Log.e(LOG_TAG, "printing is enabled");
+ return null;
+ }
+ String ownerPackage = mOwners.getProfileOwnerPackage(userHandle);
+ if (ownerPackage == null) {
+ ownerPackage = mOwners.getDeviceOwnerPackageName();
+ }
+ PackageManager pm = mInjector.getPackageManager();
+ PackageInfo packageInfo;
+ try {
+ packageInfo = pm.getPackageInfo(ownerPackage, 0);
+ } catch (NameNotFoundException e) {
+ Log.e(LOG_TAG, "getPackageInfo error", e);
+ return null;
+ }
+ if (packageInfo == null) {
+ Log.e(LOG_TAG, "packageInfo is inexplicably null");
+ return null;
+ }
+ ApplicationInfo appInfo = packageInfo.applicationInfo;
+ if (appInfo == null) {
+ Log.e(LOG_TAG, "appInfo is inexplicably null");
+ return null;
+ }
+ CharSequence appLabel = pm.getApplicationLabel(appInfo);
+ if (appLabel == null) {
+ Log.e(LOG_TAG, "appLabel is inexplicably null");
+ return null;
+ }
+ return ((Context) ActivityThread.currentActivityThread().getSystemUiContext())
+ .getResources().getString(R.string.printing_disabled_by, appLabel);
+ }
+ }
}
diff --git a/services/print/java/com/android/server/print/PrintManagerService.java b/services/print/java/com/android/server/print/PrintManagerService.java
index cd4e8f977d60..89a5fe1b82c7 100644
--- a/services/print/java/com/android/server/print/PrintManagerService.java
+++ b/services/print/java/com/android/server/print/PrintManagerService.java
@@ -21,6 +21,7 @@ import static android.content.pm.PackageManager.MATCH_DEBUG_TRIAGED_MISSING;
import android.annotation.NonNull;
import android.app.ActivityManager;
+import android.app.admin.DevicePolicyManager;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
@@ -32,6 +33,7 @@ import android.graphics.drawable.Icon;
import android.net.Uri;
import android.os.Binder;
import android.os.Bundle;
+import android.os.Looper;
import android.os.Process;
import android.os.RemoteException;
import android.os.UserHandle;
@@ -54,6 +56,7 @@ import android.service.print.PrintServiceDumpProto;
import android.util.Log;
import android.util.SparseArray;
import android.util.proto.ProtoOutputStream;
+import android.widget.Toast;
import com.android.internal.content.PackageMonitor;
import com.android.internal.os.BackgroundThread;
@@ -110,9 +113,12 @@ public final class PrintManagerService extends SystemService {
private final SparseArray<UserState> mUserStates = new SparseArray<>();
+ private final DevicePolicyManager mDpc;
+
PrintManagerImpl(Context context) {
mContext = context;
mUserManager = (UserManager) context.getSystemService(Context.USER_SERVICE);
+ mDpc = (DevicePolicyManager) context.getSystemService(Context.DEVICE_POLICY_SERVICE);
registerContentObservers();
registerBroadcastReceivers();
}
@@ -120,8 +126,26 @@ public final class PrintManagerService extends SystemService {
@Override
public Bundle print(String printJobName, IPrintDocumentAdapter adapter,
PrintAttributes attributes, String packageName, int appId, int userId) {
- printJobName = Preconditions.checkStringNotEmpty(printJobName);
adapter = Preconditions.checkNotNull(adapter);
+ if (!isPrintingEnabled()) {
+ final CharSequence disabledMessage = mDpc.getPrintingDisabledReason();
+ if (disabledMessage != null) {
+ Toast.makeText(mContext, Looper.getMainLooper(), disabledMessage,
+ Toast.LENGTH_LONG).show();
+ }
+ try {
+ adapter.start();
+ } catch (RemoteException re) {
+ Log.e(LOG_TAG, "Error calling IPrintDocumentAdapter.start()");
+ }
+ try {
+ adapter.finish();
+ } catch (RemoteException re) {
+ Log.e(LOG_TAG, "Error calling IPrintDocumentAdapter.finish()");
+ }
+ return null;
+ }
+ printJobName = Preconditions.checkStringNotEmpty(printJobName);
packageName = Preconditions.checkStringNotEmpty(packageName);
final int resolvedUserId = resolveCallingUserEnforcingPermissions(userId);
@@ -240,7 +264,8 @@ public final class PrintManagerService extends SystemService {
@Override
public void restartPrintJob(PrintJobId printJobId, int appId, int userId) {
- if (printJobId == null) {
+ if (printJobId == null || !isPrintingEnabled()) {
+ // if printing is disabled the state just remains "failed".
return;
}
@@ -685,6 +710,10 @@ public final class PrintManagerService extends SystemService {
}
}
+ private boolean isPrintingEnabled() {
+ return mDpc == null || mDpc.isPrintingEnabled();
+ }
+
private void dump(@NonNull DualDumpOutputStream dumpStream,
@NonNull ArrayList<UserState> userStatesToDump) {
final int userStateCount = userStatesToDump.size();
diff --git a/services/robotests/src/com/android/server/backup/TransportManagerTest.java b/services/robotests/src/com/android/server/backup/TransportManagerTest.java
index 6753d73590d3..068fe8137467 100644
--- a/services/robotests/src/com/android/server/backup/TransportManagerTest.java
+++ b/services/robotests/src/com/android/server/backup/TransportManagerTest.java
@@ -532,6 +532,46 @@ public class TransportManagerTest {
() -> transportManager.getTransportDirName(mTransportA2.transportName));
}
+ @Test
+ public void testGetRegisteredTransportNames() throws Exception {
+ setUpPackage(PACKAGE_A, ApplicationInfo.PRIVATE_FLAG_PRIVILEGED);
+ setUpPackage(PACKAGE_B, ApplicationInfo.PRIVATE_FLAG_PRIVILEGED);
+ TransportData[] transportsData = {mTransportA1, mTransportA2, mTransportB1};
+ setUpTransports(transportsData);
+ TransportManager transportManager =
+ createTransportManager(mTransportA1, mTransportA2, mTransportB1);
+ transportManager.registerTransports();
+
+ String[] transportNames = transportManager.getRegisteredTransportNames();
+
+ assertThat(transportNames)
+ .asList()
+ .containsExactlyElementsIn(
+ Stream.of(transportsData)
+ .map(transportData -> transportData.transportName)
+ .collect(toList()));
+ }
+
+ @Test
+ public void testGetRegisteredTransportComponents() throws Exception {
+ setUpPackage(PACKAGE_A, ApplicationInfo.PRIVATE_FLAG_PRIVILEGED);
+ setUpPackage(PACKAGE_B, ApplicationInfo.PRIVATE_FLAG_PRIVILEGED);
+ TransportData[] transportsData = {mTransportA1, mTransportA2, mTransportB1};
+ setUpTransports(transportsData);
+ TransportManager transportManager =
+ createTransportManager(mTransportA1, mTransportA2, mTransportB1);
+ transportManager.registerTransports();
+
+ ComponentName[] transportNames = transportManager.getRegisteredTransportComponents();
+
+ assertThat(transportNames)
+ .asList()
+ .containsExactlyElementsIn(
+ Stream.of(transportsData)
+ .map(TransportData::getTransportComponent)
+ .collect(toList()));
+ }
+
private List<TransportMock> setUpTransports(TransportData... transports) throws Exception {
setUpTransportsForTransportManager(mShadowPackageManager, transports);
List<TransportMock> transportMocks = new ArrayList<>(transports.length);
diff --git a/services/tests/servicestests/assets/NetworkWatchlistTest/watchlist_config_test1.xml b/services/tests/servicestests/assets/NetworkWatchlistTest/watchlist_config_test1.xml
new file mode 100644
index 000000000000..e31fad834023
--- /dev/null
+++ b/services/tests/servicestests/assets/NetworkWatchlistTest/watchlist_config_test1.xml
@@ -0,0 +1,27 @@
+<?xml version='1.0'?>
+<watchlist-config>
+ <sha256-domain>
+ <!-- test-cc-domain.com -->
+ <hash>8E7DCD2AEB4F364358242BB3F403263E61E3B4AECE4E2500FF28BF32E52FF0F1</hash>
+ <!-- test-cc-match-sha256-only.com -->
+ <hash>F0905DA7549614957B449034C281EF7BDEFDBC2B6E050AD1E78D6DE18FBD0D5F</hash>
+ </sha256-domain>
+ <sha256-ip>
+ <!-- 127.0.0.2 -->
+ <hash>1EDD62868F2767A1FFF68DF0A4CB3C23448E45100715768DB9310B5E719536A1</hash>
+ <!-- 127.0.0.3, match in sha256 only -->
+ <hash>18DD41C9F2E8E4879A1575FB780514EF33CF6E1F66578C4AE7CCA31F49B9F2ED</hash>
+ </sha256-ip>
+ <crc32-domain>
+ <!-- test-cc-domain.com -->
+ <hash>6C67059D</hash>
+ <!-- test-cc-match-crc32-only.com -->
+ <hash>3DC775F8</hash>
+ </crc32-domain>
+ <crc32-ip>
+ <!-- 127.0.0.2 -->
+ <hash>4EBEB612</hash>
+ <!-- 127.0.0.4, match in crc32 only -->
+ <hash>A7DD1327</hash>
+ </crc32-ip>
+</watchlist-config>
diff --git a/services/tests/servicestests/assets/NetworkWatchlistTest/watchlist_settings_test1.xml b/services/tests/servicestests/assets/NetworkWatchlistTest/watchlist_settings_test1.xml
index bb97e9431f72..5349a13280fd 100644
--- a/services/tests/servicestests/assets/NetworkWatchlistTest/watchlist_settings_test1.xml
+++ b/services/tests/servicestests/assets/NetworkWatchlistTest/watchlist_settings_test1.xml
@@ -1,27 +1,4 @@
<?xml version='1.0'?>
-<watchlist-settings>
- <sha256-domain>
- <!-- test-cc-domain.com -->
- <hash>8E7DCD2AEB4F364358242BB3F403263E61E3B4AECE4E2500FF28BF32E52FF0F1</hash>
- <!-- test-cc-match-sha256-only.com -->
- <hash>F0905DA7549614957B449034C281EF7BDEFDBC2B6E050AD1E78D6DE18FBD0D5F</hash>
- </sha256-domain>
- <sha256-ip>
- <!-- 127.0.0.2 -->
- <hash>1EDD62868F2767A1FFF68DF0A4CB3C23448E45100715768DB9310B5E719536A1</hash>
- <!-- 127.0.0.3, match in sha256 only -->
- <hash>18DD41C9F2E8E4879A1575FB780514EF33CF6E1F66578C4AE7CCA31F49B9F2ED</hash>
- </sha256-ip>
- <crc32-domain>
- <!-- test-cc-domain.com -->
- <hash>6C67059D</hash>
- <!-- test-cc-match-crc32-only.com -->
- <hash>3DC775F8</hash>
- </crc32-domain>
- <crc32-ip>
- <!-- 127.0.0.2 -->
- <hash>4EBEB612</hash>
- <!-- 127.0.0.4, match in crc32 only -->
- <hash>A7DD1327</hash>
- </crc32-ip>
-</watchlist-settings>
+<network-watchlist-settings>
+ <secret-key>1234567890ABCDEF1234567890ABCDEF1234567890ABCDEF1234567890ABCDEF1234567890ABCDEF1234567890ABCDEF</secret-key>
+</network-watchlist-settings>
diff --git a/services/tests/servicestests/assets/NetworkWatchlistTest/watchlist_settings_test2.xml b/services/tests/servicestests/assets/NetworkWatchlistTest/watchlist_settings_test2.xml
new file mode 100644
index 000000000000..3e65bc06be52
--- /dev/null
+++ b/services/tests/servicestests/assets/NetworkWatchlistTest/watchlist_settings_test2.xml
@@ -0,0 +1,4 @@
+<?xml version='1.0'?>
+<network-watchlist-settings>
+
+</network-watchlist-settings>
diff --git a/services/tests/servicestests/src/com/android/server/ForceAppStandbyTrackerTest.java b/services/tests/servicestests/src/com/android/server/ForceAppStandbyTrackerTest.java
index 66d0da13fff1..429dd8fd1d3d 100644
--- a/services/tests/servicestests/src/com/android/server/ForceAppStandbyTrackerTest.java
+++ b/services/tests/servicestests/src/com/android/server/ForceAppStandbyTrackerTest.java
@@ -50,13 +50,16 @@ import android.os.PowerSaveState;
import android.os.Process;
import android.os.RemoteException;
import android.os.UserHandle;
+import android.provider.Settings;
import android.support.test.filters.SmallTest;
import android.support.test.runner.AndroidJUnit4;
+import android.test.mock.MockContentResolver;
import android.util.ArraySet;
import android.util.Pair;
import com.android.internal.app.IAppOpsCallback;
import com.android.internal.app.IAppOpsService;
+import com.android.internal.util.test.FakeSettingsProvider;
import com.android.server.ForceAppStandbyTracker.Listener;
import org.junit.Before;
@@ -137,6 +140,9 @@ public class ForceAppStandbyTrackerTest {
private Consumer<PowerSaveState> mPowerSaveObserver;
private BroadcastReceiver mReceiver;
+ private MockContentResolver mMockContentResolver;
+ private FakeSettingsProvider mFakeSettingsProvider;
+
private boolean mPowerSaveMode;
private final ArraySet<Pair<Integer, String>> mRestrictedPackages = new ArraySet();
@@ -182,6 +188,11 @@ public class ForceAppStandbyTrackerTest {
any(int[].class)
)).thenAnswer(inv -> new ArrayList<AppOpsManager.PackageOps>());
+ mMockContentResolver = new MockContentResolver();
+ mFakeSettingsProvider = new FakeSettingsProvider();
+ when(mMockContext.getContentResolver()).thenReturn(mMockContentResolver);
+ mMockContentResolver.addProvider(Settings.AUTHORITY, mFakeSettingsProvider);
+
// Call start.
instance.start();
@@ -495,8 +506,8 @@ public class ForceAppStandbyTrackerTest {
verify(l, times(0)).unblockAlarmsForUidPackage(anyInt(), anyString());
reset(l);
- // Power save on.
- mPowerSaveMode = true;
+ // Updating to the same state should not fire listener
+ mPowerSaveMode = false;
mPowerSaveObserver.accept(getPowerSaveState());
assertNoCallbacks(l);
@@ -534,14 +545,14 @@ public class ForceAppStandbyTrackerTest {
verify(l, times(0)).unblockAllUnrestrictedAlarms();
verify(l, times(0)).unblockAlarmsForUid(anyInt());
- verify(l, times(0)).unblockAlarmsForUidPackage(eq(UID_10_2), eq(PACKAGE_2));
+ verify(l, times(1)).unblockAlarmsForUidPackage(eq(UID_10_2), eq(PACKAGE_2));
reset(l);
setAppOps(UID_10_2, PACKAGE_2, false);
verify(l, times(0)).updateAllJobs();
verify(l, times(0)).updateJobsForUid(anyInt());
- verify(l, times(1)).updateJobsForUidPackage(eq(UID_10_2), eq(PACKAGE_2));
+ verify(l, times(0)).updateJobsForUidPackage(anyInt(), anyString());
verify(l, times(0)).unblockAllUnrestrictedAlarms();
verify(l, times(0)).unblockAlarmsForUid(anyInt());
@@ -634,10 +645,20 @@ public class ForceAppStandbyTrackerTest {
mPowerSaveMode = true;
mPowerSaveObserver.accept(getPowerSaveState());
+ verify(l, times(1)).updateAllJobs();
+ verify(l, times(0)).updateJobsForUid(anyInt());
+ verify(l, times(0)).updateJobsForUidPackage(anyInt(), anyString());
+
+ verify(l, times(0)).unblockAllUnrestrictedAlarms();
+ verify(l, times(0)).unblockAlarmsForUid(anyInt());
+ verify(l, times(0)).unblockAlarmsForUidPackage(anyInt(), anyString());
+ reset(l);
+
instance.setPowerSaveWhitelistAppIds(new int[] {UID_1, UID_2}, new int[] {});
waitUntilMainHandlerDrain();
- verify(l, times(1)).updateAllJobs();
+ // Called once for updating all whitelist and once for updating temp whitelist
+ verify(l, times(2)).updateAllJobs();
verify(l, times(0)).updateJobsForUid(anyInt());
verify(l, times(0)).updateJobsForUidPackage(anyInt(), anyString());
@@ -699,7 +720,7 @@ public class ForceAppStandbyTrackerTest {
verify(l, times(0)).updateJobsForUidPackage(anyInt(), anyString());
verify(l, times(0)).unblockAllUnrestrictedAlarms();
- verify(l, times(0)).unblockAlarmsForUid(anyInt());
+ verify(l, times(1)).unblockAlarmsForUid(eq(UID_10_1));
verify(l, times(0)).unblockAlarmsForUidPackage(anyInt(), anyString());
reset(l);
@@ -723,7 +744,7 @@ public class ForceAppStandbyTrackerTest {
verify(l, times(0)).updateJobsForUidPackage(anyInt(), anyString());
verify(l, times(0)).unblockAllUnrestrictedAlarms();
- verify(l, times(0)).unblockAlarmsForUid(anyInt());
+ verify(l, times(1)).unblockAlarmsForUid(eq(UID_10_1));
verify(l, times(0)).unblockAlarmsForUidPackage(anyInt(), anyString());
reset(l);
@@ -743,6 +764,15 @@ public class ForceAppStandbyTrackerTest {
mPowerSaveMode = false;
mPowerSaveObserver.accept(getPowerSaveState());
+ verify(l, times(1)).updateAllJobs();
+ verify(l, times(0)).updateJobsForUid(eq(UID_10_1));
+ verify(l, times(0)).updateJobsForUidPackage(anyInt(), anyString());
+
+ verify(l, times(1)).unblockAllUnrestrictedAlarms();
+ verify(l, times(0)).unblockAlarmsForUid(anyInt());
+ verify(l, times(0)).unblockAlarmsForUidPackage(anyInt(), anyString());
+ reset(l);
+
mIUidObserver.onUidActive(UID_10_1);
waitUntilMainHandlerDrain();
@@ -751,7 +781,7 @@ public class ForceAppStandbyTrackerTest {
verify(l, times(0)).updateJobsForUidPackage(anyInt(), anyString());
verify(l, times(0)).unblockAllUnrestrictedAlarms();
- verify(l, times(0)).unblockAlarmsForUid(anyInt());
+ verify(l, times(1)).unblockAlarmsForUid(eq(UID_10_1));
verify(l, times(0)).unblockAlarmsForUidPackage(anyInt(), anyString());
reset(l);
@@ -775,7 +805,7 @@ public class ForceAppStandbyTrackerTest {
verify(l, times(0)).updateJobsForUidPackage(anyInt(), anyString());
verify(l, times(0)).unblockAllUnrestrictedAlarms();
- verify(l, times(0)).unblockAlarmsForUid(anyInt());
+ verify(l, times(1)).unblockAlarmsForUid(eq(UID_10_1));
verify(l, times(0)).unblockAlarmsForUidPackage(anyInt(), anyString());
reset(l);
diff --git a/services/tests/servicestests/src/com/android/server/NetworkPolicyManagerServiceTest.java b/services/tests/servicestests/src/com/android/server/NetworkPolicyManagerServiceTest.java
index fbcccf0fec2a..7c3082fb93de 100644
--- a/services/tests/servicestests/src/com/android/server/NetworkPolicyManagerServiceTest.java
+++ b/services/tests/servicestests/src/com/android/server/NetworkPolicyManagerServiceTest.java
@@ -18,6 +18,7 @@ package com.android.server;
import static android.net.ConnectivityManager.CONNECTIVITY_ACTION;
import static android.net.ConnectivityManager.TYPE_WIFI;
+import static android.net.NetworkCapabilities.TRANSPORT_CELLULAR;
import static android.net.NetworkPolicy.LIMIT_DISABLED;
import static android.net.NetworkPolicy.SNOOZE_NEVER;
import static android.net.NetworkPolicy.WARNING_DISABLED;
@@ -34,6 +35,7 @@ import static android.telephony.CarrierConfigManager.DATA_CYCLE_USE_PLATFORM_DEF
import static android.telephony.CarrierConfigManager.KEY_DATA_LIMIT_THRESHOLD_BYTES_LONG;
import static android.telephony.CarrierConfigManager.KEY_DATA_WARNING_THRESHOLD_BYTES_LONG;
import static android.telephony.CarrierConfigManager.KEY_MONTHLY_DATA_CYCLE_DAY_INT;
+import static android.telephony.SubscriptionPlan.LIMIT_BEHAVIOR_THROTTLED;
import static android.text.format.DateUtils.MINUTE_IN_MILLIS;
import static android.text.format.Time.TIMEZONE_UTC;
@@ -62,6 +64,7 @@ import static org.mockito.Mockito.atLeastOnce;
import static org.mockito.Mockito.doAnswer;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.reset;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
@@ -86,13 +89,16 @@ import android.net.INetworkManagementEventObserver;
import android.net.INetworkPolicyListener;
import android.net.INetworkStatsService;
import android.net.LinkProperties;
+import android.net.Network;
import android.net.NetworkCapabilities;
import android.net.NetworkInfo;
import android.net.NetworkInfo.DetailedState;
import android.net.NetworkPolicy;
import android.net.NetworkState;
import android.net.NetworkStats;
+import android.net.NetworkStatsHistory;
import android.net.NetworkTemplate;
+import android.net.StringNetworkSpecifier;
import android.os.Binder;
import android.os.INetworkManagementService;
import android.os.PersistableBundle;
@@ -105,9 +111,11 @@ import android.support.test.filters.MediumTest;
import android.support.test.runner.AndroidJUnit4;
import android.telephony.CarrierConfigManager;
import android.telephony.SubscriptionManager;
+import android.telephony.SubscriptionPlan;
import android.telephony.TelephonyManager;
import android.text.TextUtils;
import android.text.format.Time;
+import android.util.DataUnit;
import android.util.Log;
import android.util.Pair;
import android.util.RecurrenceRule;
@@ -186,6 +194,7 @@ public class NetworkPolicyManagerServiceTest {
private static final long TEST_START = 1194220800000L;
private static final String TEST_IFACE = "test0";
private static final String TEST_SSID = "AndroidAP";
+ private static final String TEST_IMSI = "310210";
private static NetworkTemplate sTemplateWifi = NetworkTemplate.buildTemplateWifi(TEST_SSID);
@@ -309,6 +318,11 @@ public class NetworkPolicyManagerServiceTest {
return super.getSystemService(name);
}
}
+
+ @Override
+ public void enforceCallingOrSelfPermission(String permission, String message) {
+ // Assume that we're AID_SYSTEM
+ }
};
setNetpolicyXml(context);
@@ -1065,6 +1079,67 @@ public class NetworkPolicyManagerServiceTest {
}
@Test
+ public void testRapidNotification() throws Exception {
+ // Create a place to store fake usage
+ final NetworkStatsHistory history = new NetworkStatsHistory(TimeUnit.HOURS.toMillis(1));
+ when(mStatsService.getNetworkTotalBytes(any(), anyLong(), anyLong()))
+ .thenAnswer(new Answer<Long>() {
+ @Override
+ public Long answer(InvocationOnMock invocation) throws Throwable {
+ final NetworkStatsHistory.Entry entry = history.getValues(
+ invocation.getArgument(1), invocation.getArgument(2), null);
+ return entry.rxBytes + entry.txBytes;
+ }
+ });
+
+ // Define simple data plan which gives us effectively 60MB/day
+ final SubscriptionPlan plan = SubscriptionPlan.Builder
+ .createRecurringMonthly(ZonedDateTime.parse("2015-11-01T00:00:00.00Z"))
+ .setDataLimit(DataUnit.MEGABYTES.toBytes(1800), LIMIT_BEHAVIOR_THROTTLED)
+ .build();
+ mService.setSubscriptionPlans(42, new SubscriptionPlan[] { plan },
+ mServiceContext.getOpPackageName());
+
+ // And get that active network in place
+ when(mConnManager.getAllNetworkState()).thenReturn(new NetworkState[] {
+ new NetworkState(null, new LinkProperties(),
+ new NetworkCapabilities().addTransportType(TRANSPORT_CELLULAR)
+ .setNetworkSpecifier(new StringNetworkSpecifier("42")),
+ new Network(42), TEST_IMSI, null)
+ });
+ mService.updateNetworks();
+
+ // We're 20% through the month (6 days)
+ final long start = parseTime("2015-11-01T00:00Z");
+ final long end = parseTime("2015-11-07T00:00Z");
+ setCurrentTimeMillis(end);
+
+ // Using 20% of data in 20% is normal
+ {
+ history.removeBucketsBefore(Long.MAX_VALUE);
+ history.recordData(start, end,
+ new NetworkStats.Entry(DataUnit.MEGABYTES.toBytes(360), 0L, 0L, 0L, 0));
+
+ reset(mNotifManager);
+ mService.updateNotifications();
+ verify(mNotifManager, never()).enqueueNotificationWithTag(any(), any(), any(),
+ anyInt(), any(), anyInt());
+ }
+
+ // Using 80% data in 20% time is alarming
+ {
+ history.removeBucketsBefore(Long.MAX_VALUE);
+ history.recordData(start, end,
+ new NetworkStats.Entry(DataUnit.MEGABYTES.toBytes(1440), 0L, 0L, 0L, 0));
+
+ reset(mNotifManager);
+ mService.updateNotifications();
+ verify(mNotifManager, atLeastOnce()).enqueueNotificationWithTag(any(), any(), any(),
+ anyInt(), any(), anyInt());
+ }
+ }
+
+ @Test
public void testMeteredNetworkWithoutLimit() throws Exception {
NetworkState[] state = null;
NetworkStats stats = null;
diff --git a/services/tests/servicestests/src/com/android/server/accessibility/GlobalActionPerformerTest.java b/services/tests/servicestests/src/com/android/server/accessibility/GlobalActionPerformerTest.java
index 1213e814b3fa..e72e4601bbe8 100644
--- a/services/tests/servicestests/src/com/android/server/accessibility/GlobalActionPerformerTest.java
+++ b/services/tests/servicestests/src/com/android/server/accessibility/GlobalActionPerformerTest.java
@@ -16,13 +16,18 @@
package com.android.server.accessibility;
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.anyBoolean;
+import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
import android.accessibilityservice.AccessibilityService;
import android.app.StatusBarManager;
import android.content.Context;
+import android.os.Handler;
+import com.android.internal.util.ScreenshotHelper;
import com.android.server.wm.WindowManagerInternal;
import org.junit.Before;
@@ -39,6 +44,7 @@ public class GlobalActionPerformerTest {
@Mock Context mMockContext;
@Mock WindowManagerInternal mMockWindowManagerInternal;
@Mock StatusBarManager mMockStatusBarManager;
+ @Mock ScreenshotHelper mMockScreenshotHelper;
@Before
public void setup() {
@@ -48,7 +54,8 @@ public class GlobalActionPerformerTest {
.thenReturn(mMockStatusBarManager);
mGlobalActionPerformer =
- new GlobalActionPerformer(mMockContext, mMockWindowManagerInternal);
+ new GlobalActionPerformer(mMockContext, mMockWindowManagerInternal,
+ () -> mMockScreenshotHelper);
}
@Test
@@ -70,4 +77,13 @@ public class GlobalActionPerformerTest {
mGlobalActionPerformer.performGlobalAction(AccessibilityService.GLOBAL_ACTION_POWER_DIALOG);
verify(mMockWindowManagerInternal).showGlobalActions();
}
+
+ @Test
+ public void testScreenshot_requestsFromScreenshotHelper() {
+ mGlobalActionPerformer.performGlobalAction(
+ AccessibilityService.GLOBAL_ACTION_TAKE_SCREENSHOT);
+ verify(mMockScreenshotHelper).takeScreenshot(
+ eq(android.view.WindowManager.TAKE_SCREENSHOT_FULLSCREEN), anyBoolean(),
+ anyBoolean(), any(Handler.class));
+ }
}
diff --git a/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerServiceTestable.java b/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerServiceTestable.java
index 5134f523a8ff..06f138ba898b 100644
--- a/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerServiceTestable.java
+++ b/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerServiceTestable.java
@@ -45,6 +45,7 @@ import android.view.IWindowManager;
import com.android.internal.util.FunctionalUtils.ThrowingRunnable;
import com.android.internal.widget.LockPatternUtils;
+import com.android.server.net.NetworkPolicyManagerInternal;
import java.io.File;
import java.io.IOException;
@@ -159,6 +160,11 @@ public class DevicePolicyManagerServiceTestable extends DevicePolicyManagerServi
}
@Override
+ NetworkPolicyManagerInternal getNetworkPolicyManagerInternal() {
+ return services.networkPolicyManagerInternal;
+ }
+
+ @Override
PackageManagerInternal getPackageManagerInternal() {
return services.packageManagerInternal;
}
@@ -438,5 +444,10 @@ public class DevicePolicyManagerServiceTestable extends DevicePolicyManagerServi
KeyChain.KeyChainConnection keyChainBindAsUser(UserHandle user) {
return services.keyChainConnection;
}
+
+ @Override
+ void postOnSystemServerInitThreadPool(Runnable runnable) {
+ runnable.run();
+ }
}
}
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 1df0ff23f847..d26a3c7b64d4 100644
--- a/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java
+++ b/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java
@@ -186,6 +186,7 @@ public class DevicePolicyManagerTest extends DpmTestBase {
initializeDpms();
Mockito.reset(getServices().usageStatsManagerInternal);
+ Mockito.reset(getServices().networkPolicyManagerInternal);
setUpPackageManagerForAdmin(admin1, DpmMockContext.CALLER_UID);
setUpPackageManagerForAdmin(admin2, DpmMockContext.CALLER_UID);
setUpPackageManagerForAdmin(admin3, DpmMockContext.CALLER_UID);
@@ -211,7 +212,6 @@ public class DevicePolicyManagerTest extends DpmTestBase {
LocalServices.removeServiceForTest(DevicePolicyManagerInternal.class);
dpms = new DevicePolicyManagerServiceTestable(getServices(), mContext);
- dpms.handleStart();
dpms.systemReady(SystemService.PHASE_LOCK_SETTINGS_READY);
dpms.systemReady(SystemService.PHASE_BOOT_COMPLETED);
@@ -283,7 +283,7 @@ public class DevicePolicyManagerTest extends DpmTestBase {
assertNull(LocalServices.getService(DevicePolicyManagerInternal.class));
}
- public void testHandleStart() throws Exception {
+ public void testLoadAdminData() throws Exception {
// Device owner in SYSTEM_USER
setDeviceOwner();
// Profile owner in CALLER_USER_HANDLE
@@ -307,6 +307,23 @@ public class DevicePolicyManagerTest extends DpmTestBase {
MockUtils.checkAdminApps(admin2.getPackageName(),
adminAnotherPackage.getPackageName()),
eq(DpmMockContext.CALLER_USER_HANDLE));
+ verify(getServices().usageStatsManagerInternal).onAdminDataAvailable();
+ verify(getServices().networkPolicyManagerInternal).onAdminDataAvailable();
+ }
+
+ public void testLoadAdminData_noAdmins() throws Exception {
+ final int ANOTHER_USER_ID = 15;
+ getServices().addUser(ANOTHER_USER_ID, 0);
+
+ initializeDpms();
+
+ // Verify
+ verify(getServices().usageStatsManagerInternal).setActiveAdminApps(
+ null, DpmMockContext.CALLER_USER_HANDLE);
+ verify(getServices().usageStatsManagerInternal).setActiveAdminApps(
+ null, ANOTHER_USER_ID);
+ verify(getServices().usageStatsManagerInternal).onAdminDataAvailable();
+ verify(getServices().networkPolicyManagerInternal).onAdminDataAvailable();
}
/**
diff --git a/services/tests/servicestests/src/com/android/server/devicepolicy/MockSystemServices.java b/services/tests/servicestests/src/com/android/server/devicepolicy/MockSystemServices.java
index 268d424734e2..0343a52e05da 100644
--- a/services/tests/servicestests/src/com/android/server/devicepolicy/MockSystemServices.java
+++ b/services/tests/servicestests/src/com/android/server/devicepolicy/MockSystemServices.java
@@ -58,6 +58,7 @@ import android.view.IWindowManager;
import com.android.internal.util.test.FakeSettingsProvider;
import com.android.internal.widget.LockPatternUtils;
+import com.android.server.net.NetworkPolicyManagerInternal;
import java.io.File;
import java.io.IOException;
@@ -76,6 +77,7 @@ public class MockSystemServices {
public final UserManager userManager;
public final UserManagerInternal userManagerInternal;
public final UsageStatsManagerInternal usageStatsManagerInternal;
+ public final NetworkPolicyManagerInternal networkPolicyManagerInternal;
public final PackageManagerInternal packageManagerInternal;
public final UserManagerForMock userManagerForMock;
public final PowerManagerForMock powerManager;
@@ -113,6 +115,8 @@ public class MockSystemServices {
userManager = mock(UserManager.class);
userManagerInternal = mock(UserManagerInternal.class);
usageStatsManagerInternal = mock(UsageStatsManagerInternal.class);
+ networkPolicyManagerInternal = mock(NetworkPolicyManagerInternal.class);
+
userManagerForMock = mock(UserManagerForMock.class);
packageManagerInternal = mock(PackageManagerInternal.class);
powerManager = mock(PowerManagerForMock.class);
diff --git a/services/tests/servicestests/src/com/android/server/job/JobStoreTest.java b/services/tests/servicestests/src/com/android/server/job/JobStoreTest.java
index d8e3be951bd0..43d026d8efc3 100644
--- a/services/tests/servicestests/src/com/android/server/job/JobStoreTest.java
+++ b/services/tests/servicestests/src/com/android/server/job/JobStoreTest.java
@@ -6,12 +6,17 @@ import static android.net.NetworkCapabilities.TRANSPORT_WIFI;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;
+import static org.mockito.ArgumentMatchers.anyString;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.when;
import android.app.job.JobInfo;
import android.app.job.JobInfo.Builder;
import android.content.ComponentName;
import android.content.Context;
+import android.content.pm.PackageManagerInternal;
import android.net.NetworkRequest;
+import android.os.Build;
import android.os.Parcel;
import android.os.Parcelable;
import android.os.PersistableBundle;
@@ -24,6 +29,7 @@ import android.util.Pair;
import com.android.internal.util.HexDump;
import com.android.server.IoThread;
+import com.android.server.LocalServices;
import com.android.server.job.JobStore.JobSet;
import com.android.server.job.controllers.JobStatus;
@@ -65,6 +71,13 @@ public class JobStoreTest {
JobStore.initAndGetForTesting(mTestContext, mTestContext.getFilesDir());
mComponent = new ComponentName(getContext().getPackageName(), StubClass.class.getName());
+ // Assume all packages are current SDK
+ final PackageManagerInternal pm = mock(PackageManagerInternal.class);
+ when(pm.getPackageTargetSdkVersion(anyString()))
+ .thenReturn(Build.VERSION_CODES.CUR_DEVELOPMENT);
+ LocalServices.removeServiceForTest(PackageManagerInternal.class);
+ LocalServices.addService(PackageManagerInternal.class, pm);
+
// Freeze the clocks at this moment in time
JobSchedulerService.sSystemClock =
Clock.fixed(Clock.systemUTC().instant(), ZoneOffset.UTC);
diff --git a/services/tests/servicestests/src/com/android/server/job/controllers/ConnectivityControllerTest.java b/services/tests/servicestests/src/com/android/server/job/controllers/ConnectivityControllerTest.java
new file mode 100644
index 000000000000..f6a749df1df6
--- /dev/null
+++ b/services/tests/servicestests/src/com/android/server/job/controllers/ConnectivityControllerTest.java
@@ -0,0 +1,169 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License
+ */
+
+package com.android.server.job.controllers;
+
+import static android.net.NetworkCapabilities.NET_CAPABILITY_INTERNET;
+import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_CONGESTED;
+import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_METERED;
+import static android.net.NetworkCapabilities.NET_CAPABILITY_VALIDATED;
+
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+import static org.mockito.ArgumentMatchers.anyString;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.when;
+
+import android.app.job.JobInfo;
+import android.content.ComponentName;
+import android.content.pm.PackageManagerInternal;
+import android.net.Network;
+import android.net.NetworkCapabilities;
+import android.os.Build;
+import android.os.SystemClock;
+import android.support.test.runner.AndroidJUnit4;
+import android.util.DataUnit;
+
+import com.android.server.LocalServices;
+import com.android.server.job.JobSchedulerService;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import java.time.Clock;
+import java.time.ZoneOffset;
+
+@RunWith(AndroidJUnit4.class)
+public class ConnectivityControllerTest {
+ @Before
+ public void setUp() throws Exception {
+ // Assume all packages are current SDK
+ final PackageManagerInternal pm = mock(PackageManagerInternal.class);
+ when(pm.getPackageTargetSdkVersion(anyString()))
+ .thenReturn(Build.VERSION_CODES.CUR_DEVELOPMENT);
+ LocalServices.removeServiceForTest(PackageManagerInternal.class);
+ LocalServices.addService(PackageManagerInternal.class, pm);
+
+ // Freeze the clocks at this moment in time
+ JobSchedulerService.sSystemClock =
+ Clock.fixed(Clock.systemUTC().instant(), ZoneOffset.UTC);
+ JobSchedulerService.sUptimeMillisClock =
+ Clock.fixed(SystemClock.uptimeMillisClock().instant(), ZoneOffset.UTC);
+ JobSchedulerService.sElapsedRealtimeClock =
+ Clock.fixed(SystemClock.elapsedRealtimeClock().instant(), ZoneOffset.UTC);
+ }
+
+ @Test
+ public void testInsane() throws Exception {
+ final Network network = new Network(101);
+ final JobInfo.Builder job = createJob()
+ .setEstimatedNetworkBytes(DataUnit.MEBIBYTES.toBytes(1))
+ .setRequiredNetworkType(JobInfo.NETWORK_TYPE_ANY);
+
+ // Slow network is too slow
+ assertFalse(ConnectivityController.isSatisfied(createJobStatus(job), network,
+ createCapabilities().setLinkUpstreamBandwidthKbps(1)
+ .setLinkDownstreamBandwidthKbps(1)));
+ // Fast network looks great
+ assertTrue(ConnectivityController.isSatisfied(createJobStatus(job), network,
+ createCapabilities().setLinkUpstreamBandwidthKbps(1024)
+ .setLinkDownstreamBandwidthKbps(1024)));
+ }
+
+ @Test
+ public void testCongestion() throws Exception {
+ final long now = JobSchedulerService.sElapsedRealtimeClock.millis();
+ final JobInfo.Builder job = createJob()
+ .setEstimatedNetworkBytes(DataUnit.MEBIBYTES.toBytes(1))
+ .setRequiredNetworkType(JobInfo.NETWORK_TYPE_ANY);
+ final JobStatus early = createJobStatus(job, now - 1000, now + 2000);
+ final JobStatus late = createJobStatus(job, now - 2000, now + 1000);
+
+ // Uncongested network is whenever
+ {
+ final Network network = new Network(101);
+ final NetworkCapabilities capabilities = createCapabilities()
+ .addCapability(NET_CAPABILITY_NOT_CONGESTED);
+ assertTrue(ConnectivityController.isSatisfied(early, network, capabilities));
+ assertTrue(ConnectivityController.isSatisfied(late, network, capabilities));
+ }
+
+ // Congested network is more selective
+ {
+ final Network network = new Network(101);
+ final NetworkCapabilities capabilities = createCapabilities();
+ assertFalse(ConnectivityController.isSatisfied(early, network, capabilities));
+ assertTrue(ConnectivityController.isSatisfied(late, network, capabilities));
+ }
+ }
+
+ @Test
+ public void testRelaxed() throws Exception {
+ final long now = JobSchedulerService.sElapsedRealtimeClock.millis();
+ final JobInfo.Builder job = createJob()
+ .setEstimatedNetworkBytes(DataUnit.MEBIBYTES.toBytes(1))
+ .setRequiredNetworkType(JobInfo.NETWORK_TYPE_UNMETERED);
+ final JobStatus early = createJobStatus(job, now - 1000, now + 2000);
+ final JobStatus late = createJobStatus(job, now - 2000, now + 1000);
+
+ job.setIsPrefetch(true);
+ final JobStatus earlyPrefetch = createJobStatus(job, now - 1000, now + 2000);
+ final JobStatus latePrefetch = createJobStatus(job, now - 2000, now + 1000);
+
+ // Unmetered network is whenever
+ {
+ final Network network = new Network(101);
+ final NetworkCapabilities capabilities = createCapabilities()
+ .addCapability(NET_CAPABILITY_NOT_CONGESTED)
+ .addCapability(NET_CAPABILITY_NOT_METERED);
+ assertTrue(ConnectivityController.isSatisfied(early, network, capabilities));
+ assertTrue(ConnectivityController.isSatisfied(late, network, capabilities));
+ assertTrue(ConnectivityController.isSatisfied(earlyPrefetch, network, capabilities));
+ assertTrue(ConnectivityController.isSatisfied(latePrefetch, network, capabilities));
+ }
+
+ // Metered network is only when prefetching and late
+ {
+ final Network network = new Network(101);
+ final NetworkCapabilities capabilities = createCapabilities()
+ .addCapability(NET_CAPABILITY_NOT_CONGESTED);
+ assertFalse(ConnectivityController.isSatisfied(early, network, capabilities));
+ assertFalse(ConnectivityController.isSatisfied(late, network, capabilities));
+ assertFalse(ConnectivityController.isSatisfied(earlyPrefetch, network, capabilities));
+ assertTrue(ConnectivityController.isSatisfied(latePrefetch, network, capabilities));
+ }
+ }
+
+ private static NetworkCapabilities createCapabilities() {
+ return new NetworkCapabilities().addCapability(NET_CAPABILITY_INTERNET)
+ .addCapability(NET_CAPABILITY_VALIDATED);
+ }
+
+ private static JobInfo.Builder createJob() {
+ return new JobInfo.Builder(101, new ComponentName("foo", "bar"));
+ }
+
+ private static JobStatus createJobStatus(JobInfo.Builder job) {
+ return createJobStatus(job, 0, Long.MAX_VALUE);
+ }
+
+ private static JobStatus createJobStatus(JobInfo.Builder job, long earliestRunTimeElapsedMillis,
+ long latestRunTimeElapsedMillis) {
+ return new JobStatus(job.build(), 0, null, -1, 0, 0, null, earliestRunTimeElapsedMillis,
+ latestRunTimeElapsedMillis, 0, 0, null);
+ }
+}
diff --git a/services/tests/servicestests/src/com/android/server/job/controllers/JobStatusTest.java b/services/tests/servicestests/src/com/android/server/job/controllers/JobStatusTest.java
new file mode 100644
index 000000000000..15c24ac7efd6
--- /dev/null
+++ b/services/tests/servicestests/src/com/android/server/job/controllers/JobStatusTest.java
@@ -0,0 +1,76 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License
+ */
+
+package com.android.server.job.controllers;
+
+import static org.junit.Assert.assertEquals;
+
+import android.app.job.JobInfo;
+import android.content.ComponentName;
+import android.os.SystemClock;
+import android.support.test.runner.AndroidJUnit4;
+
+import com.android.server.job.JobSchedulerService;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import java.time.Clock;
+import java.time.ZoneOffset;
+
+@RunWith(AndroidJUnit4.class)
+public class JobStatusTest {
+ private static final double DELTA = 0.00001;
+
+ @Before
+ public void setUp() throws Exception {
+ // Freeze the clocks at this moment in time
+ JobSchedulerService.sSystemClock =
+ Clock.fixed(Clock.systemUTC().instant(), ZoneOffset.UTC);
+ JobSchedulerService.sUptimeMillisClock =
+ Clock.fixed(SystemClock.uptimeMillisClock().instant(), ZoneOffset.UTC);
+ JobSchedulerService.sElapsedRealtimeClock =
+ Clock.fixed(SystemClock.elapsedRealtimeClock().instant(), ZoneOffset.UTC);
+ }
+
+ @Test
+ public void testFraction() throws Exception {
+ final long now = JobSchedulerService.sElapsedRealtimeClock.millis();
+
+ assertEquals(1, createJobStatus(0, Long.MAX_VALUE).getFractionRunTime(), DELTA);
+
+ assertEquals(1, createJobStatus(0, now - 1000).getFractionRunTime(), DELTA);
+ assertEquals(0, createJobStatus(0, now + 1000).getFractionRunTime(), DELTA);
+
+ assertEquals(1, createJobStatus(now - 1000, Long.MAX_VALUE).getFractionRunTime(), DELTA);
+ assertEquals(0, createJobStatus(now + 1000, Long.MAX_VALUE).getFractionRunTime(), DELTA);
+
+ assertEquals(0, createJobStatus(now, now + 2000).getFractionRunTime(), DELTA);
+ assertEquals(0.25, createJobStatus(now - 500, now + 1500).getFractionRunTime(), DELTA);
+ assertEquals(0.5, createJobStatus(now - 1000, now + 1000).getFractionRunTime(), DELTA);
+ assertEquals(0.75, createJobStatus(now - 1500, now + 500).getFractionRunTime(), DELTA);
+ assertEquals(1, createJobStatus(now - 2000, now).getFractionRunTime(), DELTA);
+ }
+
+ private static JobStatus createJobStatus(long earliestRunTimeElapsedMillis,
+ long latestRunTimeElapsedMillis) {
+ final JobInfo job = new JobInfo.Builder(101, new ComponentName("foo", "bar"))
+ .setRequiredNetworkType(JobInfo.NETWORK_TYPE_ANY).build();
+ return new JobStatus(job, 0, null, -1, 0, 0, null, earliestRunTimeElapsedMillis,
+ latestRunTimeElapsedMillis, 0, 0, null);
+ }
+}
diff --git a/services/tests/servicestests/src/com/android/server/locksettings/recoverablekeystore/KeySyncTaskTest.java b/services/tests/servicestests/src/com/android/server/locksettings/recoverablekeystore/KeySyncTaskTest.java
index c6fc675db6b1..7eec4fea64dc 100644
--- a/services/tests/servicestests/src/com/android/server/locksettings/recoverablekeystore/KeySyncTaskTest.java
+++ b/services/tests/servicestests/src/com/android/server/locksettings/recoverablekeystore/KeySyncTaskTest.java
@@ -78,7 +78,7 @@ public class KeySyncTaskTest {
private static final int TEST_RECOVERY_AGENT_UID = 10009;
private static final int TEST_RECOVERY_AGENT_UID2 = 10010;
private static final byte[] TEST_VAULT_HANDLE =
- new byte[]{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 14, 15, 16, 17};
+ new byte[]{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17};
private static final String TEST_APP_KEY_ALIAS = "rcleaver";
private static final int TEST_GENERATION_ID = 2;
private static final int TEST_CREDENTIAL_TYPE = CREDENTIAL_TYPE_PASSWORD;
@@ -278,9 +278,13 @@ public class KeySyncTaskTest {
public void run_sendsEncryptedKeysIfAvailableToSync() throws Exception {
mRecoverableKeyStoreDb.setRecoveryServicePublicKey(
TEST_USER_ID, TEST_RECOVERY_AGENT_UID, mKeyPair.getPublic());
+
+ mRecoverableKeyStoreDb.setServerParams(
+ TEST_USER_ID, TEST_RECOVERY_AGENT_UID, TEST_VAULT_HANDLE);
when(mSnapshotListenersStorage.hasListener(TEST_RECOVERY_AGENT_UID)).thenReturn(true);
SecretKey applicationKey =
addApplicationKey(TEST_USER_ID, TEST_RECOVERY_AGENT_UID, TEST_APP_KEY_ALIAS);
+
mKeySyncTask.run();
KeychainSnapshot keychainSnapshot = mRecoverySnapshotStorage.get(TEST_RECOVERY_AGENT_UID);
@@ -293,6 +297,7 @@ public class KeySyncTaskTest {
KeyDerivationParams.getSalt(),
TEST_CREDENTIAL);
Long counterId = mRecoverableKeyStoreDb.getCounterId(TEST_USER_ID, TEST_RECOVERY_AGENT_UID);
+ counterId = 1L; // TODO: use value from the database.
assertThat(counterId).isNotNull();
byte[] recoveryKey = decryptThmEncryptedKey(
lockScreenHash,
@@ -304,6 +309,11 @@ public class KeySyncTaskTest {
TEST_VAULT_HANDLE));
List<WrappedApplicationKey> applicationKeys = keychainSnapshot.getWrappedApplicationKeys();
assertThat(applicationKeys).hasSize(1);
+ assertThat(keychainSnapshot.getCounterId()).isEqualTo(counterId);
+ assertThat(keychainSnapshot.getMaxAttempts()).isEqualTo(10);
+ assertThat(keychainSnapshot.getTrustedHardwarePublicKey())
+ .isEqualTo(SecureBox.encodePublicKey(mKeyPair.getPublic()));
+ assertThat(keychainSnapshot.getServerParams()).isEqualTo(TEST_VAULT_HANDLE);
WrappedApplicationKey keyData = applicationKeys.get(0);
assertEquals(TEST_APP_KEY_ALIAS, keyData.getAlias());
assertThat(keyData.getAlias()).isEqualTo(keyData.getAlias());
diff --git a/services/tests/servicestests/src/com/android/server/locksettings/recoverablekeystore/KeySyncUtilsTest.java b/services/tests/servicestests/src/com/android/server/locksettings/recoverablekeystore/KeySyncUtilsTest.java
index ba6b274b83b8..a251c9d7898e 100644
--- a/services/tests/servicestests/src/com/android/server/locksettings/recoverablekeystore/KeySyncUtilsTest.java
+++ b/services/tests/servicestests/src/com/android/server/locksettings/recoverablekeystore/KeySyncUtilsTest.java
@@ -51,7 +51,7 @@ public class KeySyncUtilsTest {
private static final int THM_KF_HASH_SIZE = 256;
private static final int KEY_CLAIMANT_LENGTH_BYTES = 16;
private static final byte[] TEST_VAULT_HANDLE =
- new byte[]{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 14, 15, 16, 17};
+ new byte[]{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17};
private static final String SHA_256_ALGORITHM = "SHA-256";
private static final String APPLICATION_KEY_ALGORITHM = "AES";
private static final byte[] LOCK_SCREEN_HASH_1 =
@@ -417,8 +417,7 @@ public class KeySyncUtilsTest {
byteBuffer.position(PUBLIC_KEY_LENGTH_BYTES + Long.BYTES + Integer.BYTES);
byte[] vaultHandle = new byte[VAULT_HANDLE_LENGTH_BYTES];
byteBuffer.get(vaultHandle);
- // TODO: Fix this once we fix the code in the KeySyncUtils class
- assertArrayEquals(new byte[VAULT_HANDLE_LENGTH_BYTES], vaultHandle);
+ assertArrayEquals(TEST_VAULT_HANDLE, vaultHandle);
}
private static byte[] randomBytes(int n) {
diff --git a/services/tests/servicestests/src/com/android/server/locksettings/recoverablekeystore/RecoverableKeyStoreManagerTest.java b/services/tests/servicestests/src/com/android/server/locksettings/recoverablekeystore/RecoverableKeyStoreManagerTest.java
index 402a37c420a7..970bc33337da 100644
--- a/services/tests/servicestests/src/com/android/server/locksettings/recoverablekeystore/RecoverableKeyStoreManagerTest.java
+++ b/services/tests/servicestests/src/com/android/server/locksettings/recoverablekeystore/RecoverableKeyStoreManagerTest.java
@@ -330,7 +330,7 @@ public class RecoverableKeyStoreManagerTest {
TEST_VAULT_CHALLENGE,
ImmutableList.of());
fail("should have thrown");
- } catch (ServiceSpecificException e) {
+ } catch (UnsupportedOperationException e) {
assertThat(e.getMessage()).startsWith(
"Only a single KeychainProtectionParams is supported");
}
diff --git a/services/tests/servicestests/src/com/android/server/locksettings/recoverablekeystore/storage/RecoverySessionStorageTest.java b/services/tests/servicestests/src/com/android/server/locksettings/recoverablekeystore/storage/RecoverySessionStorageTest.java
index 0f95748a8ea7..bb0474efee58 100644
--- a/services/tests/servicestests/src/com/android/server/locksettings/recoverablekeystore/storage/RecoverySessionStorageTest.java
+++ b/services/tests/servicestests/src/com/android/server/locksettings/recoverablekeystore/storage/RecoverySessionStorageTest.java
@@ -125,7 +125,7 @@ public class RecoverySessionStorageTest {
storage.remove(TEST_USER_ID, TEST_SESSION_ID);
- assertNotNull(storage.get(TEST_USER_ID, TEST_SESSION_ID));
+ assertNotNull(storage.get(TEST_USER_ID, otherSessionId));
}
@Test
diff --git a/services/tests/servicestests/src/com/android/server/net/watchlist/PrivacyUtilsTests.java b/services/tests/servicestests/src/com/android/server/net/watchlist/PrivacyUtilsTests.java
new file mode 100644
index 000000000000..a31b46ce5534
--- /dev/null
+++ b/services/tests/servicestests/src/com/android/server/net/watchlist/PrivacyUtilsTests.java
@@ -0,0 +1,105 @@
+/*
+ * Copyright 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.net.watchlist;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+
+import android.privacy.DifferentialPrivacyEncoder;
+import android.support.test.filters.SmallTest;
+import android.support.test.runner.AndroidJUnit4;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import java.util.Arrays;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
+
+/**
+ * runtest frameworks-services -c com.android.server.net.watchlist.PrivacyUtilsTests
+ */
+@RunWith(AndroidJUnit4.class)
+@SmallTest
+public class PrivacyUtilsTests {
+
+ private static final List<String> TEST_DIGEST_LIST = Arrays.asList(
+ "B86F9D37425340B635F43D6BC2506630761ADA71F5E6BBDBCA4651C479F9FB43",
+ "E86F9D37425340B635F43D6BC2506630761ADA71F5E6BBDBCA4651C479F9FB45",
+ "C86F9D37425340B635F43D6BC2506630761ADA71F5E6BBDBCA4651C479F9FB44",
+ "C86F9D37425340B635F43D6BC2506630761ADA71F5E6BBDBCA4651C479F9FB47",
+ "C86F9D37425340B635F43D6BC2506630761ADA71F5E6BBDBCA4651C479F9FB48",
+ "C86F9D37425340B635F43D6BC2506630761ADA71F5E6BBDBCA4651C479F9FB49");
+
+ private static final WatchlistReportDbHelper.AggregatedResult TEST_AGGREGATED_RESULT1 =
+ new WatchlistReportDbHelper.AggregatedResult(new HashSet<>(Arrays.asList(
+ "B86F9D37425340B635F43D6BC2506630761ADA71F5E6BBDBCA4651C479F9FB43",
+ "C86F9D37425340B635F43D6BC2506630761ADA71F5E6BBDBCA4651C479F9FB48",
+ "E86F9D37425340B635F43D6BC2506630761ADA71F5E6BBDBCA4651C479F9FB45")), null,
+ new HashMap<>());
+
+ private static final byte[] TEST_SECRET = new byte[]{
+ (byte) 0xD7, (byte) 0x68, (byte) 0x99, (byte) 0x93,
+ (byte) 0x94, (byte) 0x13, (byte) 0x53, (byte) 0x54,
+ (byte) 0xFE, (byte) 0xD0, (byte) 0x7E, (byte) 0x54,
+ (byte) 0xFE, (byte) 0xD0, (byte) 0x7E, (byte) 0x54,
+ (byte) 0xD7, (byte) 0x68, (byte) 0x99, (byte) 0x93,
+ (byte) 0x94, (byte) 0x13, (byte) 0x53, (byte) 0x54,
+ (byte) 0xFE, (byte) 0xD0, (byte) 0x7E, (byte) 0x54,
+ (byte) 0xFE, (byte) 0xD0, (byte) 0x7E, (byte) 0x54,
+ (byte) 0xD7, (byte) 0x68, (byte) 0x99, (byte) 0x93,
+ (byte) 0x94, (byte) 0x13, (byte) 0x53, (byte) 0x54,
+ (byte) 0xFE, (byte) 0xD0, (byte) 0x7E, (byte) 0x54,
+ (byte) 0xFE, (byte) 0xD0, (byte) 0x7E, (byte) 0x54
+ };
+
+ @Test
+ public void testPrivacyUtils_encodeReport() throws Exception {
+ Map<String, Boolean> result = PrivacyUtils.createDpEncodedReportMap(false, null,
+ TEST_DIGEST_LIST, TEST_AGGREGATED_RESULT1);
+ assertEquals(6, result.size());
+ assertTrue(result.get("C86F9D37425340B635F43D6BC2506630761ADA71F5E6BBDBCA4651C479F9FB48"));
+ assertTrue(result.get("C86F9D37425340B635F43D6BC2506630761ADA71F5E6BBDBCA4651C479F9FB49"));
+ assertFalse(result.get("C86F9D37425340B635F43D6BC2506630761ADA71F5E6BBDBCA4651C479F9FB47"));
+ assertTrue(result.get("E86F9D37425340B635F43D6BC2506630761ADA71F5E6BBDBCA4651C479F9FB45"));
+ assertFalse(result.get("C86F9D37425340B635F43D6BC2506630761ADA71F5E6BBDBCA4651C479F9FB44"));
+ assertTrue(result.get("B86F9D37425340B635F43D6BC2506630761ADA71F5E6BBDBCA4651C479F9FB43"));
+ }
+
+ @Test
+ public void testPrivacyUtils_createInsecureDPEncoderForTest() throws Exception {
+ DifferentialPrivacyEncoder encoder = PrivacyUtils.createInsecureDPEncoderForTest("foo");
+ assertEquals(
+ "EncoderId: watchlist_encoder:foo, ProbabilityF: 0.400, ProbabilityP: 0.250, "
+ + "ProbabilityQ: 1.000",
+ encoder.getConfig().toString());
+ assertTrue(encoder.isInsecureEncoderForTest());
+ }
+
+ @Test
+ public void testPrivacyUtils_createSecureDPEncoderTest() throws Exception {
+ DifferentialPrivacyEncoder encoder = PrivacyUtils.createSecureDPEncoder(TEST_SECRET, "foo");
+ assertEquals(
+ "EncoderId: watchlist_encoder:foo, ProbabilityF: 0.400, ProbabilityP: 0.250, "
+ + "ProbabilityQ: 1.000",
+ encoder.getConfig().toString());
+ assertFalse(encoder.isInsecureEncoderForTest());
+ }
+}
diff --git a/services/tests/servicestests/src/com/android/server/net/watchlist/ReportUtilsTests.java b/services/tests/servicestests/src/com/android/server/net/watchlist/ReportUtilsTests.java
new file mode 100644
index 000000000000..395969eb7c77
--- /dev/null
+++ b/services/tests/servicestests/src/com/android/server/net/watchlist/ReportUtilsTests.java
@@ -0,0 +1,119 @@
+/*
+ * Copyright 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.net.watchlist;
+
+import static org.junit.Assert.assertArrayEquals;
+
+import android.content.Context;
+import android.support.test.InstrumentationRegistry;
+import android.support.test.filters.SmallTest;
+import android.support.test.runner.AndroidJUnit4;
+
+import com.android.internal.util.HexDump;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import java.io.BufferedReader;
+import java.io.File;
+import java.io.FileWriter;
+import java.io.IOException;
+import java.io.InputStreamReader;
+import java.util.HashMap;
+
+/**
+ * runtest frameworks-services -c com.android.server.net.watchlist.ReportUtilsTests
+ */
+@RunWith(AndroidJUnit4.class)
+@SmallTest
+public class ReportUtilsTests {
+
+ private static final String TEST_XML_1 = "NetworkWatchlistTest/watchlist_config_test1.xml";
+ private static final String TEST_XML_1_HASH =
+ "C99F27A08B1FDB15B101098E12BB2A0AA0D474E23C50F24920A52AB2322BFD94";
+ private static final String REPORT_HEADER_MAGIC = "8D370AAC";
+ private static final String REPORT_HEADER_VERSION = "0001";
+
+ private Context mContext;
+ private File mTestXmlFile;
+
+ @Before
+ public void setUp() throws Exception {
+ mContext = InstrumentationRegistry.getContext();
+ mTestXmlFile = new File(mContext.getFilesDir(), "test_watchlist_config.xml");
+ mTestXmlFile.delete();
+ }
+
+ @After
+ public void tearDown() throws Exception {
+ mTestXmlFile.delete();
+ }
+
+ @Test
+ public void testReportUtils_serializeReport() throws Exception {
+ final byte[] expectedResult = HexDump.hexStringToByteArray(
+ REPORT_HEADER_MAGIC + REPORT_HEADER_VERSION + TEST_XML_1_HASH
+ + "B86F9D37425340B635F43D6BC2506630761ADA71F5E6BBDBCA4651C479F9FB43" + "01"
+ + "C86F9D37425340B635F43D6BC2506630761ADA71F5E6BBDBCA4651C479F9FB44" + "00"
+ + "D86F9D37425340B635F43D6BC2506630761ADA71F5E6BBDBCA4651C479F9FB45" + "00"
+ + "E86F9D37425340B635F43D6BC2506630761ADA71F5E6BBDBCA4651C479F9FB46" + "01"
+ + "F86F9D37425340B635F43D6BC2506630761ADA71F5E6BBDBCA4651C479F9FB47" + "01"
+ );
+ HashMap<String, Boolean> input = new HashMap<>();
+ input.put("C86F9D37425340B635F43D6BC2506630761ADA71F5E6BBDBCA4651C479F9FB44", false);
+ input.put("B86F9D37425340B635F43D6BC2506630761ADA71F5E6BBDBCA4651C479F9FB43", true);
+ input.put("D86F9D37425340B635F43D6BC2506630761ADA71F5E6BBDBCA4651C479F9FB45", false);
+ input.put("E86F9D37425340B635F43D6BC2506630761ADA71F5E6BBDBCA4651C479F9FB46", true);
+ input.put("F86F9D37425340B635F43D6BC2506630761ADA71F5E6BBDBCA4651C479F9FB47", true);
+
+ copyWatchlistConfigXml(mContext, TEST_XML_1, mTestXmlFile);
+ WatchlistConfig config = new WatchlistConfig(mTestXmlFile);
+
+ byte[] result = ReportEncoder.serializeReport(config, input);
+ assertArrayEquals(expectedResult, result);
+ }
+
+ private static void copyWatchlistConfigXml(Context context, String xmlAsset, File outFile)
+ throws IOException {
+ writeToFile(outFile, readAsset(context, xmlAsset));
+ }
+
+ private static String readAsset(Context context, String assetPath) throws IOException {
+ final StringBuilder sb = new StringBuilder();
+ try (BufferedReader br = new BufferedReader(
+ new InputStreamReader(
+ context.getResources().getAssets().open(assetPath)))) {
+ String line;
+ while ((line = br.readLine()) != null) {
+ sb.append(line);
+ sb.append(System.lineSeparator());
+ }
+ }
+ return sb.toString();
+ }
+
+ private static void writeToFile(File path, String content)
+ throws IOException {
+ path.getParentFile().mkdirs();
+
+ try (FileWriter writer = new FileWriter(path)) {
+ writer.write(content);
+ }
+ }
+}
diff --git a/services/tests/servicestests/src/com/android/server/net/watchlist/WatchlistConfigTests.java b/services/tests/servicestests/src/com/android/server/net/watchlist/WatchlistConfigTests.java
new file mode 100644
index 000000000000..851d2c62e87e
--- /dev/null
+++ b/services/tests/servicestests/src/com/android/server/net/watchlist/WatchlistConfigTests.java
@@ -0,0 +1,147 @@
+/*
+ * Copyright 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.net.watchlist;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+
+import android.content.Context;
+import android.support.test.InstrumentationRegistry;
+import android.support.test.filters.SmallTest;
+import android.support.test.runner.AndroidJUnit4;
+
+import com.android.internal.util.HexDump;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import java.io.BufferedReader;
+import java.io.File;
+import java.io.FileWriter;
+import java.io.IOException;
+import java.io.InputStreamReader;
+import java.util.Arrays;
+
+/**
+ * runtest frameworks-services -c com.android.server.net.watchlist.WatchlistConfigTests
+ */
+@RunWith(AndroidJUnit4.class)
+@SmallTest
+public class WatchlistConfigTests {
+
+ private static final String TEST_XML_1 = "NetworkWatchlistTest/watchlist_config_test1.xml";
+ private static final String TEST_XML_1_HASH =
+ "C99F27A08B1FDB15B101098E12BB2A0AA0D474E23C50F24920A52AB2322BFD94";
+ private static final String TEST_CC_DOMAIN = "test-cc-domain.com";
+ private static final String TEST_CC_IP = "127.0.0.2";
+ private static final String TEST_NOT_EXIST_CC_DOMAIN = "test-not-exist-cc-domain.com";
+ private static final String TEST_NOT_EXIST_CC_IP = "1.2.3.4";
+ private static final String TEST_SHA256_ONLY_DOMAIN = "test-cc-match-sha256-only.com";
+ private static final String TEST_SHA256_ONLY_IP = "127.0.0.3";
+ private static final String TEST_CRC32_ONLY_DOMAIN = "test-cc-match-crc32-only.com";
+ private static final String TEST_CRC32_ONLY_IP = "127.0.0.4";
+
+ private static final String TEST_NEW_CC_DOMAIN = "test-new-cc-domain.com";
+ private static final byte[] TEST_NEW_CC_DOMAIN_SHA256 = HexDump.hexStringToByteArray(
+ "B86F9D37425340B635F43D6BC2506630761ADA71F5E6BBDBCA4651C479F9FB43");
+ private static final byte[] TEST_NEW_CC_DOMAIN_CRC32 = HexDump.hexStringToByteArray("76795BD3");
+
+ private static final String TEST_NEW_CC_IP = "1.1.1.2";
+ private static final byte[] TEST_NEW_CC_IP_SHA256 = HexDump.hexStringToByteArray(
+ "721BAB5E313CF0CC76B10F9592F18B9D1B8996497501A3306A55B3AE9F1CC87C");
+ private static final byte[] TEST_NEW_CC_IP_CRC32 = HexDump.hexStringToByteArray("940B8BEE");
+
+ private Context mContext;
+ private File mTestXmlFile;
+
+ @Before
+ public void setUp() throws Exception {
+ mContext = InstrumentationRegistry.getContext();
+ mTestXmlFile = new File(mContext.getFilesDir(), "test_watchlist_config.xml");
+ mTestXmlFile.delete();
+ }
+
+ @After
+ public void tearDown() throws Exception {
+ mTestXmlFile.delete();
+ }
+
+ @Test
+ public void testWatchlistConfig_parsing() throws Exception {
+ copyWatchlistConfigXml(mContext, TEST_XML_1, mTestXmlFile);
+ WatchlistConfig config = new WatchlistConfig(mTestXmlFile);
+ assertTrue(config.containsDomain(TEST_CC_DOMAIN));
+ assertTrue(config.containsIp(TEST_CC_IP));
+ assertFalse(config.containsDomain(TEST_NOT_EXIST_CC_DOMAIN));
+ assertFalse(config.containsIp(TEST_NOT_EXIST_CC_IP));
+ assertFalse(config.containsDomain(TEST_SHA256_ONLY_DOMAIN));
+ assertFalse(config.containsIp(TEST_SHA256_ONLY_IP));
+ assertFalse(config.containsDomain(TEST_CRC32_ONLY_DOMAIN));
+ assertFalse(config.containsIp(TEST_CRC32_ONLY_IP));
+ }
+
+ @Test
+ public void testWatchlistConfig_noXml() throws Exception {
+ WatchlistConfig config = new WatchlistConfig(mTestXmlFile);
+ assertFalse(config.containsDomain(TEST_CC_DOMAIN));
+ assertFalse(config.containsIp(TEST_CC_IP));
+ assertFalse(config.containsDomain(TEST_NOT_EXIST_CC_DOMAIN));
+ assertFalse(config.containsIp(TEST_NOT_EXIST_CC_IP));
+ assertFalse(config.containsDomain(TEST_SHA256_ONLY_DOMAIN));
+ assertFalse(config.containsIp(TEST_SHA256_ONLY_IP));
+ assertFalse(config.containsDomain(TEST_CRC32_ONLY_DOMAIN));
+ assertFalse(config.containsIp(TEST_CRC32_ONLY_IP));
+ }
+
+ @Test
+ public void testWatchlistConfig_getWatchlistConfigHash() throws Exception {
+ copyWatchlistConfigXml(mContext, TEST_XML_1, mTestXmlFile);
+ WatchlistConfig config = new WatchlistConfig(mTestXmlFile);
+ assertEquals(TEST_XML_1_HASH, HexDump.toHexString(config.getWatchlistConfigHash()));
+ }
+
+ private static void copyWatchlistConfigXml(Context context, String xmlAsset, File outFile)
+ throws IOException {
+ writeToFile(outFile, readAsset(context, xmlAsset));
+ }
+
+ private static String readAsset(Context context, String assetPath) throws IOException {
+ final StringBuilder sb = new StringBuilder();
+ try (BufferedReader br = new BufferedReader(
+ new InputStreamReader(
+ context.getResources().getAssets().open(assetPath)))) {
+ String line;
+ while ((line = br.readLine()) != null) {
+ sb.append(line);
+ sb.append(System.lineSeparator());
+ }
+ }
+ return sb.toString();
+ }
+
+ private static void writeToFile(File path, String content)
+ throws IOException {
+ path.getParentFile().mkdirs();
+
+ try (FileWriter writer = new FileWriter(path)) {
+ writer.write(content);
+ }
+ }
+}
diff --git a/services/tests/servicestests/src/com/android/server/net/watchlist/WatchlistLoggingHandlerTests.java b/services/tests/servicestests/src/com/android/server/net/watchlist/WatchlistLoggingHandlerTests.java
index e356b13d01d5..070de5b95356 100644
--- a/services/tests/servicestests/src/com/android/server/net/watchlist/WatchlistLoggingHandlerTests.java
+++ b/services/tests/servicestests/src/com/android/server/net/watchlist/WatchlistLoggingHandlerTests.java
@@ -36,14 +36,6 @@ import java.util.Arrays;
@SmallTest
public class WatchlistLoggingHandlerTests {
- @Before
- public void setUp() throws Exception {
- }
-
- @After
- public void tearDown() throws Exception {
- }
-
@Test
public void testWatchlistLoggingHandler_getAllSubDomains() throws Exception {
String[] subDomains = WatchlistLoggingHandler.getAllSubDomains("abc.def.gh.i.jkl.mm");
diff --git a/services/tests/servicestests/src/com/android/server/net/watchlist/WatchlistSettingsTests.java b/services/tests/servicestests/src/com/android/server/net/watchlist/WatchlistSettingsTests.java
index 212d25d42420..07158afbaaff 100644
--- a/services/tests/servicestests/src/com/android/server/net/watchlist/WatchlistSettingsTests.java
+++ b/services/tests/servicestests/src/com/android/server/net/watchlist/WatchlistSettingsTests.java
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2017 The Android Open Source Project
+ * Copyright 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.
@@ -16,8 +16,8 @@
package com.android.server.net.watchlist;
-import static org.junit.Assert.assertFalse;
-import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotEquals;
import android.content.Context;
import android.support.test.InstrumentationRegistry;
@@ -36,7 +36,6 @@ import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
import java.io.InputStreamReader;
-import java.util.Arrays;
/**
* runtest frameworks-services -c com.android.server.net.watchlist.WatchlistSettingsTests
@@ -46,24 +45,9 @@ import java.util.Arrays;
public class WatchlistSettingsTests {
private static final String TEST_XML_1 = "NetworkWatchlistTest/watchlist_settings_test1.xml";
- private static final String TEST_CC_DOMAIN = "test-cc-domain.com";
- private static final String TEST_CC_IP = "127.0.0.2";
- private static final String TEST_NOT_EXIST_CC_DOMAIN = "test-not-exist-cc-domain.com";
- private static final String TEST_NOT_EXIST_CC_IP = "1.2.3.4";
- private static final String TEST_SHA256_ONLY_DOMAIN = "test-cc-match-sha256-only.com";
- private static final String TEST_SHA256_ONLY_IP = "127.0.0.3";
- private static final String TEST_CRC32_ONLY_DOMAIN = "test-cc-match-crc32-only.com";
- private static final String TEST_CRC32_ONLY_IP = "127.0.0.4";
-
- private static final String TEST_NEW_CC_DOMAIN = "test-new-cc-domain.com";
- private static final byte[] TEST_NEW_CC_DOMAIN_SHA256 = HexDump.hexStringToByteArray(
- "B86F9D37425340B635F43D6BC2506630761ADA71F5E6BBDBCA4651C479F9FB43");
- private static final byte[] TEST_NEW_CC_DOMAIN_CRC32 = HexDump.hexStringToByteArray("76795BD3");
-
- private static final String TEST_NEW_CC_IP = "1.1.1.2";
- private static final byte[] TEST_NEW_CC_IP_SHA256 = HexDump.hexStringToByteArray(
- "721BAB5E313CF0CC76B10F9592F18B9D1B8996497501A3306A55B3AE9F1CC87C");
- private static final byte[] TEST_NEW_CC_IP_CRC32 = HexDump.hexStringToByteArray("940B8BEE");
+ private static final String TEST_XML_2 = "NetworkWatchlistTest/watchlist_settings_test2.xml";
+ private static final String HARD_CODED_SECRET_KEY = "1234567890ABCDEF1234567890ABCDEF"
+ + "1234567890ABCDEF1234567890ABCDEF1234567890ABCDEF1234567890ABCDEF";
private Context mContext;
private File mTestXmlFile;
@@ -71,7 +55,7 @@ public class WatchlistSettingsTests {
@Before
public void setUp() throws Exception {
mContext = InstrumentationRegistry.getContext();
- mTestXmlFile = new File(mContext.getFilesDir(), "test_watchlist_settings.xml");
+ mTestXmlFile = new File(mContext.getFilesDir(), "test_settings_config.xml");
mTestXmlFile.delete();
}
@@ -84,55 +68,48 @@ public class WatchlistSettingsTests {
public void testWatchlistSettings_parsing() throws Exception {
copyWatchlistSettingsXml(mContext, TEST_XML_1, mTestXmlFile);
WatchlistSettings settings = new WatchlistSettings(mTestXmlFile);
- assertTrue(settings.containsDomain(TEST_CC_DOMAIN));
- assertTrue(settings.containsIp(TEST_CC_IP));
- assertFalse(settings.containsDomain(TEST_NOT_EXIST_CC_DOMAIN));
- assertFalse(settings.containsIp(TEST_NOT_EXIST_CC_IP));
- assertFalse(settings.containsDomain(TEST_SHA256_ONLY_DOMAIN));
- assertFalse(settings.containsIp(TEST_SHA256_ONLY_IP));
- assertFalse(settings.containsDomain(TEST_CRC32_ONLY_DOMAIN));
- assertFalse(settings.containsIp(TEST_CRC32_ONLY_IP));
+ assertEquals(HARD_CODED_SECRET_KEY, HexDump.toHexString(settings.getPrivacySecretKey()));
+ // Try again.
+ assertEquals(HARD_CODED_SECRET_KEY, HexDump.toHexString(settings.getPrivacySecretKey()));
}
@Test
- public void testWatchlistSettings_writeSettingsToMemory() throws Exception {
- copyWatchlistSettingsXml(mContext, TEST_XML_1, mTestXmlFile);
+ public void testWatchlistSettings_parsingWithoutKey() throws Exception {
+ copyWatchlistSettingsXml(mContext, TEST_XML_2, mTestXmlFile);
WatchlistSettings settings = new WatchlistSettings(mTestXmlFile);
- settings.writeSettingsToMemory(Arrays.asList(TEST_NEW_CC_DOMAIN_CRC32),
- Arrays.asList(TEST_NEW_CC_DOMAIN_SHA256), Arrays.asList(TEST_NEW_CC_IP_CRC32),
- Arrays.asList(TEST_NEW_CC_IP_SHA256));
- // Ensure old watchlist is not in memory
- assertFalse(settings.containsDomain(TEST_CC_DOMAIN));
- assertFalse(settings.containsIp(TEST_CC_IP));
- assertFalse(settings.containsDomain(TEST_NOT_EXIST_CC_DOMAIN));
- assertFalse(settings.containsIp(TEST_NOT_EXIST_CC_IP));
- assertFalse(settings.containsDomain(TEST_SHA256_ONLY_DOMAIN));
- assertFalse(settings.containsIp(TEST_SHA256_ONLY_IP));
- assertFalse(settings.containsDomain(TEST_CRC32_ONLY_DOMAIN));
- assertFalse(settings.containsIp(TEST_CRC32_ONLY_IP));
- // Ensure new watchlist is in memory
- assertTrue(settings.containsDomain(TEST_NEW_CC_DOMAIN));
- assertTrue(settings.containsIp(TEST_NEW_CC_IP));
- // Reload settings from disk and test again
+ final String tmpKey1 = HexDump.toHexString(settings.getPrivacySecretKey());
+ assertNotEquals(HARD_CODED_SECRET_KEY, tmpKey1);
+ assertEquals(96, tmpKey1.length());
+ // Try again to make sure it's the same.
+ assertEquals(tmpKey1, HexDump.toHexString(settings.getPrivacySecretKey()));
+ // Create new settings object again to make sure it can get the new saved key.
settings = new WatchlistSettings(mTestXmlFile);
- // Ensure old watchlist is in memory
- assertTrue(settings.containsDomain(TEST_CC_DOMAIN));
- assertTrue(settings.containsIp(TEST_CC_IP));
- assertFalse(settings.containsDomain(TEST_NOT_EXIST_CC_DOMAIN));
- assertFalse(settings.containsIp(TEST_NOT_EXIST_CC_IP));
- assertFalse(settings.containsDomain(TEST_SHA256_ONLY_DOMAIN));
- assertFalse(settings.containsIp(TEST_SHA256_ONLY_IP));
- assertFalse(settings.containsDomain(TEST_CRC32_ONLY_DOMAIN));
- assertFalse(settings.containsIp(TEST_CRC32_ONLY_IP));
- // Ensure new watchlist is not in memory
- assertFalse(settings.containsDomain(TEST_NEW_CC_DOMAIN));
- assertFalse(settings.containsIp(TEST_NEW_CC_IP));;
+ assertEquals(tmpKey1, HexDump.toHexString(settings.getPrivacySecretKey()));
+ }
+
+ @Test
+ public void testWatchlistSettings_noExistingXml() throws Exception {
+ WatchlistSettings settings = new WatchlistSettings(mTestXmlFile);
+ final String tmpKey1 = HexDump.toHexString(settings.getPrivacySecretKey());
+ assertNotEquals(HARD_CODED_SECRET_KEY, tmpKey1);
+ assertEquals(96, tmpKey1.length());
+ // Try again to make sure it's the same.
+ assertEquals(tmpKey1, HexDump.toHexString(settings.getPrivacySecretKey()));
+ // Create new settings object again to make sure it can get the new saved key.
+ settings = new WatchlistSettings(mTestXmlFile);
+ assertEquals(tmpKey1, HexDump.toHexString(settings.getPrivacySecretKey()));
+ // Delete xml and generate key again, to make sure key is randomly generated.
+ mTestXmlFile.delete();
+ settings = new WatchlistSettings(mTestXmlFile);
+ final String tmpKey2 = HexDump.toHexString(settings.getPrivacySecretKey());
+ assertNotEquals(HARD_CODED_SECRET_KEY, tmpKey2);
+ assertNotEquals(tmpKey1, tmpKey2);
+ assertEquals(96, tmpKey2.length());
}
private static void copyWatchlistSettingsXml(Context context, String xmlAsset, File outFile)
throws IOException {
writeToFile(outFile, readAsset(context, xmlAsset));
-
}
private static String readAsset(Context context, String assetPath) throws IOException {
diff --git a/services/tests/servicestests/src/com/android/server/wm/DragDropControllerTests.java b/services/tests/servicestests/src/com/android/server/wm/DragDropControllerTests.java
index ac291632c877..57da6a3a60a6 100644
--- a/services/tests/servicestests/src/com/android/server/wm/DragDropControllerTests.java
+++ b/services/tests/servicestests/src/com/android/server/wm/DragDropControllerTests.java
@@ -20,7 +20,6 @@ import static android.app.WindowConfiguration.ACTIVITY_TYPE_STANDARD;
import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN;
import static android.view.WindowManager.LayoutParams.TYPE_BASE_APPLICATION;
import static org.junit.Assert.assertNotNull;
-import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertTrue;
import static org.mockito.Mockito.any;
import static org.mockito.Mockito.mock;
@@ -28,6 +27,7 @@ import static org.mockito.Mockito.spy;
import static org.mockito.Mockito.when;
import android.content.ClipData;
+import android.graphics.PixelFormat;
import android.os.IBinder;
import android.os.Looper;
import android.os.UserHandle;
@@ -36,7 +36,7 @@ import android.platform.test.annotations.Presubmit;
import android.support.test.filters.SmallTest;
import android.support.test.runner.AndroidJUnit4;
import android.view.InputChannel;
-import android.view.Surface;
+import android.view.SurfaceControl;
import android.view.SurfaceSession;
import android.view.View;
import com.android.internal.annotations.GuardedBy;
@@ -146,14 +146,6 @@ public class DragDropControllerTests extends WindowTestsBase {
}
@Test
- public void testPrepareDrag_ZeroSizeSurface() throws Exception {
- final Surface surface = new Surface();
- mToken = mTarget.prepareDrag(
- new SurfaceSession(), 0, 0, mWindow.mClient, 0, 0, 0, surface);
- assertNull(mToken);
- }
-
- @Test
public void testPerformDrag_NullDataWithGrantUri() throws Exception {
dragFlow(View.DRAG_FLAG_GLOBAL | View.DRAG_FLAG_GLOBAL_URI_READ, null, 0, 0);
}
@@ -169,16 +161,24 @@ public class DragDropControllerTests extends WindowTestsBase {
}
private void dragFlow(int flag, ClipData data, float dropX, float dropY) {
- final Surface surface = new Surface();
- mToken = mTarget.prepareDrag(
- new SurfaceSession(), 0, 0, mWindow.mClient, flag, 100, 100, surface);
- assertNotNull(mToken);
-
- assertTrue(sWm.mInputManager.transferTouchFocus(null, null));
- assertTrue(mTarget.performDrag(
- mWindow.mClient, mToken, 0, 0, 0, 0, 0, data));
-
- mTarget.handleMotionEvent(false, dropX, dropY);
- mToken = mWindow.mClient.asBinder();
+ final SurfaceSession appSession = new SurfaceSession();
+ try {
+ final SurfaceControl surface = new SurfaceControl.Builder(appSession)
+ .setName("drag surface")
+ .setSize(100, 100)
+ .setFormat(PixelFormat.TRANSLUCENT)
+ .build();
+
+ assertTrue(sWm.mInputManager.transferTouchFocus(null, null));
+ mToken = mTarget.performDrag(
+ new SurfaceSession(), 0, 0, mWindow.mClient, flag, surface, 0, 0, 0, 0, 0,
+ data);
+ assertNotNull(mToken);
+
+ mTarget.handleMotionEvent(false, dropX, dropY);
+ mToken = mWindow.mClient.asBinder();
+ } finally {
+ appSession.kill();
+ }
}
}
diff --git a/services/tests/servicestests/src/com/android/server/wm/TestWindowManagerPolicy.java b/services/tests/servicestests/src/com/android/server/wm/TestWindowManagerPolicy.java
index 5ed17ccc6d9b..35ca493e909f 100644
--- a/services/tests/servicestests/src/com/android/server/wm/TestWindowManagerPolicy.java
+++ b/services/tests/servicestests/src/com/android/server/wm/TestWindowManagerPolicy.java
@@ -539,7 +539,7 @@ class TestWindowManagerPolicy implements WindowManagerPolicy {
}
@Override
- public void showRecentApps(boolean fromHome) {
+ public void showRecentApps() {
}
diff --git a/services/tests/servicestests/src/com/android/server/wm/ZOrderingTests.java b/services/tests/servicestests/src/com/android/server/wm/ZOrderingTests.java
index 6468763440a5..5f44fb675330 100644
--- a/services/tests/servicestests/src/com/android/server/wm/ZOrderingTests.java
+++ b/services/tests/servicestests/src/com/android/server/wm/ZOrderingTests.java
@@ -17,14 +17,17 @@
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_STANDARD;
import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN;
import static android.app.WindowConfiguration.WINDOWING_MODE_PINNED;
import static android.app.WindowConfiguration.WINDOWING_MODE_SPLIT_SCREEN_PRIMARY;
+import static android.app.WindowConfiguration.WINDOWING_MODE_SPLIT_SCREEN_SECONDARY;
import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_ATTACHED_DIALOG;
import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_MEDIA;
import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_MEDIA_OVERLAY;
import static android.view.WindowManager.LayoutParams.TYPE_BASE_APPLICATION;
+import static android.view.WindowManager.LayoutParams.TYPE_DOCK_DIVIDER;
import static android.view.WindowManager.LayoutParams.TYPE_NAVIGATION_BAR_PANEL;
import static android.view.WindowManager.LayoutParams.TYPE_STATUS_BAR_PANEL;
import static android.view.WindowManager.LayoutParams.TYPE_STATUS_BAR_SUB_PANEL;
@@ -74,11 +77,11 @@ public class ZOrderingTests extends WindowTestsBase {
return super.setRelativeLayer(sc, relativeTo, layer);
}
- int getLayer(SurfaceControl sc) {
+ private int getLayer(SurfaceControl sc) {
return mLayersForControl.getOrDefault(sc, 0);
}
- SurfaceControl getRelativeLayer(SurfaceControl sc) {
+ private SurfaceControl getRelativeLayer(SurfaceControl sc) {
return mRelativeLayersForControl.get(sc);
}
};
@@ -146,8 +149,9 @@ public class ZOrderingTests extends WindowTestsBase {
return p;
}
- void assertZOrderGreaterThan(LayerRecordingTransaction t,
- SurfaceControl left, SurfaceControl right) throws Exception {
+
+ void assertZOrderGreaterThan(LayerRecordingTransaction t, SurfaceControl left,
+ SurfaceControl right) throws Exception {
final LinkedList<SurfaceControl> leftParentChain = getAncestors(t, left);
final LinkedList<SurfaceControl> rightParentChain = getAncestors(t, right);
@@ -171,9 +175,12 @@ public class ZOrderingTests extends WindowTestsBase {
}
}
- void assertWindowLayerGreaterThan(LayerRecordingTransaction t,
- WindowState left, WindowState right) throws Exception {
- assertZOrderGreaterThan(t, left.getSurfaceControl(), right.getSurfaceControl());
+ void assertWindowHigher(WindowState left, WindowState right) throws Exception {
+ assertZOrderGreaterThan(mTransaction, left.getSurfaceControl(), right.getSurfaceControl());
+ }
+
+ WindowState createWindow(String name) {
+ return createWindow(null, TYPE_BASE_APPLICATION, mDisplayContent, name);
}
@Test
@@ -184,38 +191,37 @@ public class ZOrderingTests extends WindowTestsBase {
// The Ime has an higher base layer than app windows and lower base layer than system
// windows, so it should be above app windows and below system windows if there isn't an IME
// target.
- assertWindowLayerGreaterThan(mTransaction, mImeWindow, mChildAppWindowAbove);
- assertWindowLayerGreaterThan(mTransaction, mImeWindow, mAppWindow);
- assertWindowLayerGreaterThan(mTransaction, mNavBarWindow, mImeWindow);
- assertWindowLayerGreaterThan(mTransaction, mStatusBarWindow, mImeWindow);
+ assertWindowHigher(mImeWindow, mChildAppWindowAbove);
+ assertWindowHigher(mImeWindow, mAppWindow);
+ assertWindowHigher(mNavBarWindow, mImeWindow);
+ assertWindowHigher(mStatusBarWindow, mImeWindow);
// And, IME dialogs should always have an higher layer than the IME.
- assertWindowLayerGreaterThan(mTransaction, mImeDialogWindow, mImeWindow);
+ assertWindowHigher(mImeDialogWindow, mImeWindow);
}
@Test
public void testAssignWindowLayers_ForImeWithAppTarget() throws Exception {
- final WindowState imeAppTarget =
- createWindow(null, TYPE_BASE_APPLICATION, mDisplayContent, "imeAppTarget");
+ final WindowState imeAppTarget = createWindow("imeAppTarget");
sWm.mInputMethodTarget = imeAppTarget;
+
mDisplayContent.assignChildLayers(mTransaction);
// Ime should be above all app windows and below system windows if it is targeting an app
// window.
- assertWindowLayerGreaterThan(mTransaction, mImeWindow, imeAppTarget);
- assertWindowLayerGreaterThan(mTransaction, mImeWindow, mChildAppWindowAbove);
- assertWindowLayerGreaterThan(mTransaction, mImeWindow, mAppWindow);
- assertWindowLayerGreaterThan(mTransaction, mNavBarWindow, mImeWindow);
- assertWindowLayerGreaterThan(mTransaction, mStatusBarWindow, mImeWindow);
+ assertWindowHigher(mImeWindow, imeAppTarget);
+ assertWindowHigher(mImeWindow, mChildAppWindowAbove);
+ assertWindowHigher(mImeWindow, mAppWindow);
+ assertWindowHigher(mNavBarWindow, mImeWindow);
+ assertWindowHigher(mStatusBarWindow, mImeWindow);
// And, IME dialogs should always have an higher layer than the IME.
- assertWindowLayerGreaterThan(mTransaction, mImeDialogWindow, mImeWindow);
+ assertWindowHigher(mImeDialogWindow, mImeWindow);
}
@Test
public void testAssignWindowLayers_ForImeWithAppTargetWithChildWindows() throws Exception {
- final WindowState imeAppTarget =
- createWindow(null, TYPE_BASE_APPLICATION, mDisplayContent, "imeAppTarget");
+ final WindowState imeAppTarget = createWindow("imeAppTarget");
final WindowState imeAppTargetChildAboveWindow = createWindow(imeAppTarget,
TYPE_APPLICATION_ATTACHED_DIALOG, imeAppTarget.mToken,
"imeAppTargetChildAboveWindow");
@@ -228,41 +234,38 @@ public class ZOrderingTests extends WindowTestsBase {
// Ime should be above all app windows except for child windows that are z-ordered above it
// and below system windows if it is targeting an app window.
- assertWindowLayerGreaterThan(mTransaction, mImeWindow, imeAppTarget);
- assertWindowLayerGreaterThan(mTransaction, imeAppTargetChildAboveWindow, mImeWindow);
- assertWindowLayerGreaterThan(mTransaction, mImeWindow, mChildAppWindowAbove);
- assertWindowLayerGreaterThan(mTransaction, mImeWindow, mAppWindow);
- assertWindowLayerGreaterThan(mTransaction, mNavBarWindow, mImeWindow);
- assertWindowLayerGreaterThan(mTransaction, mStatusBarWindow, mImeWindow);
+ assertWindowHigher(mImeWindow, imeAppTarget);
+ assertWindowHigher(imeAppTargetChildAboveWindow, mImeWindow);
+ assertWindowHigher(mImeWindow, mChildAppWindowAbove);
+ assertWindowHigher(mImeWindow, mAppWindow);
+ assertWindowHigher(mNavBarWindow, mImeWindow);
+ assertWindowHigher(mStatusBarWindow, mImeWindow);
// And, IME dialogs should always have an higher layer than the IME.
- assertWindowLayerGreaterThan(mTransaction, mImeDialogWindow, mImeWindow);
+ assertWindowHigher(mImeDialogWindow, mImeWindow);
}
@Test
public void testAssignWindowLayers_ForImeWithAppTargetAndAppAbove() throws Exception {
- final WindowState appBelowImeTarget =
- createWindow(null, TYPE_BASE_APPLICATION, mDisplayContent, "appBelowImeTarget");
- final WindowState imeAppTarget =
- createWindow(null, TYPE_BASE_APPLICATION, mDisplayContent, "imeAppTarget");
- final WindowState appAboveImeTarget =
- createWindow(null, TYPE_BASE_APPLICATION, mDisplayContent, "appAboveImeTarget");
+ final WindowState appBelowImeTarget = createWindow("appBelowImeTarget");
+ final WindowState imeAppTarget = createWindow("imeAppTarget");
+ final WindowState appAboveImeTarget = createWindow("appAboveImeTarget");
sWm.mInputMethodTarget = imeAppTarget;
mDisplayContent.assignChildLayers(mTransaction);
// Ime should be above all app windows except for non-fullscreen app window above it and
// below system windows if it is targeting an app window.
- assertWindowLayerGreaterThan(mTransaction, mImeWindow, imeAppTarget);
- assertWindowLayerGreaterThan(mTransaction, mImeWindow, appBelowImeTarget);
- assertWindowLayerGreaterThan(mTransaction, appAboveImeTarget, mImeWindow);
- assertWindowLayerGreaterThan(mTransaction, mImeWindow, mChildAppWindowAbove);
- assertWindowLayerGreaterThan(mTransaction, mImeWindow, mAppWindow);
- assertWindowLayerGreaterThan(mTransaction, mNavBarWindow, mImeWindow);
- assertWindowLayerGreaterThan(mTransaction, mStatusBarWindow, mImeWindow);
+ assertWindowHigher(mImeWindow, imeAppTarget);
+ assertWindowHigher(mImeWindow, appBelowImeTarget);
+ assertWindowHigher(appAboveImeTarget, mImeWindow);
+ assertWindowHigher(mImeWindow, mChildAppWindowAbove);
+ assertWindowHigher(mImeWindow, mAppWindow);
+ assertWindowHigher(mNavBarWindow, mImeWindow);
+ assertWindowHigher(mStatusBarWindow, mImeWindow);
// And, IME dialogs should always have an higher layer than the IME.
- assertWindowLayerGreaterThan(mTransaction, mImeDialogWindow, mImeWindow);
+ assertWindowHigher(mImeDialogWindow, mImeWindow);
}
@Test
@@ -276,20 +279,20 @@ public class ZOrderingTests extends WindowTestsBase {
// The IME target base layer is higher than all window except for the nav bar window, so the
// IME should be above all windows except for the nav bar.
- assertWindowLayerGreaterThan(mTransaction, mImeWindow, imeSystemOverlayTarget);
- assertWindowLayerGreaterThan(mTransaction, mImeWindow, mChildAppWindowAbove);
- assertWindowLayerGreaterThan(mTransaction, mImeWindow, mAppWindow);
- assertWindowLayerGreaterThan(mTransaction, mImeWindow, mDockedDividerWindow);
+ assertWindowHigher(mImeWindow, imeSystemOverlayTarget);
+ assertWindowHigher(mImeWindow, mChildAppWindowAbove);
+ assertWindowHigher(mImeWindow, mAppWindow);
+ assertWindowHigher(mImeWindow, mDockedDividerWindow);
// The IME has a higher base layer than the status bar so we may expect it to go
// above the status bar once they are both in the Non-App layer, as past versions of this
// test enforced. However this seems like the wrong behavior unless the status bar is the
// IME target.
- assertWindowLayerGreaterThan(mTransaction, mNavBarWindow, mImeWindow);
- assertWindowLayerGreaterThan(mTransaction, mStatusBarWindow, mImeWindow);
+ assertWindowHigher(mNavBarWindow, mImeWindow);
+ assertWindowHigher(mStatusBarWindow, mImeWindow);
// And, IME dialogs should always have an higher layer than the IME.
- assertWindowLayerGreaterThan(mTransaction, mImeDialogWindow, mImeWindow);
+ assertWindowHigher(mImeDialogWindow, mImeWindow);
}
@Test
@@ -297,17 +300,18 @@ public class ZOrderingTests extends WindowTestsBase {
sWm.mInputMethodTarget = mStatusBarWindow;
mDisplayContent.assignChildLayers(mTransaction);
- assertWindowLayerGreaterThan(mTransaction, mImeWindow, mChildAppWindowAbove);
- assertWindowLayerGreaterThan(mTransaction, mImeWindow, mAppWindow);
- assertWindowLayerGreaterThan(mTransaction, mImeWindow, mDockedDividerWindow);
- assertWindowLayerGreaterThan(mTransaction, mImeWindow, mStatusBarWindow);
+ assertWindowHigher(mImeWindow, mChildAppWindowAbove);
+ assertWindowHigher(mImeWindow, mAppWindow);
+ assertWindowHigher(mImeWindow, mDockedDividerWindow);
+ assertWindowHigher(mImeWindow, mStatusBarWindow);
// And, IME dialogs should always have an higher layer than the IME.
- assertWindowLayerGreaterThan(mTransaction, mImeDialogWindow, mImeWindow);
+ assertWindowHigher(mImeDialogWindow, mImeWindow);
}
@Test
public void testStackLayers() throws Exception {
+ final WindowState anyWindow1 = createWindow("anyWindow");
final WindowState pinnedStackWindow = createWindowOnStack(null, WINDOWING_MODE_PINNED,
ACTIVITY_TYPE_STANDARD, TYPE_BASE_APPLICATION, mDisplayContent,
"pinnedStackWindow");
@@ -317,12 +321,22 @@ public class ZOrderingTests extends WindowTestsBase {
final WindowState assistantStackWindow = createWindowOnStack(null, WINDOWING_MODE_FULLSCREEN,
ACTIVITY_TYPE_ASSISTANT, TYPE_BASE_APPLICATION,
mDisplayContent, "assistantStackWindow");
+ final WindowState homeActivityWindow = createWindowOnStack(null, WINDOWING_MODE_FULLSCREEN,
+ ACTIVITY_TYPE_HOME, TYPE_BASE_APPLICATION,
+ mDisplayContent, "homeActivityWindow");
+ final WindowState anyWindow2 = createWindow("anyWindow2");
mDisplayContent.assignChildLayers(mTransaction);
- assertWindowLayerGreaterThan(mTransaction, dockedStackWindow, mAppWindow);
- assertWindowLayerGreaterThan(mTransaction, assistantStackWindow, dockedStackWindow);
- assertWindowLayerGreaterThan(mTransaction, pinnedStackWindow, assistantStackWindow);
+ assertWindowHigher(dockedStackWindow, homeActivityWindow);
+ assertWindowHigher(assistantStackWindow, homeActivityWindow);
+ assertWindowHigher(pinnedStackWindow, homeActivityWindow);
+ assertWindowHigher(anyWindow1, homeActivityWindow);
+ assertWindowHigher(anyWindow2, homeActivityWindow);
+ assertWindowHigher(pinnedStackWindow, anyWindow1);
+ assertWindowHigher(pinnedStackWindow, anyWindow2);
+ assertWindowHigher(pinnedStackWindow, dockedStackWindow);
+ assertWindowHigher(pinnedStackWindow, assistantStackWindow);
}
@Test
@@ -337,9 +351,9 @@ public class ZOrderingTests extends WindowTestsBase {
// Ime should be above all app windows and below system windows if it is targeting an app
// window.
- assertWindowLayerGreaterThan(mTransaction, navBarPanel, mNavBarWindow);
- assertWindowLayerGreaterThan(mTransaction, statusBarPanel, mStatusBarWindow);
- assertWindowLayerGreaterThan(mTransaction, statusBarSubPanel, statusBarPanel);
+ assertWindowHigher(navBarPanel, mNavBarWindow);
+ assertWindowHigher(statusBarPanel, mStatusBarWindow);
+ assertWindowHigher(statusBarSubPanel, statusBarPanel);
}
@Test
@@ -347,8 +361,7 @@ public class ZOrderingTests extends WindowTestsBase {
// TODO(b/70040778): We should aim to eliminate the last user of TYPE_APPLICATION_MEDIA
// then we can drop all negative layering on the windowing side.
- final WindowState anyWindow =
- createWindow(null, TYPE_BASE_APPLICATION, mDisplayContent, "anyWindow");
+ final WindowState anyWindow = createWindow("anyWindow");
final WindowState child = createWindow(anyWindow, TYPE_APPLICATION_MEDIA, mDisplayContent,
"TypeApplicationMediaChild");
final WindowState mediaOverlayChild = createWindow(anyWindow, TYPE_APPLICATION_MEDIA_OVERLAY,
@@ -356,7 +369,29 @@ public class ZOrderingTests extends WindowTestsBase {
mDisplayContent.assignChildLayers(mTransaction);
- assertWindowLayerGreaterThan(mTransaction, anyWindow, mediaOverlayChild);
- assertWindowLayerGreaterThan(mTransaction, mediaOverlayChild, child);
+ assertWindowHigher(anyWindow, mediaOverlayChild);
+ assertWindowHigher(mediaOverlayChild, child);
+ }
+
+ @Test
+ public void testDockedDividerPosition() throws Exception {
+ final WindowState pinnedStackWindow = createWindowOnStack(null, WINDOWING_MODE_PINNED,
+ ACTIVITY_TYPE_STANDARD, TYPE_BASE_APPLICATION, mDisplayContent,
+ "pinnedStackWindow");
+ final WindowState splitScreenWindow = createWindowOnStack(null,
+ WINDOWING_MODE_SPLIT_SCREEN_PRIMARY, ACTIVITY_TYPE_STANDARD, TYPE_BASE_APPLICATION,
+ mDisplayContent, "splitScreenWindow");
+ final WindowState splitScreenSecondaryWindow = createWindowOnStack(null,
+ WINDOWING_MODE_SPLIT_SCREEN_SECONDARY, ACTIVITY_TYPE_STANDARD,
+ TYPE_BASE_APPLICATION, mDisplayContent, "splitScreenSecondaryWindow");
+ final WindowState assistantStackWindow = createWindowOnStack(null, WINDOWING_MODE_FULLSCREEN,
+ ACTIVITY_TYPE_ASSISTANT, TYPE_BASE_APPLICATION,
+ mDisplayContent, "assistantStackWindow");
+
+ mDisplayContent.assignChildLayers(mTransaction);
+
+ assertWindowHigher(mDockedDividerWindow, splitScreenWindow);
+ assertWindowHigher(mDockedDividerWindow, splitScreenSecondaryWindow);
+ assertWindowHigher(pinnedStackWindow, mDockedDividerWindow);
}
}
diff --git a/services/usage/java/com/android/server/usage/AppStandbyController.java b/services/usage/java/com/android/server/usage/AppStandbyController.java
index ff3d58652aed..6782188c0f34 100644
--- a/services/usage/java/com/android/server/usage/AppStandbyController.java
+++ b/services/usage/java/com/android/server/usage/AppStandbyController.java
@@ -78,6 +78,7 @@ import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.app.IBatteryStats;
import com.android.internal.os.SomeArgs;
import com.android.internal.util.ArrayUtils;
+import com.android.internal.util.ConcurrentUtils;
import com.android.internal.util.IndentingPrintWriter;
import com.android.server.LocalServices;
@@ -90,6 +91,7 @@ import java.util.Arrays;
import java.util.List;
import java.util.Map;
import java.util.Set;
+import java.util.concurrent.CountDownLatch;
/**
* Manages the standby state of an app, listening to various events.
@@ -128,6 +130,11 @@ public class AppStandbyController {
// Expiration time for predicted bucket
private static final long PREDICTION_TIMEOUT = 12 * ONE_HOUR;
+ /**
+ * Indicates the maximum wait time for admin data to be available;
+ */
+ private static final long WAIT_FOR_ADMIN_DATA_TIMEOUT_MS = 10_000;
+
// To name the lock for stack traces
static class Lock {}
@@ -153,6 +160,8 @@ public class AppStandbyController {
@GuardedBy("mActiveAdminApps")
private final SparseArray<Set<String>> mActiveAdminApps = new SparseArray<>();
+ private final CountDownLatch mAdminDataAvailableLatch = new CountDownLatch(1);
+
// Messages for the handler
static final int MSG_INFORM_LISTENERS = 3;
static final int MSG_FORCE_IDLE_STATE = 4;
@@ -895,6 +904,20 @@ public class AppStandbyController {
}
}
+ public void onAdminDataAvailable() {
+ mAdminDataAvailableLatch.countDown();
+ }
+
+ /**
+ * This will only ever be called once - during device boot.
+ */
+ private void waitForAdminData() {
+ if (mContext.getPackageManager().hasSystemFeature(PackageManager.FEATURE_DEVICE_ADMIN)) {
+ ConcurrentUtils.waitForCountDownNoInterrupt(mAdminDataAvailableLatch,
+ WAIT_FOR_ADMIN_DATA_TIMEOUT_MS, "Wait for admin data");
+ }
+ }
+
Set<String> getActiveAdminAppsForTest(int userId) {
synchronized (mActiveAdminApps) {
return mActiveAdminApps.get(userId);
@@ -1224,6 +1247,7 @@ public class AppStandbyController {
case MSG_ONE_TIME_CHECK_IDLE_STATES:
mHandler.removeMessages(MSG_ONE_TIME_CHECK_IDLE_STATES);
+ waitForAdminData();
checkIdleStates(UserHandle.USER_ALL);
break;
diff --git a/services/usage/java/com/android/server/usage/UsageStatsService.java b/services/usage/java/com/android/server/usage/UsageStatsService.java
index 78cc81f2bab6..979feaa5a165 100644
--- a/services/usage/java/com/android/server/usage/UsageStatsService.java
+++ b/services/usage/java/com/android/server/usage/UsageStatsService.java
@@ -1030,5 +1030,10 @@ public class UsageStatsService extends SystemService implements
public void setActiveAdminApps(Set<String> packageNames, int userId) {
mAppStandby.setActiveAdminApps(packageNames, userId);
}
+
+ @Override
+ public void onAdminDataAvailable() {
+ mAppStandby.onAdminDataAvailable();
+ }
}
}
diff --git a/telephony/java/android/telephony/SubscriptionInfo.java b/telephony/java/android/telephony/SubscriptionInfo.java
index 4e1c15fa1251..38408fe3d0fd 100644
--- a/telephony/java/android/telephony/SubscriptionInfo.java
+++ b/telephony/java/android/telephony/SubscriptionInfo.java
@@ -126,14 +126,31 @@ public class SubscriptionInfo implements Parcelable {
private UiccAccessRule[] mAccessRules;
/**
+ * The ID of the SIM card. It is the ICCID of the active profile for a UICC card and the EID
+ * for an eUICC card.
+ */
+ private String mCardId;
+
+ /**
+ * @hide
+ */
+ public SubscriptionInfo(int id, String iccId, int simSlotIndex, CharSequence displayName,
+ CharSequence carrierName, int nameSource, int iconTint, String number, int roaming,
+ Bitmap icon, int mcc, int mnc, String countryIso) {
+ this(id, iccId, simSlotIndex, displayName, carrierName, nameSource, iconTint, number,
+ roaming, icon, mcc, mnc, countryIso, false /* isEmbedded */,
+ null /* accessRules */, null /* accessRules */);
+ }
+
+ /**
* @hide
*/
public SubscriptionInfo(int id, String iccId, int simSlotIndex, CharSequence displayName,
CharSequence carrierName, int nameSource, int iconTint, String number, int roaming,
- Bitmap icon, int mcc, int mnc, String countryIso) {
+ Bitmap icon, int mcc, int mnc, String countryIso, boolean isEmbedded,
+ @Nullable UiccAccessRule[] accessRules) {
this(id, iccId, simSlotIndex, displayName, carrierName, nameSource, iconTint, number,
- roaming, icon, mcc, mnc, countryIso, false /* isEmbedded */,
- null /* accessRules */);
+ roaming, icon, mcc, mnc, countryIso, isEmbedded, accessRules, null /* cardId */);
}
/**
@@ -142,7 +159,7 @@ public class SubscriptionInfo implements Parcelable {
public SubscriptionInfo(int id, String iccId, int simSlotIndex, CharSequence displayName,
CharSequence carrierName, int nameSource, int iconTint, String number, int roaming,
Bitmap icon, int mcc, int mnc, String countryIso, boolean isEmbedded,
- @Nullable UiccAccessRule[] accessRules) {
+ @Nullable UiccAccessRule[] accessRules, String cardId) {
this.mId = id;
this.mIccId = iccId;
this.mSimSlotIndex = simSlotIndex;
@@ -158,6 +175,7 @@ public class SubscriptionInfo implements Parcelable {
this.mCountryIso = countryIso;
this.mIsEmbedded = isEmbedded;
this.mAccessRules = accessRules;
+ this.mCardId = cardId;
}
/**
@@ -387,6 +405,14 @@ public class SubscriptionInfo implements Parcelable {
return mAccessRules;
}
+ /**
+ * @return the ID of the SIM card which contains the subscription.
+ * @hide
+ */
+ public String getCardId() {
+ return this.mCardId;
+ }
+
public static final Parcelable.Creator<SubscriptionInfo> CREATOR = new Parcelable.Creator<SubscriptionInfo>() {
@Override
public SubscriptionInfo createFromParcel(Parcel source) {
@@ -405,10 +431,11 @@ public class SubscriptionInfo implements Parcelable {
Bitmap iconBitmap = Bitmap.CREATOR.createFromParcel(source);
boolean isEmbedded = source.readBoolean();
UiccAccessRule[] accessRules = source.createTypedArray(UiccAccessRule.CREATOR);
+ String cardId = source.readString();
return new SubscriptionInfo(id, iccId, simSlotIndex, displayName, carrierName,
nameSource, iconTint, number, dataRoaming, iconBitmap, mcc, mnc, countryIso,
- isEmbedded, accessRules);
+ isEmbedded, accessRules, cardId);
}
@Override
@@ -434,6 +461,7 @@ public class SubscriptionInfo implements Parcelable {
mIconBitmap.writeToParcel(dest, flags);
dest.writeBoolean(mIsEmbedded);
dest.writeTypedArray(mAccessRules, flags);
+ dest.writeString(mCardId);
}
@Override
@@ -459,11 +487,13 @@ public class SubscriptionInfo implements Parcelable {
@Override
public String toString() {
String iccIdToPrint = givePrintableIccid(mIccId);
+ String cardIdToPrint = givePrintableIccid(mCardId);
return "{id=" + mId + ", iccId=" + iccIdToPrint + " simSlotIndex=" + mSimSlotIndex
+ " displayName=" + mDisplayName + " carrierName=" + mCarrierName
+ " nameSource=" + mNameSource + " iconTint=" + mIconTint
+ " dataRoaming=" + mDataRoaming + " iconBitmap=" + mIconBitmap + " mcc " + mMcc
+ " mnc " + mMnc + " isEmbedded " + mIsEmbedded
- + " accessRules " + Arrays.toString(mAccessRules) + "}";
+ + " accessRules " + Arrays.toString(mAccessRules)
+ + " cardId=" + cardIdToPrint + "}";
}
}
diff --git a/telephony/java/android/telephony/SubscriptionManager.java b/telephony/java/android/telephony/SubscriptionManager.java
index 423dc80af54d..57f4cf28d90d 100644
--- a/telephony/java/android/telephony/SubscriptionManager.java
+++ b/telephony/java/android/telephony/SubscriptionManager.java
@@ -16,6 +16,10 @@
package android.telephony;
+import static android.net.NetworkPolicyManager.OVERRIDE_CONGESTED;
+import static android.net.NetworkPolicyManager.OVERRIDE_UNMETERED;
+
+import android.annotation.DurationMillisLong;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.annotation.RequiresPermission;
@@ -30,6 +34,7 @@ import android.content.pm.PackageManager;
import android.content.res.Configuration;
import android.content.res.Resources;
import android.net.INetworkPolicyManager;
+import android.net.NetworkCapabilities;
import android.net.Uri;
import android.os.Handler;
import android.os.Looper;
@@ -38,7 +43,6 @@ import android.os.RemoteException;
import android.os.ServiceManager;
import android.os.ServiceManager.ServiceNotFoundException;
import android.util.DisplayMetrics;
-import android.util.Log;
import com.android.internal.telephony.IOnSubscriptionsChangedListener;
import com.android.internal.telephony.ISub;
@@ -280,6 +284,14 @@ public class SubscriptionManager {
public static final String IS_EMBEDDED = "is_embedded";
/**
+ * TelephonyProvider column name for SIM card identifier. For UICC card it is the ICCID of the
+ * current enabled profile on the card, while for eUICC card it is the EID of the card.
+ * <P>Type: TEXT (String)</P>
+ * @hide
+ */
+ public static final String CARD_ID = "card_id";
+
+ /**
* TelephonyProvider column name for the encoded {@link UiccAccessRule}s from
* {@link UiccAccessRule#encodeRules}. Only present if {@link #IS_EMBEDDED} is 1.
* <p>TYPE: BLOB
@@ -1738,6 +1750,75 @@ public class SubscriptionManager {
}
/**
+ * Temporarily override the billing relationship plan between a carrier and
+ * a specific subscriber to be considered unmetered. This will be reflected
+ * to apps via {@link NetworkCapabilities#NET_CAPABILITY_NOT_METERED}.
+ * <p>
+ * This method is only accessible to the following narrow set of apps:
+ * <ul>
+ * <li>The carrier app for this subscriberId, as determined by
+ * {@link TelephonyManager#hasCarrierPrivileges()}.
+ * <li>The carrier app explicitly delegated access through
+ * {@link CarrierConfigManager#KEY_CONFIG_PLANS_PACKAGE_OVERRIDE_STRING}.
+ * </ul>
+ *
+ * @param subId the subscriber this override applies to.
+ * @param overrideUnmetered set if the billing relationship should be
+ * considered unmetered.
+ * @param timeoutMillis the timeout after which the requested override will
+ * be automatically cleared, or {@code 0} to leave in the
+ * requested state until explicitly cleared, or the next reboot,
+ * whichever happens first.
+ * @hide
+ */
+ @SystemApi
+ public void setSubscriptionOverrideUnmetered(int subId, boolean overrideUnmetered,
+ @DurationMillisLong long timeoutMillis) {
+ try {
+ final int overrideValue = overrideUnmetered ? OVERRIDE_UNMETERED : 0;
+ mNetworkPolicy.setSubscriptionOverride(subId, OVERRIDE_UNMETERED, overrideValue,
+ timeoutMillis, mContext.getOpPackageName());
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
+
+ /**
+ * Temporarily override the billing relationship plan between a carrier and
+ * a specific subscriber to be considered congested. This will cause the
+ * device to delay certain network requests when possible, such as developer
+ * jobs that are willing to run in a flexible time window.
+ * <p>
+ * This method is only accessible to the following narrow set of apps:
+ * <ul>
+ * <li>The carrier app for this subscriberId, as determined by
+ * {@link TelephonyManager#hasCarrierPrivileges()}.
+ * <li>The carrier app explicitly delegated access through
+ * {@link CarrierConfigManager#KEY_CONFIG_PLANS_PACKAGE_OVERRIDE_STRING}.
+ * </ul>
+ *
+ * @param subId the subscriber this override applies to.
+ * @param overrideCongested set if the subscription should be considered
+ * congested.
+ * @param timeoutMillis the timeout after which the requested override will
+ * be automatically cleared, or {@code 0} to leave in the
+ * requested state until explicitly cleared, or the next reboot,
+ * whichever happens first.
+ * @hide
+ */
+ @SystemApi
+ public void setSubscriptionOverrideCongested(int subId, boolean overrideCongested,
+ @DurationMillisLong long timeoutMillis) {
+ try {
+ final int overrideValue = overrideCongested ? OVERRIDE_CONGESTED : 0;
+ mNetworkPolicy.setSubscriptionOverride(subId, OVERRIDE_CONGESTED, overrideValue,
+ timeoutMillis, mContext.getOpPackageName());
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
+
+ /**
* Create an {@link Intent} that can be launched towards the carrier app
* that is currently defining the billing relationship plan through
* {@link #setSubscriptionPlans(int, List)}.
diff --git a/telephony/java/android/telephony/TelephonyManager.java b/telephony/java/android/telephony/TelephonyManager.java
index 8edc8b17c9e0..de9e691eadcf 100644
--- a/telephony/java/android/telephony/TelephonyManager.java
+++ b/telephony/java/android/telephony/TelephonyManager.java
@@ -2122,6 +2122,27 @@ public class TelephonyManager {
* carrier restrictions.
*/
public static final int SIM_STATE_CARD_RESTRICTED = 9;
+ /**
+ * SIM card state: Loaded: SIM card applications have been loaded
+ * @hide
+ */
+ @SystemApi
+ public static final int SIM_STATE_LOADED = 10;
+ /**
+ * SIM card state: SIM Card is present
+ * @hide
+ */
+ @SystemApi
+ public static final int SIM_STATE_PRESENT = 11;
+
+ /**
+ * Extra included in {@link Intent.ACTION_SIM_CARD_STATE_CHANGED} and
+ * {@link Intent.ACTION_SIM_APPLICATION_STATE_CHANGED} to indicate the card/application state.
+ *
+ * @hide
+ */
+ @SystemApi
+ public static final String EXTRA_SIM_STATE = "android.telephony.extra.SIM_STATE";
/**
* @return true if a ICC card is present
@@ -2168,6 +2189,14 @@ public class TelephonyManager {
* @see #SIM_STATE_CARD_RESTRICTED
*/
public int getSimState() {
+ int simState = getSimStateIncludingLoaded();
+ if (simState == SIM_STATE_LOADED) {
+ simState = SIM_STATE_READY;
+ }
+ return simState;
+ }
+
+ private int getSimStateIncludingLoaded() {
int slotIndex = getSlotIndex();
// slotIndex may be invalid due to sim being absent. In that case query all slots to get
// sim state
@@ -2186,7 +2215,63 @@ public class TelephonyManager {
"state as absent");
return SIM_STATE_ABSENT;
}
- return getSimState(slotIndex);
+ return SubscriptionManager.getSimStateForSlotIndex(slotIndex);
+ }
+
+ /**
+ * Returns a constant indicating the state of the default SIM card.
+ *
+ * @see #SIM_STATE_UNKNOWN
+ * @see #SIM_STATE_ABSENT
+ * @see #SIM_STATE_CARD_IO_ERROR
+ * @see #SIM_STATE_CARD_RESTRICTED
+ * @see #SIM_STATE_PRESENT
+ *
+ * @hide
+ */
+ @SystemApi
+ public int getSimCardState() {
+ int simCardState = getSimState();
+ switch (simCardState) {
+ case SIM_STATE_UNKNOWN:
+ case SIM_STATE_ABSENT:
+ case SIM_STATE_CARD_IO_ERROR:
+ case SIM_STATE_CARD_RESTRICTED:
+ return simCardState;
+ default:
+ return SIM_STATE_PRESENT;
+ }
+ }
+
+ /**
+ * Returns a constant indicating the state of the card applications on the default SIM card.
+ *
+ * @see #SIM_STATE_UNKNOWN
+ * @see #SIM_STATE_PIN_REQUIRED
+ * @see #SIM_STATE_PUK_REQUIRED
+ * @see #SIM_STATE_NETWORK_LOCKED
+ * @see #SIM_STATE_NOT_READY
+ * @see #SIM_STATE_PERM_DISABLED
+ * @see #SIM_STATE_LOADED
+ *
+ * @hide
+ */
+ @SystemApi
+ public int getSimApplicationState() {
+ int simApplicationState = getSimStateIncludingLoaded();
+ switch (simApplicationState) {
+ case SIM_STATE_UNKNOWN:
+ case SIM_STATE_ABSENT:
+ case SIM_STATE_CARD_IO_ERROR:
+ case SIM_STATE_CARD_RESTRICTED:
+ return SIM_STATE_UNKNOWN;
+ case SIM_STATE_READY:
+ // Ready is not a valid state anymore. The state that is broadcast goes from
+ // NOT_READY to either LOCKED or LOADED.
+ return SIM_STATE_NOT_READY;
+ default:
+ return simApplicationState;
+ }
}
/**
@@ -2207,6 +2292,9 @@ public class TelephonyManager {
*/
public int getSimState(int slotIndex) {
int simState = SubscriptionManager.getSimStateForSlotIndex(slotIndex);
+ if (simState == SIM_STATE_LOADED) {
+ simState = SIM_STATE_READY;
+ }
return simState;
}
diff --git a/telephony/java/com/android/internal/telephony/IccCardConstants.java b/telephony/java/com/android/internal/telephony/IccCardConstants.java
index f3d9335f4052..d57f9afa01e9 100644
--- a/telephony/java/com/android/internal/telephony/IccCardConstants.java
+++ b/telephony/java/com/android/internal/telephony/IccCardConstants.java
@@ -30,16 +30,14 @@ public class IccCardConstants {
public static final String INTENT_VALUE_ICC_NOT_READY = "NOT_READY";
/* ABSENT means ICC is missing */
public static final String INTENT_VALUE_ICC_ABSENT = "ABSENT";
+ /* PRESENT means ICC is present */
+ public static final String INTENT_VALUE_ICC_PRESENT = "PRESENT";
/* CARD_IO_ERROR means for three consecutive times there was SIM IO error */
static public final String INTENT_VALUE_ICC_CARD_IO_ERROR = "CARD_IO_ERROR";
/* CARD_RESTRICTED means card is present but not usable due to carrier restrictions */
static public final String INTENT_VALUE_ICC_CARD_RESTRICTED = "CARD_RESTRICTED";
/* LOCKED means ICC is locked by pin or by network */
public static final String INTENT_VALUE_ICC_LOCKED = "LOCKED";
- //TODO: we can remove this state in the future if Bug 18489776 analysis
- //#42's first race condition is resolved
- /* INTERNAL LOCKED means ICC is locked by pin or by network */
- public static final String INTENT_VALUE_ICC_INTERNAL_LOCKED = "INTERNAL_LOCKED";
/* READY means ICC is ready to access */
public static final String INTENT_VALUE_ICC_READY = "READY";
/* IMSI means ICC IMSI is ready in property */
@@ -77,7 +75,8 @@ public class IccCardConstants {
NOT_READY, /** ordinal(6) == {@See TelephonyManager#SIM_STATE_NOT_READY} */
PERM_DISABLED, /** ordinal(7) == {@See TelephonyManager#SIM_STATE_PERM_DISABLED} */
CARD_IO_ERROR, /** ordinal(8) == {@See TelephonyManager#SIM_STATE_CARD_IO_ERROR} */
- CARD_RESTRICTED;/** ordinal(9) == {@See TelephonyManager#SIM_STATE_CARD_RESTRICTED} */
+ CARD_RESTRICTED,/** ordinal(9) == {@See TelephonyManager#SIM_STATE_CARD_RESTRICTED} */
+ LOADED; /** ordinal(9) == {@See TelephonyManager#SIM_STATE_LOADED} */
public boolean isPinLocked() {
return ((this == PIN_REQUIRED) || (this == PUK_REQUIRED));
@@ -85,9 +84,9 @@ public class IccCardConstants {
public boolean iccCardExist() {
return ((this == PIN_REQUIRED) || (this == PUK_REQUIRED)
- || (this == NETWORK_LOCKED) || (this == READY)
+ || (this == NETWORK_LOCKED) || (this == READY) || (this == NOT_READY)
|| (this == PERM_DISABLED) || (this == CARD_IO_ERROR)
- || (this == CARD_RESTRICTED));
+ || (this == CARD_RESTRICTED) || (this == LOADED));
}
public static State intToState(int state) throws IllegalArgumentException {
@@ -102,6 +101,7 @@ public class IccCardConstants {
case 7: return PERM_DISABLED;
case 8: return CARD_IO_ERROR;
case 9: return CARD_RESTRICTED;
+ case 10: return LOADED;
default:
throw new IllegalArgumentException();
}
diff --git a/tests/UiBench/src/com/android/test/uibench/leanback/BrowseFragment.java b/tests/UiBench/src/com/android/test/uibench/leanback/BrowseFragment.java
index 11ea36132dcc..4ab38a66d504 100644
--- a/tests/UiBench/src/com/android/test/uibench/leanback/BrowseFragment.java
+++ b/tests/UiBench/src/com/android/test/uibench/leanback/BrowseFragment.java
@@ -24,6 +24,7 @@ public class BrowseFragment extends android.support.v17.leanback.app.BrowseSuppo
@Override
public void onCreate(Bundle savedInstanceState) {
+ TestHelper.initHeaderState(this);
super.onCreate(savedInstanceState);
BitmapLoader.clear();
TestHelper.initBackground(getActivity());
diff --git a/tests/UiBench/src/com/android/test/uibench/leanback/TestHelper.java b/tests/UiBench/src/com/android/test/uibench/leanback/TestHelper.java
index 2bf388501ba0..bf408f7475ac 100644
--- a/tests/UiBench/src/com/android/test/uibench/leanback/TestHelper.java
+++ b/tests/UiBench/src/com/android/test/uibench/leanback/TestHelper.java
@@ -40,6 +40,7 @@ public class TestHelper {
public static final String EXTRA_CARD_ROUND_RECT = "extra_card_round_rect";
public static final String EXTRA_ENTRANCE_TRANSITION = "extra_entrance_transition";
public static final String EXTRA_BITMAP_UPLOAD = "extra_bitmap_upload";
+ public static final String EXTRA_SHOW_FAST_LANE = "extra_show_fast_lane";
/**
* Dont change the default values, they gave baseline for measuring the performance
@@ -53,6 +54,7 @@ public class TestHelper {
static final boolean DEFAULT_CARD_SHADOW = true;
static final boolean DEFAULT_CARD_ROUND_RECT = true;
static final boolean DEFAULT_BITMAP_UPLOAD = true;
+ static final boolean DEFAULT_SHOW_FAST_LANE = true;
static long sCardIdSeed = 0;
static long sRowIdSeed = 0;
@@ -235,4 +237,11 @@ public class TestHelper {
manager.setBitmap(bitmap);
}
}
+
+ public static void initHeaderState(BrowseFragment fragment) {
+ if (!fragment.getActivity().getIntent()
+ .getBooleanExtra(EXTRA_SHOW_FAST_LANE, DEFAULT_SHOW_FAST_LANE)) {
+ fragment.setHeadersState(BrowseFragment.HEADERS_HIDDEN);
+ }
+ }
}
diff --git a/tests/net/java/android/net/NetworkStatsTest.java b/tests/net/java/android/net/NetworkStatsTest.java
index 25289ba92e24..035a4cd7601a 100644
--- a/tests/net/java/android/net/NetworkStatsTest.java
+++ b/tests/net/java/android/net/NetworkStatsTest.java
@@ -16,6 +16,9 @@
package android.net;
+import static android.net.NetworkStats.DEFAULT_NETWORK_ALL;
+import static android.net.NetworkStats.DEFAULT_NETWORK_NO;
+import static android.net.NetworkStats.DEFAULT_NETWORK_YES;
import static android.net.NetworkStats.METERED_ALL;
import static android.net.NetworkStats.METERED_NO;
import static android.net.NetworkStats.METERED_YES;
@@ -56,71 +59,75 @@ public class NetworkStatsTest {
@Test
public void testFindIndex() throws Exception {
final NetworkStats stats = new NetworkStats(TEST_START, 5)
- .addValues(TEST_IFACE, 100, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_NO, 1024L,
- 8L, 0L, 0L, 10)
- .addValues(TEST_IFACE, 101, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_NO, 0L, 0L,
- 1024L, 8L, 11)
- .addValues(TEST_IFACE, 101, SET_DEFAULT, TAG_NONE, METERED_YES, ROAMING_NO, 0L, 0L,
- 1024L, 8L, 11)
- .addValues(TEST_IFACE, 102, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_NO, 1024L,
- 8L, 1024L, 8L, 12)
- .addValues(TEST_IFACE, 102, SET_DEFAULT, TAG_NONE, METERED_YES, ROAMING_YES, 1024L,
- 8L, 1024L, 8L, 12);
+ .addValues(TEST_IFACE, 100, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_NO,
+ DEFAULT_NETWORK_YES, 1024L, 8L, 0L, 0L, 10)
+ .addValues(TEST_IFACE, 101, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_NO,
+ DEFAULT_NETWORK_NO, 0L, 0L, 1024L, 8L, 11)
+ .addValues(TEST_IFACE, 101, SET_DEFAULT, TAG_NONE, METERED_YES, ROAMING_NO,
+ DEFAULT_NETWORK_YES, 0L, 0L, 1024L, 8L, 11)
+ .addValues(TEST_IFACE, 102, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_NO,
+ DEFAULT_NETWORK_NO, 1024L, 8L, 1024L, 8L, 12)
+ .addValues(TEST_IFACE, 102, SET_DEFAULT, TAG_NONE, METERED_YES, ROAMING_YES,
+ DEFAULT_NETWORK_YES, 1024L, 8L, 1024L, 8L, 12);
assertEquals(4, stats.findIndex(TEST_IFACE, 102, SET_DEFAULT, TAG_NONE, METERED_YES,
- ROAMING_YES));
+ ROAMING_YES, DEFAULT_NETWORK_YES));
assertEquals(3, stats.findIndex(TEST_IFACE, 102, SET_DEFAULT, TAG_NONE, METERED_NO,
- ROAMING_NO));
+ ROAMING_NO, DEFAULT_NETWORK_NO));
assertEquals(2, stats.findIndex(TEST_IFACE, 101, SET_DEFAULT, TAG_NONE, METERED_YES,
- ROAMING_NO));
+ ROAMING_NO, DEFAULT_NETWORK_YES));
assertEquals(1, stats.findIndex(TEST_IFACE, 101, SET_DEFAULT, TAG_NONE, METERED_NO,
- ROAMING_NO));
+ ROAMING_NO, DEFAULT_NETWORK_NO));
assertEquals(0, stats.findIndex(TEST_IFACE, 100, SET_DEFAULT, TAG_NONE, METERED_NO,
- ROAMING_NO));
+ ROAMING_NO, DEFAULT_NETWORK_YES));
assertEquals(-1, stats.findIndex(TEST_IFACE, 6, SET_DEFAULT, TAG_NONE, METERED_NO,
- ROAMING_NO));
+ ROAMING_NO, DEFAULT_NETWORK_NO));
+ assertEquals(-1, stats.findIndex(TEST_IFACE, 100, SET_DEFAULT, TAG_NONE, METERED_NO,
+ ROAMING_NO, DEFAULT_NETWORK_NO));
}
@Test
public void testFindIndexHinted() {
final NetworkStats stats = new NetworkStats(TEST_START, 3)
- .addValues(TEST_IFACE, 100, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_NO, 1024L,
- 8L, 0L, 0L, 10)
- .addValues(TEST_IFACE, 101, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_NO, 0L, 0L,
- 1024L, 8L, 11)
- .addValues(TEST_IFACE, 102, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_NO, 1024L,
- 8L, 1024L, 8L, 12)
+ .addValues(TEST_IFACE, 100, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_NO,
+ DEFAULT_NETWORK_YES, 1024L, 8L, 0L, 0L, 10)
+ .addValues(TEST_IFACE, 101, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_NO,
+ DEFAULT_NETWORK_NO, 0L, 0L, 1024L, 8L, 11)
+ .addValues(TEST_IFACE, 102, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_NO,
+ DEFAULT_NETWORK_YES, 1024L, 8L, 1024L, 8L, 12)
.addValues(TEST_IFACE2, 100, SET_FOREGROUND, TAG_NONE, METERED_NO, ROAMING_NO,
- 1024L, 8L, 0L, 0L, 10)
- .addValues(TEST_IFACE2, 101, SET_DEFAULT, 0xF00D, METERED_NO, ROAMING_NO, 0L, 0L,
- 1024L, 8L, 11)
- .addValues(TEST_IFACE2, 101, SET_DEFAULT, 0xF00D, METERED_YES, ROAMING_NO, 0L, 0L,
- 1024L, 8L, 11)
- .addValues(TEST_IFACE2, 102, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_NO, 1024L,
- 8L, 1024L, 8L, 12)
- .addValues(TEST_IFACE2, 102, SET_DEFAULT, TAG_NONE, METERED_YES, ROAMING_YES, 1024L,
- 8L, 1024L, 8L, 12);
+ DEFAULT_NETWORK_NO, 1024L, 8L, 0L, 0L, 10)
+ .addValues(TEST_IFACE2, 101, SET_DEFAULT, 0xF00D, METERED_NO, ROAMING_NO,
+ DEFAULT_NETWORK_YES, 0L, 0L, 1024L, 8L, 11)
+ .addValues(TEST_IFACE2, 101, SET_DEFAULT, 0xF00D, METERED_YES, ROAMING_NO,
+ DEFAULT_NETWORK_NO, 0L, 0L, 1024L, 8L, 11)
+ .addValues(TEST_IFACE2, 102, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_NO,
+ DEFAULT_NETWORK_YES, 1024L, 8L, 1024L, 8L, 12)
+ .addValues(TEST_IFACE2, 102, SET_DEFAULT, TAG_NONE, METERED_YES, ROAMING_YES,
+ DEFAULT_NETWORK_NO, 1024L, 8L, 1024L, 8L, 12);
// verify that we correctly find across regardless of hinting
for (int hint = 0; hint < stats.size(); hint++) {
assertEquals(0, stats.findIndexHinted(TEST_IFACE, 100, SET_DEFAULT, TAG_NONE,
- METERED_NO, ROAMING_NO, hint));
+ METERED_NO, ROAMING_NO, DEFAULT_NETWORK_YES, hint));
assertEquals(1, stats.findIndexHinted(TEST_IFACE, 101, SET_DEFAULT, TAG_NONE,
- METERED_NO, ROAMING_NO, hint));
+ METERED_NO, ROAMING_NO, DEFAULT_NETWORK_NO, hint));
assertEquals(2, stats.findIndexHinted(TEST_IFACE, 102, SET_DEFAULT, TAG_NONE,
- METERED_NO, ROAMING_NO, hint));
+ METERED_NO, ROAMING_NO, DEFAULT_NETWORK_YES, hint));
assertEquals(3, stats.findIndexHinted(TEST_IFACE2, 100, SET_FOREGROUND, TAG_NONE,
- METERED_NO, ROAMING_NO, hint));
+ METERED_NO, ROAMING_NO, DEFAULT_NETWORK_NO, hint));
assertEquals(4, stats.findIndexHinted(TEST_IFACE2, 101, SET_DEFAULT, 0xF00D,
- METERED_NO, ROAMING_NO, hint));
+ METERED_NO, ROAMING_NO, DEFAULT_NETWORK_YES, hint));
assertEquals(5, stats.findIndexHinted(TEST_IFACE2, 101, SET_DEFAULT, 0xF00D,
- METERED_YES, ROAMING_NO, hint));
+ METERED_YES, ROAMING_NO, DEFAULT_NETWORK_NO, hint));
assertEquals(6, stats.findIndexHinted(TEST_IFACE2, 102, SET_DEFAULT, TAG_NONE,
- METERED_NO, ROAMING_NO, hint));
+ METERED_NO, ROAMING_NO, DEFAULT_NETWORK_YES, hint));
assertEquals(7, stats.findIndexHinted(TEST_IFACE2, 102, SET_DEFAULT, TAG_NONE,
- METERED_YES, ROAMING_YES, hint));
+ METERED_YES, ROAMING_YES, DEFAULT_NETWORK_NO, hint));
assertEquals(-1, stats.findIndexHinted(TEST_IFACE, 6, SET_DEFAULT, TAG_NONE,
- METERED_NO, ROAMING_NO, hint));
+ METERED_NO, ROAMING_NO, DEFAULT_NETWORK_YES, hint));
+ assertEquals(-1, stats.findIndexHinted(TEST_IFACE2, 102, SET_DEFAULT, TAG_NONE,
+ METERED_YES, ROAMING_YES, DEFAULT_NETWORK_YES, hint));
}
}
@@ -131,50 +138,50 @@ public class NetworkStatsTest {
assertEquals(0, stats.size());
assertEquals(4, stats.internalSize());
- stats.addValues(TEST_IFACE, TEST_UID, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_NO, 1L, 1L,
- 2L, 2L, 3);
- stats.addValues(TEST_IFACE, TEST_UID, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_NO, 2L, 2L,
- 2L, 2L, 4);
- stats.addValues(TEST_IFACE, TEST_UID, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_YES, 3L,
- 3L, 2L, 2L, 5);
- stats.addValues(TEST_IFACE, TEST_UID, SET_DEFAULT, TAG_NONE, METERED_YES, ROAMING_YES, 3L,
- 3L, 2L, 2L, 5);
+ stats.addValues(TEST_IFACE, TEST_UID, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_NO,
+ DEFAULT_NETWORK_YES, 1L, 1L, 2L, 2L, 3);
+ stats.addValues(TEST_IFACE, TEST_UID, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_NO,
+ DEFAULT_NETWORK_NO, 2L, 2L, 2L, 2L, 4);
+ stats.addValues(TEST_IFACE, TEST_UID, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_YES,
+ DEFAULT_NETWORK_YES, 3L, 3L, 2L, 2L, 5);
+ stats.addValues(TEST_IFACE, TEST_UID, SET_DEFAULT, TAG_NONE, METERED_YES, ROAMING_YES,
+ DEFAULT_NETWORK_NO, 3L, 3L, 2L, 2L, 5);
assertEquals(4, stats.size());
assertEquals(4, stats.internalSize());
- stats.addValues(TEST_IFACE, TEST_UID, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_NO, 4L,
- 40L, 4L, 40L, 7);
- stats.addValues(TEST_IFACE, TEST_UID, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_NO, 5L,
- 50L, 4L, 40L, 8);
- stats.addValues(TEST_IFACE, TEST_UID, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_NO, 6L,
- 60L, 5L, 50L, 10);
- stats.addValues(TEST_IFACE, TEST_UID, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_YES, 7L,
- 70L, 5L, 50L, 11);
- stats.addValues(TEST_IFACE, TEST_UID, SET_DEFAULT, TAG_NONE, METERED_YES, ROAMING_YES, 7L,
- 70L, 5L, 50L, 11);
+ stats.addValues(TEST_IFACE, TEST_UID, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_NO,
+ DEFAULT_NETWORK_NO, 4L, 40L, 4L, 40L, 7);
+ stats.addValues(TEST_IFACE, TEST_UID, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_NO,
+ DEFAULT_NETWORK_YES, 5L, 50L, 4L, 40L, 8);
+ stats.addValues(TEST_IFACE, TEST_UID, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_NO,
+ DEFAULT_NETWORK_NO, 6L, 60L, 5L, 50L, 10);
+ stats.addValues(TEST_IFACE, TEST_UID, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_YES,
+ DEFAULT_NETWORK_YES, 7L, 70L, 5L, 50L, 11);
+ stats.addValues(TEST_IFACE, TEST_UID, SET_DEFAULT, TAG_NONE, METERED_YES, ROAMING_YES,
+ DEFAULT_NETWORK_NO, 7L, 70L, 5L, 50L, 11);
assertEquals(9, stats.size());
assertTrue(stats.internalSize() >= 9);
assertValues(stats, 0, TEST_IFACE, TEST_UID, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_NO,
- 1L, 1L, 2L, 2L, 3);
+ DEFAULT_NETWORK_YES, 1L, 1L, 2L, 2L, 3);
assertValues(stats, 1, TEST_IFACE, TEST_UID, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_NO,
- 2L, 2L, 2L, 2L, 4);
+ DEFAULT_NETWORK_NO, 2L, 2L, 2L, 2L, 4);
assertValues(stats, 2, TEST_IFACE, TEST_UID, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_YES,
- 3L, 3L, 2L, 2L, 5);
+ DEFAULT_NETWORK_YES, 3L, 3L, 2L, 2L, 5);
assertValues(stats, 3, TEST_IFACE, TEST_UID, SET_DEFAULT, TAG_NONE, METERED_YES,
- ROAMING_YES, 3L, 3L, 2L, 2L, 5);
+ ROAMING_YES, DEFAULT_NETWORK_NO, 3L, 3L, 2L, 2L, 5);
assertValues(stats, 4, TEST_IFACE, TEST_UID, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_NO,
- 4L, 40L, 4L, 40L, 7);
+ DEFAULT_NETWORK_NO, 4L, 40L, 4L, 40L, 7);
assertValues(stats, 5, TEST_IFACE, TEST_UID, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_NO,
- 5L, 50L, 4L, 40L, 8);
+ DEFAULT_NETWORK_YES, 5L, 50L, 4L, 40L, 8);
assertValues(stats, 6, TEST_IFACE, TEST_UID, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_NO,
- 6L, 60L, 5L, 50L, 10);
+ DEFAULT_NETWORK_NO, 6L, 60L, 5L, 50L, 10);
assertValues(stats, 7, TEST_IFACE, TEST_UID, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_YES,
- 7L, 70L, 5L, 50L, 11);
+ DEFAULT_NETWORK_YES, 7L, 70L, 5L, 50L, 11);
assertValues(stats, 8, TEST_IFACE, TEST_UID, SET_DEFAULT, TAG_NONE, METERED_YES,
- ROAMING_YES, 7L, 70L, 5L, 50L, 11);
+ ROAMING_YES, DEFAULT_NETWORK_NO, 7L, 70L, 5L, 50L, 11);
}
@Test
@@ -187,17 +194,17 @@ public class NetworkStatsTest {
-128L, -1L, -1);
assertValues(stats, 0, TEST_IFACE, 1001, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_NO,
- 384L, 3L, 128L, 1L, 9);
- assertValues(stats, 1, TEST_IFACE, 1001, SET_DEFAULT, 0xff, METERED_NO, ROAMING_NO, 128L,
- 1L, 128L, 1L, 2);
+ DEFAULT_NETWORK_NO, 384L, 3L, 128L, 1L, 9);
+ assertValues(stats, 1, TEST_IFACE, 1001, SET_DEFAULT, 0xff, METERED_NO, ROAMING_NO,
+ DEFAULT_NETWORK_NO, 128L, 1L, 128L, 1L, 2);
// now try combining that should create row
stats.combineValues(TEST_IFACE, 5005, SET_DEFAULT, TAG_NONE, 128L, 1L, 128L, 1L, 3);
assertValues(stats, 2, TEST_IFACE, 5005, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_NO,
- 128L, 1L, 128L, 1L, 3);
+ DEFAULT_NETWORK_NO, 128L, 1L, 128L, 1L, 3);
stats.combineValues(TEST_IFACE, 5005, SET_DEFAULT, TAG_NONE, 128L, 1L, 128L, 1L, 3);
assertValues(stats, 2, TEST_IFACE, 5005, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_NO,
- 256L, 2L, 256L, 2L, 6);
+ DEFAULT_NETWORK_NO, 256L, 2L, 256L, 2L, 6);
}
@Test
@@ -213,10 +220,10 @@ public class NetworkStatsTest {
final NetworkStats result = after.subtract(before);
// identical data should result in zero delta
- assertValues(result, 0, TEST_IFACE, 100, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_NO, 0L,
- 0L, 0L, 0L, 0);
- assertValues(result, 1, TEST_IFACE, 101, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_NO, 0L,
- 0L, 0L, 0L, 0);
+ assertValues(result, 0, TEST_IFACE, 100, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_NO,
+ DEFAULT_NETWORK_NO, 0L, 0L, 0L, 0L, 0);
+ assertValues(result, 1, TEST_IFACE, 101, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_NO,
+ DEFAULT_NETWORK_NO, 0L, 0L, 0L, 0L, 0);
}
@Test
@@ -232,10 +239,10 @@ public class NetworkStatsTest {
final NetworkStats result = after.subtract(before);
// expect delta between measurements
- assertValues(result, 0, TEST_IFACE, 100, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_NO, 1L,
- 1L, 2L, 1L, 4);
- assertValues(result, 1, TEST_IFACE, 101, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_NO, 3L,
- 1L, 4L, 1L, 8);
+ assertValues(result, 0, TEST_IFACE, 100, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_NO,
+ DEFAULT_NETWORK_NO, 1L, 1L, 2L, 1L, 4);
+ assertValues(result, 1, TEST_IFACE, 101, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_NO,
+ DEFAULT_NETWORK_NO, 3L, 1L, 4L, 1L, 8);
}
@Test
@@ -252,12 +259,12 @@ public class NetworkStatsTest {
final NetworkStats result = after.subtract(before);
// its okay to have new rows
- assertValues(result, 0, TEST_IFACE, 100, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_NO, 0L,
- 0L, 0L, 0L, 0);
- assertValues(result, 1, TEST_IFACE, 101, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_NO, 0L,
- 0L, 0L, 0L, 0);
+ assertValues(result, 0, TEST_IFACE, 100, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_NO,
+ DEFAULT_NETWORK_NO, 0L, 0L, 0L, 0L, 0);
+ assertValues(result, 1, TEST_IFACE, 101, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_NO,
+ DEFAULT_NETWORK_NO, 0L, 0L, 0L, 0L, 0);
assertValues(result, 2, TEST_IFACE, 102, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_NO,
- 1024L, 8L, 1024L, 8L, 20);
+ DEFAULT_NETWORK_NO, 1024L, 8L, 1024L, 8L, 20);
}
@Test
@@ -274,7 +281,7 @@ public class NetworkStatsTest {
// should silently drop omitted rows
assertEquals(1, result.size());
assertValues(result, 0, TEST_IFACE2, UID_ALL, SET_DEFAULT, TAG_NONE, METERED_NO,
- ROAMING_NO, 1L, 2L, 3L, 4L, 0);
+ ROAMING_NO, DEFAULT_NETWORK_NO, 1L, 2L, 3L, 4L, 0);
assertEquals(4L, result.getTotalBytes());
}
@@ -301,21 +308,21 @@ public class NetworkStatsTest {
assertEquals(64L, uidTag.getTotalBytes());
final NetworkStats uidMetered = new NetworkStats(TEST_START, 3)
- .addValues(TEST_IFACE, 100, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_NO, 32L, 0L,
- 0L, 0L, 0L)
- .addValues(TEST_IFACE, 101, SET_DEFAULT, TAG_NONE, METERED_YES, ROAMING_NO, 32L, 0L,
- 0L, 0L, 0L)
- .addValues(TEST_IFACE, 101, SET_DEFAULT, TAG_NONE, METERED_YES, ROAMING_NO, 32L, 0L,
- 0L, 0L, 0L);
+ .addValues(TEST_IFACE, 100, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_NO,
+ DEFAULT_NETWORK_YES, 32L, 0L, 0L, 0L, 0L)
+ .addValues(TEST_IFACE, 101, SET_DEFAULT, TAG_NONE, METERED_YES, ROAMING_NO,
+ DEFAULT_NETWORK_NO, 32L, 0L, 0L, 0L, 0L)
+ .addValues(TEST_IFACE, 101, SET_DEFAULT, TAG_NONE, METERED_YES, ROAMING_NO,
+ DEFAULT_NETWORK_YES, 32L, 0L, 0L, 0L, 0L);
assertEquals(96L, uidMetered.getTotalBytes());
final NetworkStats uidRoaming = new NetworkStats(TEST_START, 3)
- .addValues(TEST_IFACE, 100, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_NO, 32L, 0L,
- 0L, 0L, 0L)
- .addValues(TEST_IFACE, 101, SET_DEFAULT, TAG_NONE, METERED_YES, ROAMING_NO, 32L, 0L,
- 0L, 0L, 0L)
- .addValues(TEST_IFACE, 101, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_YES, 32L, 0L,
- 0L, 0L, 0L);
+ .addValues(TEST_IFACE, 100, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_NO,
+ DEFAULT_NETWORK_YES, 32L, 0L, 0L, 0L, 0L)
+ .addValues(TEST_IFACE, 101, SET_DEFAULT, TAG_NONE, METERED_YES, ROAMING_NO,
+ DEFAULT_NETWORK_NO, 32L, 0L, 0L, 0L, 0L)
+ .addValues(TEST_IFACE, 101, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_YES,
+ DEFAULT_NETWORK_YES, 32L, 0L, 0L, 0L, 0L);
assertEquals(96L, uidRoaming.getTotalBytes());
}
@@ -331,38 +338,38 @@ public class NetworkStatsTest {
@Test
public void testGroupedByIfaceAll() throws Exception {
final NetworkStats uidStats = new NetworkStats(TEST_START, 3)
- .addValues(IFACE_ALL, 100, SET_ALL, TAG_NONE, METERED_NO, ROAMING_NO, 128L, 8L, 0L,
- 2L, 20L)
- .addValues(IFACE_ALL, 101, SET_FOREGROUND, TAG_NONE, METERED_YES, ROAMING_NO, 128L,
- 8L, 0L, 2L, 20L)
- .addValues(IFACE_ALL, 101, SET_ALL, TAG_NONE, METERED_NO, ROAMING_YES, 128L, 8L, 0L,
- 2L, 20L);
+ .addValues(IFACE_ALL, 100, SET_ALL, TAG_NONE, METERED_NO, ROAMING_NO,
+ DEFAULT_NETWORK_YES, 128L, 8L, 0L, 2L, 20L)
+ .addValues(IFACE_ALL, 101, SET_FOREGROUND, TAG_NONE, METERED_YES, ROAMING_NO,
+ DEFAULT_NETWORK_NO, 128L, 8L, 0L, 2L, 20L)
+ .addValues(IFACE_ALL, 101, SET_ALL, TAG_NONE, METERED_NO, ROAMING_YES,
+ DEFAULT_NETWORK_YES, 128L, 8L, 0L, 2L, 20L);
final NetworkStats grouped = uidStats.groupedByIface();
assertEquals(3, uidStats.size());
assertEquals(1, grouped.size());
assertValues(grouped, 0, IFACE_ALL, UID_ALL, SET_ALL, TAG_NONE, METERED_ALL, ROAMING_ALL,
- 384L, 24L, 0L, 6L, 0L);
+ DEFAULT_NETWORK_ALL, 384L, 24L, 0L, 6L, 0L);
}
@Test
public void testGroupedByIface() throws Exception {
final NetworkStats uidStats = new NetworkStats(TEST_START, 7)
- .addValues(TEST_IFACE, 100, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_NO, 128L, 8L,
- 0L, 2L, 20L)
- .addValues(TEST_IFACE2, 100, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_NO, 512L,
- 32L, 0L, 0L, 0L)
- .addValues(TEST_IFACE2, 100, SET_DEFAULT, 0xF00D, METERED_NO, ROAMING_NO, 64L, 4L,
- 0L, 0L, 0L)
- .addValues(TEST_IFACE2, 100, SET_FOREGROUND, TAG_NONE, METERED_NO, ROAMING_NO, 512L,
- 32L, 0L, 0L, 0L)
- .addValues(TEST_IFACE, 101, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_NO, 128L, 8L,
- 0L, 0L, 0L)
- .addValues(TEST_IFACE, 101, SET_DEFAULT, 0xF00D, METERED_YES, ROAMING_NO, 128L, 8L,
- 0L, 0L, 0L)
- .addValues(TEST_IFACE, 101, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_YES, 128L,
- 8L, 0L, 0L, 0L);
+ .addValues(TEST_IFACE, 100, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_NO,
+ DEFAULT_NETWORK_YES, 128L, 8L, 0L, 2L, 20L)
+ .addValues(TEST_IFACE2, 100, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_NO,
+ DEFAULT_NETWORK_NO, 512L, 32L, 0L, 0L, 0L)
+ .addValues(TEST_IFACE2, 100, SET_DEFAULT, 0xF00D, METERED_NO, ROAMING_NO,
+ DEFAULT_NETWORK_YES, 64L, 4L, 0L, 0L, 0L)
+ .addValues(TEST_IFACE2, 100, SET_FOREGROUND, TAG_NONE, METERED_NO, ROAMING_NO,
+ DEFAULT_NETWORK_NO, 512L, 32L, 0L, 0L, 0L)
+ .addValues(TEST_IFACE, 101, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_NO,
+ DEFAULT_NETWORK_YES, 128L, 8L, 0L, 0L, 0L)
+ .addValues(TEST_IFACE, 101, SET_DEFAULT, 0xF00D, METERED_YES, ROAMING_NO,
+ DEFAULT_NETWORK_NO, 128L, 8L, 0L, 0L, 0L)
+ .addValues(TEST_IFACE, 101, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_YES,
+ DEFAULT_NETWORK_YES, 128L, 8L, 0L, 0L, 0L);
final NetworkStats grouped = uidStats.groupedByIface();
@@ -370,59 +377,59 @@ public class NetworkStatsTest {
assertEquals(2, grouped.size());
assertValues(grouped, 0, TEST_IFACE, UID_ALL, SET_ALL, TAG_NONE, METERED_ALL, ROAMING_ALL,
- 384L, 24L, 0L, 2L, 0L);
+ DEFAULT_NETWORK_ALL, 384L, 24L, 0L, 2L, 0L);
assertValues(grouped, 1, TEST_IFACE2, UID_ALL, SET_ALL, TAG_NONE, METERED_ALL, ROAMING_ALL,
- 1024L, 64L, 0L, 0L, 0L);
+ DEFAULT_NETWORK_ALL, 1024L, 64L, 0L, 0L, 0L);
}
@Test
public void testAddAllValues() {
final NetworkStats first = new NetworkStats(TEST_START, 5)
- .addValues(TEST_IFACE, 100, SET_DEFAULT, TAG_NONE, METERED_YES, ROAMING_NO, 32L, 0L,
- 0L, 0L, 0L)
- .addValues(TEST_IFACE, 100, SET_FOREGROUND, TAG_NONE, METERED_NO, ROAMING_NO, 32L,
- 0L, 0L, 0L, 0L)
- .addValues(TEST_IFACE, 100, SET_FOREGROUND, TAG_NONE, METERED_YES, ROAMING_YES, 32L,
- 0L, 0L, 0L, 0L);
+ .addValues(TEST_IFACE, 100, SET_DEFAULT, TAG_NONE, METERED_YES, ROAMING_NO,
+ DEFAULT_NETWORK_YES, 32L, 0L, 0L, 0L, 0L)
+ .addValues(TEST_IFACE, 100, SET_FOREGROUND, TAG_NONE, METERED_NO, ROAMING_NO,
+ DEFAULT_NETWORK_NO, 32L, 0L, 0L, 0L, 0L)
+ .addValues(TEST_IFACE, 100, SET_FOREGROUND, TAG_NONE, METERED_YES, ROAMING_YES,
+ DEFAULT_NETWORK_YES, 32L, 0L, 0L, 0L, 0L);
final NetworkStats second = new NetworkStats(TEST_START, 2)
- .addValues(TEST_IFACE, 100, SET_DEFAULT, TAG_NONE, METERED_YES, ROAMING_NO, 32L, 0L,
- 0L, 0L, 0L)
- .addValues(TEST_IFACE2, UID_ALL, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_NO, 32L,
- 0L, 0L, 0L, 0L)
- .addValues(TEST_IFACE, 100, SET_FOREGROUND, TAG_NONE, METERED_YES, ROAMING_YES, 32L,
- 0L, 0L, 0L, 0L);
+ .addValues(TEST_IFACE, 100, SET_DEFAULT, TAG_NONE, METERED_YES, ROAMING_NO,
+ DEFAULT_NETWORK_YES, 32L, 0L, 0L, 0L, 0L)
+ .addValues(TEST_IFACE2, UID_ALL, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_NO,
+ DEFAULT_NETWORK_NO, 32L, 0L, 0L, 0L, 0L)
+ .addValues(TEST_IFACE, 100, SET_FOREGROUND, TAG_NONE, METERED_YES, ROAMING_YES,
+ DEFAULT_NETWORK_YES, 32L, 0L, 0L, 0L, 0L);
first.combineAllValues(second);
assertEquals(4, first.size());
- assertValues(first, 0, TEST_IFACE, 100, SET_DEFAULT, TAG_NONE, METERED_YES, ROAMING_NO, 64L,
- 0L, 0L, 0L, 0L);
+ assertValues(first, 0, TEST_IFACE, 100, SET_DEFAULT, TAG_NONE, METERED_YES, ROAMING_NO,
+ DEFAULT_NETWORK_YES, 64L, 0L, 0L, 0L, 0L);
assertValues(first, 1, TEST_IFACE, 100, SET_FOREGROUND, TAG_NONE, METERED_NO, ROAMING_NO,
- 32L, 0L, 0L, 0L, 0L);
+ DEFAULT_NETWORK_NO, 32L, 0L, 0L, 0L, 0L);
assertValues(first, 2, TEST_IFACE, 100, SET_FOREGROUND, TAG_NONE, METERED_YES, ROAMING_YES,
- 64L, 0L, 0L, 0L, 0L);
+ DEFAULT_NETWORK_YES, 64L, 0L, 0L, 0L, 0L);
assertValues(first, 3, TEST_IFACE2, UID_ALL, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_NO,
- 32L, 0L, 0L, 0L, 0L);
+ DEFAULT_NETWORK_NO, 32L, 0L, 0L, 0L, 0L);
}
@Test
public void testGetTotal() {
final NetworkStats stats = new NetworkStats(TEST_START, 7)
- .addValues(TEST_IFACE, 100, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_NO, 128L, 8L,
- 0L, 2L, 20L)
- .addValues(TEST_IFACE2, 100, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_NO, 512L,
- 32L, 0L, 0L, 0L)
- .addValues(TEST_IFACE2, 100, SET_DEFAULT, 0xF00D, METERED_NO, ROAMING_NO, 64L, 4L,
- 0L, 0L, 0L)
- .addValues(TEST_IFACE2, 100, SET_FOREGROUND, TAG_NONE, METERED_NO, ROAMING_NO, 512L,
- 32L, 0L, 0L, 0L)
- .addValues(TEST_IFACE, 101, SET_DEFAULT, TAG_NONE, METERED_YES, ROAMING_NO, 128L,
- 8L, 0L, 0L, 0L)
- .addValues(TEST_IFACE, 101, SET_DEFAULT, 0xF00D, METERED_NO, ROAMING_NO, 128L, 8L,
- 0L, 0L, 0L)
- .addValues(TEST_IFACE, 100, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_YES, 128L,
- 8L, 0L, 0L, 0L);
+ .addValues(TEST_IFACE, 100, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_NO,
+ DEFAULT_NETWORK_YES, 128L, 8L, 0L, 2L, 20L)
+ .addValues(TEST_IFACE2, 100, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_NO,
+ DEFAULT_NETWORK_NO, 512L, 32L, 0L, 0L, 0L)
+ .addValues(TEST_IFACE2, 100, SET_DEFAULT, 0xF00D, METERED_NO, ROAMING_NO,
+ DEFAULT_NETWORK_YES, 64L, 4L, 0L, 0L, 0L)
+ .addValues(TEST_IFACE2, 100, SET_FOREGROUND, TAG_NONE, METERED_NO, ROAMING_NO,
+ DEFAULT_NETWORK_NO, 512L,32L, 0L, 0L, 0L)
+ .addValues(TEST_IFACE, 101, SET_DEFAULT, TAG_NONE, METERED_YES, ROAMING_NO,
+ DEFAULT_NETWORK_YES, 128L, 8L, 0L, 0L, 0L)
+ .addValues(TEST_IFACE, 101, SET_DEFAULT, 0xF00D, METERED_NO, ROAMING_NO,
+ DEFAULT_NETWORK_NO, 128L, 8L, 0L, 0L, 0L)
+ .addValues(TEST_IFACE, 100, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_YES,
+ DEFAULT_NETWORK_NO, 128L, 8L, 0L, 0L, 0L);
assertValues(stats.getTotal(null), 1408L, 88L, 0L, 2L, 20L);
assertValues(stats.getTotal(null, 100), 1280L, 80L, 0L, 2L, 20L);
@@ -449,9 +456,9 @@ public class NetworkStatsTest {
assertEquals(6, before.size());
assertEquals(2, after.size());
assertValues(after, 0, TEST_IFACE, 101, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_NO,
- 128L, 8L, 0L, 0L, 0L);
- assertValues(after, 1, TEST_IFACE, 101, SET_DEFAULT, 0xF00D, METERED_NO, ROAMING_NO, 128L,
- 8L, 0L, 0L, 0L);
+ DEFAULT_NETWORK_NO, 128L, 8L, 0L, 0L, 0L);
+ assertValues(after, 1, TEST_IFACE, 101, SET_DEFAULT, 0xF00D, METERED_NO, ROAMING_NO,
+ DEFAULT_NETWORK_NO, 128L, 8L, 0L, 0L, 0L);
}
@Test
@@ -489,90 +496,90 @@ public class NetworkStatsTest {
final String underlyingIface = "wlan0";
final int testTag1 = 8888;
NetworkStats delta = new NetworkStats(TEST_START, 17)
- .addValues(tunIface, 10100, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_NO, 39605L, 46L,
- 12259L, 55L, 0L)
- .addValues(tunIface, 10100, SET_FOREGROUND, TAG_NONE, METERED_NO, ROAMING_NO, 0L, 0L,
- 0L, 0L, 0L)
- .addValues(tunIface, 10120, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_NO, 72667L, 197L,
- 43909L, 241L, 0L)
- .addValues(tunIface, 10120, SET_FOREGROUND, TAG_NONE, METERED_NO, ROAMING_NO, 9297L,
- 17L, 4128L, 21L, 0L)
+ .addValues(tunIface, 10100, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_NO,
+ DEFAULT_NETWORK_NO, 39605L, 46L, 12259L, 55L, 0L)
+ .addValues(tunIface, 10100, SET_FOREGROUND, TAG_NONE, METERED_NO, ROAMING_NO,
+ DEFAULT_NETWORK_NO, 0L, 0L, 0L, 0L, 0L)
+ .addValues(tunIface, 10120, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_NO,
+ DEFAULT_NETWORK_NO, 72667L, 197L, 43909L, 241L, 0L)
+ .addValues(tunIface, 10120, SET_FOREGROUND, TAG_NONE, METERED_NO, ROAMING_NO,
+ DEFAULT_NETWORK_NO, 9297L, 17L, 4128L, 21L, 0L)
// VPN package also uses some traffic through unprotected network.
- .addValues(tunIface, tunUid, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_NO, 4983L, 10L,
- 1801L, 12L, 0L)
- .addValues(tunIface, tunUid, SET_FOREGROUND, TAG_NONE, METERED_NO, ROAMING_NO, 0L, 0L,
- 0L, 0L, 0L)
+ .addValues(tunIface, tunUid, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_NO,
+ DEFAULT_NETWORK_NO, 4983L, 10L, 1801L, 12L, 0L)
+ .addValues(tunIface, tunUid, SET_FOREGROUND, TAG_NONE, METERED_NO, ROAMING_NO,
+ DEFAULT_NETWORK_NO, 0L, 0L, 0L, 0L, 0L)
// Tag entries
- .addValues(tunIface, 10120, SET_DEFAULT, testTag1, METERED_NO, ROAMING_NO, 21691L, 41L,
- 13820L, 51L, 0L)
- .addValues(tunIface, 10120, SET_FOREGROUND, testTag1, METERED_NO, ROAMING_NO, 1281L, 2L,
- 665L, 2L, 0L)
+ .addValues(tunIface, 10120, SET_DEFAULT, testTag1, METERED_NO, ROAMING_NO,
+ DEFAULT_NETWORK_NO, 21691L, 41L, 13820L, 51L, 0L)
+ .addValues(tunIface, 10120, SET_FOREGROUND, testTag1, METERED_NO, ROAMING_NO,
+ DEFAULT_NETWORK_NO, 1281L, 2L, 665L, 2L, 0L)
// Irrelevant entries
- .addValues(TEST_IFACE, 10100, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_NO, 1685L, 5L,
- 2070L, 6L, 0L)
+ .addValues(TEST_IFACE, 10100, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_NO,
+ DEFAULT_NETWORK_NO, 1685L, 5L, 2070L, 6L, 0L)
// Underlying Iface entries
- .addValues(underlyingIface, 10100, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_NO, 5178L,
- 8L, 2139L, 11L, 0L)
- .addValues(underlyingIface, 10100, SET_FOREGROUND, TAG_NONE, METERED_NO, ROAMING_NO, 0L,
- 0L, 0L, 0L, 0L)
+ .addValues(underlyingIface, 10100, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_NO,
+ DEFAULT_NETWORK_NO, 5178L, 8L, 2139L, 11L, 0L)
+ .addValues(underlyingIface, 10100, SET_FOREGROUND, TAG_NONE, METERED_NO, ROAMING_NO,
+ DEFAULT_NETWORK_NO, 0L, 0L, 0L, 0L, 0L)
.addValues(underlyingIface, tunUid, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_NO,
- 149873L, 287L, 59217L /* smaller than sum(tun0) */,
+ DEFAULT_NETWORK_NO, 149873L, 287L, 59217L /* smaller than sum(tun0) */,
299L /* smaller than sum(tun0) */, 0L)
.addValues(underlyingIface, tunUid, SET_FOREGROUND, TAG_NONE, METERED_NO, ROAMING_NO,
- 0L, 0L, 0L, 0L, 0L);
+ DEFAULT_NETWORK_NO, 0L, 0L, 0L, 0L, 0L);
- assertTrue(delta.migrateTun(tunUid, tunIface, underlyingIface));
+ assertTrue(delta.toString(), delta.migrateTun(tunUid, tunIface, underlyingIface));
assertEquals(20, delta.size());
// tunIface and TEST_IFACE entries are not changed.
assertValues(delta, 0, tunIface, 10100, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_NO,
- 39605L, 46L, 12259L, 55L, 0L);
+ DEFAULT_NETWORK_NO, 39605L, 46L, 12259L, 55L, 0L);
assertValues(delta, 1, tunIface, 10100, SET_FOREGROUND, TAG_NONE, METERED_NO, ROAMING_NO,
- 0L, 0L, 0L, 0L, 0L);
+ DEFAULT_NETWORK_NO, 0L, 0L, 0L, 0L, 0L);
assertValues(delta, 2, tunIface, 10120, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_NO,
- 72667L, 197L, 43909L, 241L, 0L);
+ DEFAULT_NETWORK_NO, 72667L, 197L, 43909L, 241L, 0L);
assertValues(delta, 3, tunIface, 10120, SET_FOREGROUND, TAG_NONE, METERED_NO, ROAMING_NO,
- 9297L, 17L, 4128L, 21L, 0L);
+ DEFAULT_NETWORK_NO, 9297L, 17L, 4128L, 21L, 0L);
assertValues(delta, 4, tunIface, tunUid, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_NO,
- 4983L, 10L, 1801L, 12L, 0L);
+ DEFAULT_NETWORK_NO, 4983L, 10L, 1801L, 12L, 0L);
assertValues(delta, 5, tunIface, tunUid, SET_FOREGROUND, TAG_NONE, METERED_NO, ROAMING_NO,
- 0L, 0L, 0L, 0L, 0L);
+ DEFAULT_NETWORK_NO, 0L, 0L, 0L, 0L, 0L);
assertValues(delta, 6, tunIface, 10120, SET_DEFAULT, testTag1, METERED_NO, ROAMING_NO,
- 21691L, 41L, 13820L, 51L, 0L);
+ DEFAULT_NETWORK_NO, 21691L, 41L, 13820L, 51L, 0L);
assertValues(delta, 7, tunIface, 10120, SET_FOREGROUND, testTag1, METERED_NO, ROAMING_NO,
- 1281L, 2L, 665L, 2L, 0L);
+ DEFAULT_NETWORK_NO, 1281L, 2L, 665L, 2L, 0L);
assertValues(delta, 8, TEST_IFACE, 10100, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_NO,
- 1685L, 5L, 2070L, 6L, 0L);
+ DEFAULT_NETWORK_NO, 1685L, 5L, 2070L, 6L, 0L);
// Existing underlying Iface entries are updated
assertValues(delta, 9, underlyingIface, 10100, SET_DEFAULT, TAG_NONE, METERED_NO,
- ROAMING_NO, 44783L, 54L, 14178L, 62L, 0L);
+ ROAMING_NO, DEFAULT_NETWORK_NO, 44783L, 54L, 14178L, 62L, 0L);
assertValues(delta, 10, underlyingIface, 10100, SET_FOREGROUND, TAG_NONE, METERED_NO,
- ROAMING_NO, 0L, 0L, 0L, 0L, 0L);
+ ROAMING_NO, DEFAULT_NETWORK_NO, 0L, 0L, 0L, 0L, 0L);
// VPN underlying Iface entries are updated
assertValues(delta, 11, underlyingIface, tunUid, SET_DEFAULT, TAG_NONE, METERED_NO,
- ROAMING_NO, 28304L, 27L, 1L, 2L, 0L);
+ ROAMING_NO, DEFAULT_NETWORK_NO, 28304L, 27L, 1L, 2L, 0L);
assertValues(delta, 12, underlyingIface, tunUid, SET_FOREGROUND, TAG_NONE, METERED_NO,
- ROAMING_NO, 0L, 0L, 0L, 0L, 0L);
+ ROAMING_NO, DEFAULT_NETWORK_NO, 0L, 0L, 0L, 0L, 0L);
// New entries are added for new application's underlying Iface traffic
assertContains(delta, underlyingIface, 10120, SET_DEFAULT, TAG_NONE, METERED_NO,
- ROAMING_NO, 72667L, 197L, 43123L, 227L, 0L);
+ ROAMING_NO, DEFAULT_NETWORK_NO, 72667L, 197L, 43123L, 227L, 0L);
assertContains(delta, underlyingIface, 10120, SET_FOREGROUND, TAG_NONE, METERED_NO,
- ROAMING_NO, 9297L, 17L, 4054, 19L, 0L);
+ ROAMING_NO, DEFAULT_NETWORK_NO, 9297L, 17L, 4054, 19L, 0L);
assertContains(delta, underlyingIface, 10120, SET_DEFAULT, testTag1, METERED_NO,
- ROAMING_NO, 21691L, 41L, 13572L, 48L, 0L);
+ ROAMING_NO, DEFAULT_NETWORK_NO, 21691L, 41L, 13572L, 48L, 0L);
assertContains(delta, underlyingIface, 10120, SET_FOREGROUND, testTag1, METERED_NO,
- ROAMING_NO, 1281L, 2L, 653L, 1L, 0L);
+ ROAMING_NO, DEFAULT_NETWORK_NO, 1281L, 2L, 653L, 1L, 0L);
// New entries are added for debug purpose
assertContains(delta, underlyingIface, 10100, SET_DBG_VPN_IN, TAG_NONE, METERED_NO,
- ROAMING_NO, 39605L, 46L, 12039, 51, 0);
+ ROAMING_NO, DEFAULT_NETWORK_NO, 39605L, 46L, 12039, 51, 0);
assertContains(delta, underlyingIface, 10120, SET_DBG_VPN_IN, TAG_NONE, METERED_NO,
- ROAMING_NO, 81964, 214, 47177, 246, 0);
+ ROAMING_NO, DEFAULT_NETWORK_NO, 81964, 214, 47177, 246, 0);
assertContains(delta, underlyingIface, tunUid, SET_DBG_VPN_OUT, TAG_NONE, METERED_ALL,
- ROAMING_ALL, 121569, 260, 59216, 297, 0);
+ ROAMING_ALL, DEFAULT_NETWORK_ALL, 121569, 260, 59216, 297, 0);
}
@@ -587,79 +594,80 @@ public class NetworkStatsTest {
final String underlyingIface = "wlan0";
NetworkStats delta = new NetworkStats(TEST_START, 9)
// 2 different apps sent/receive data via tun0.
- .addValues(tunIface, 10100, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_NO, 50000L, 25L,
- 100000L, 50L, 0L)
- .addValues(tunIface, 20100, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_NO, 500L, 2L,
- 200L, 5L, 0L)
+ .addValues(tunIface, 10100, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_NO,
+ DEFAULT_NETWORK_NO, 50000L, 25L, 100000L, 50L, 0L)
+ .addValues(tunIface, 20100, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_NO,
+ DEFAULT_NETWORK_NO, 500L, 2L, 200L, 5L, 0L)
// VPN package resends data through the tunnel (with exaggerated overhead)
- .addValues(tunIface, tunUid, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_NO, 240000,
- 100L, 120000L, 60L, 0L)
+ .addValues(tunIface, tunUid, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_NO,
+ DEFAULT_NETWORK_NO, 240000, 100L, 120000L, 60L, 0L)
// 1 app already has some traffic on the underlying interface, the other doesn't yet
- .addValues(underlyingIface, 10100, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_NO, 1000L,
- 10L, 2000L, 20L, 0L)
+ .addValues(underlyingIface, 10100, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_NO,
+ DEFAULT_NETWORK_NO, 1000L, 10L, 2000L, 20L, 0L)
// Traffic through the underlying interface via the vpn app.
// This test should redistribute this data correctly.
.addValues(underlyingIface, tunUid, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_NO,
- 75500L, 37L, 130000L, 70L, 0L);
+ DEFAULT_NETWORK_NO, 75500L, 37L, 130000L, 70L, 0L);
assertTrue(delta.migrateTun(tunUid, tunIface, underlyingIface));
assertEquals(9, delta.size());
// tunIface entries should not be changed.
assertValues(delta, 0, tunIface, 10100, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_NO,
- 50000L, 25L, 100000L, 50L, 0L);
+ DEFAULT_NETWORK_NO, 50000L, 25L, 100000L, 50L, 0L);
assertValues(delta, 1, tunIface, 20100, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_NO,
- 500L, 2L, 200L, 5L, 0L);
+ DEFAULT_NETWORK_NO, 500L, 2L, 200L, 5L, 0L);
assertValues(delta, 2, tunIface, tunUid, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_NO,
- 240000L, 100L, 120000L, 60L, 0L);
+ DEFAULT_NETWORK_NO, 240000L, 100L, 120000L, 60L, 0L);
// Existing underlying Iface entries are updated
assertValues(delta, 3, underlyingIface, 10100, SET_DEFAULT, TAG_NONE, METERED_NO,
- ROAMING_NO, 51000L, 35L, 102000L, 70L, 0L);
+ ROAMING_NO, DEFAULT_NETWORK_NO, 51000L, 35L, 102000L, 70L, 0L);
// VPN underlying Iface entries are updated
assertValues(delta, 4, underlyingIface, tunUid, SET_DEFAULT, TAG_NONE, METERED_NO,
- ROAMING_NO, 25000L, 10L, 29800L, 15L, 0L);
+ ROAMING_NO, DEFAULT_NETWORK_NO, 25000L, 10L, 29800L, 15L, 0L);
// New entries are added for new application's underlying Iface traffic
assertContains(delta, underlyingIface, 20100, SET_DEFAULT, TAG_NONE, METERED_NO,
- ROAMING_NO, 500L, 2L, 200L, 5L, 0L);
+ ROAMING_NO, DEFAULT_NETWORK_NO, 500L, 2L, 200L, 5L, 0L);
// New entries are added for debug purpose
assertContains(delta, underlyingIface, 10100, SET_DBG_VPN_IN, TAG_NONE, METERED_NO,
- ROAMING_NO, 50000L, 25L, 100000L, 50L, 0L);
+ ROAMING_NO, DEFAULT_NETWORK_NO, 50000L, 25L, 100000L, 50L, 0L);
assertContains(delta, underlyingIface, 20100, SET_DBG_VPN_IN, TAG_NONE, METERED_NO,
- ROAMING_NO, 500, 2L, 200L, 5L, 0L);
+ ROAMING_NO, DEFAULT_NETWORK_NO, 500, 2L, 200L, 5L, 0L);
assertContains(delta, underlyingIface, tunUid, SET_DBG_VPN_OUT, TAG_NONE, METERED_ALL,
- ROAMING_ALL, 50500L, 27L, 100200L, 55, 0);
+ ROAMING_ALL, DEFAULT_NETWORK_ALL, 50500L, 27L, 100200L, 55, 0);
}
private static void assertContains(NetworkStats stats, String iface, int uid, int set,
- int tag, int metered, int roaming, long rxBytes, long rxPackets, long txBytes,
- long txPackets, long operations) {
- int index = stats.findIndex(iface, uid, set, tag, metered, roaming);
+ int tag, int metered, int roaming, int defaultNetwork, long rxBytes, long rxPackets,
+ long txBytes, long txPackets, long operations) {
+ int index = stats.findIndex(iface, uid, set, tag, metered, roaming, defaultNetwork);
assertTrue(index != -1);
- assertValues(stats, index, iface, uid, set, tag, metered, roaming,
+ assertValues(stats, index, iface, uid, set, tag, metered, roaming, defaultNetwork,
rxBytes, rxPackets, txBytes, txPackets, operations);
}
private static void assertValues(NetworkStats stats, int index, String iface, int uid, int set,
- int tag, int metered, int roaming, long rxBytes, long rxPackets, long txBytes,
- long txPackets, long operations) {
+ int tag, int metered, int roaming, int defaultNetwork, long rxBytes, long rxPackets,
+ long txBytes, long txPackets, long operations) {
final NetworkStats.Entry entry = stats.getValues(index, null);
- assertValues(entry, iface, uid, set, tag, metered, roaming);
+ assertValues(entry, iface, uid, set, tag, metered, roaming, defaultNetwork);
assertValues(entry, rxBytes, rxPackets, txBytes, txPackets, operations);
}
private static void assertValues(
NetworkStats.Entry entry, String iface, int uid, int set, int tag, int metered,
- int roaming) {
+ int roaming, int defaultNetwork) {
assertEquals(iface, entry.iface);
assertEquals(uid, entry.uid);
assertEquals(set, entry.set);
assertEquals(tag, entry.tag);
assertEquals(metered, entry.metered);
assertEquals(roaming, entry.roaming);
+ assertEquals(defaultNetwork, entry.defaultNetwork);
}
private static void assertValues(NetworkStats.Entry entry, long rxBytes, long rxPackets,
diff --git a/tests/net/java/com/android/internal/net/NetworkStatsFactoryTest.java b/tests/net/java/com/android/internal/net/NetworkStatsFactoryTest.java
index fb2bd79fed3a..56b8e608dad1 100644
--- a/tests/net/java/com/android/internal/net/NetworkStatsFactoryTest.java
+++ b/tests/net/java/com/android/internal/net/NetworkStatsFactoryTest.java
@@ -16,6 +16,7 @@
package com.android.internal.net;
+import static android.net.NetworkStats.DEFAULT_NETWORK_NO;
import static android.net.NetworkStats.METERED_NO;
import static android.net.NetworkStats.ROAMING_NO;
import static android.net.NetworkStats.SET_ALL;
@@ -240,7 +241,8 @@ public class NetworkStatsFactoryTest {
private static void assertStatsEntry(NetworkStats stats, String iface, int uid, int set,
int tag, long rxBytes, long txBytes) {
- final int i = stats.findIndex(iface, uid, set, tag, METERED_NO, ROAMING_NO);
+ final int i = stats.findIndex(iface, uid, set, tag, METERED_NO, ROAMING_NO,
+ DEFAULT_NETWORK_NO);
if (i < 0) {
fail(String.format("no NetworkStats for (iface: %s, uid: %d, set: %d, tag: %d)",
iface, uid, set, tag));
@@ -252,7 +254,8 @@ public class NetworkStatsFactoryTest {
private static void assertStatsEntry(NetworkStats stats, String iface, int uid, int set,
int tag, long rxBytes, long rxPackets, long txBytes, long txPackets) {
- final int i = stats.findIndex(iface, uid, set, tag, METERED_NO, ROAMING_NO);
+ final int i = stats.findIndex(iface, uid, set, tag, METERED_NO, ROAMING_NO,
+ DEFAULT_NETWORK_NO);
if (i < 0) {
fail(String.format("no NetworkStats for (iface: %s, uid: %d, set: %d, tag: %d)",
iface, uid, set, tag));
diff --git a/tests/net/java/com/android/server/ConnectivityServiceTest.java b/tests/net/java/com/android/server/ConnectivityServiceTest.java
index b8e37f3a10ea..70cacb3af009 100644
--- a/tests/net/java/com/android/server/ConnectivityServiceTest.java
+++ b/tests/net/java/com/android/server/ConnectivityServiceTest.java
@@ -3501,34 +3501,50 @@ public class ConnectivityServiceTest {
@Test
public void testStatsIfacesChanged() throws Exception {
mCellNetworkAgent = new MockNetworkAgent(TRANSPORT_CELLULAR);
+ mWiFiNetworkAgent = new MockNetworkAgent(TRANSPORT_WIFI);
+
+ Network[] onlyCell = new Network[]{mCellNetworkAgent.getNetwork()};
+ Network[] onlyWifi = new Network[]{mWiFiNetworkAgent.getNetwork()};
// Simple connection should have updated ifaces
mCellNetworkAgent.connect(false);
waitForIdle();
- verify(mStatsService, atLeastOnce()).forceUpdateIfaces();
+ verify(mStatsService, atLeastOnce()).forceUpdateIfaces(onlyCell);
+ reset(mStatsService);
+
+ // Default network switch should update ifaces.
+ mWiFiNetworkAgent.connect(false);
+ waitForIdle();
+ verify(mStatsService, atLeastOnce()).forceUpdateIfaces(onlyWifi);
+ reset(mStatsService);
+
+ // Disconnect should update ifaces.
+ mWiFiNetworkAgent.disconnect();
+ waitForIdle();
+ verify(mStatsService, atLeastOnce()).forceUpdateIfaces(onlyCell);
reset(mStatsService);
// Metered change should update ifaces
mCellNetworkAgent.addCapability(NetworkCapabilities.NET_CAPABILITY_NOT_METERED);
waitForIdle();
- verify(mStatsService, atLeastOnce()).forceUpdateIfaces();
+ verify(mStatsService, atLeastOnce()).forceUpdateIfaces(onlyCell);
reset(mStatsService);
mCellNetworkAgent.removeCapability(NetworkCapabilities.NET_CAPABILITY_NOT_METERED);
waitForIdle();
- verify(mStatsService, atLeastOnce()).forceUpdateIfaces();
+ verify(mStatsService, atLeastOnce()).forceUpdateIfaces(onlyCell);
reset(mStatsService);
// Captive portal change shouldn't update ifaces
mCellNetworkAgent.addCapability(NetworkCapabilities.NET_CAPABILITY_CAPTIVE_PORTAL);
waitForIdle();
- verify(mStatsService, never()).forceUpdateIfaces();
+ verify(mStatsService, never()).forceUpdateIfaces(onlyCell);
reset(mStatsService);
// Roaming change should update ifaces
mCellNetworkAgent.addCapability(NetworkCapabilities.NET_CAPABILITY_NOT_ROAMING);
waitForIdle();
- verify(mStatsService, atLeastOnce()).forceUpdateIfaces();
+ verify(mStatsService, atLeastOnce()).forceUpdateIfaces(onlyCell);
reset(mStatsService);
}
diff --git a/tests/net/java/com/android/server/net/NetworkStatsCollectionTest.java b/tests/net/java/com/android/server/net/NetworkStatsCollectionTest.java
index dbaf8e690e07..6f1433286ca4 100644
--- a/tests/net/java/com/android/server/net/NetworkStatsCollectionTest.java
+++ b/tests/net/java/com/android/server/net/NetworkStatsCollectionTest.java
@@ -210,7 +210,7 @@ public class NetworkStatsCollectionTest {
final NetworkStats.Entry entry = new NetworkStats.Entry();
final NetworkIdentitySet identSet = new NetworkIdentitySet();
identSet.add(new NetworkIdentity(TYPE_MOBILE, TelephonyManager.NETWORK_TYPE_UNKNOWN,
- TEST_IMSI, null, false, true));
+ TEST_IMSI, null, false, true, true));
int myUid = Process.myUid();
int otherUidInSameUser = Process.myUid() + 1;
@@ -465,7 +465,7 @@ public class NetworkStatsCollectionTest {
final NetworkStatsCollection large = new NetworkStatsCollection(HOUR_IN_MILLIS);
final NetworkIdentitySet ident = new NetworkIdentitySet();
ident.add(new NetworkIdentity(ConnectivityManager.TYPE_MOBILE, -1, TEST_IMSI, null,
- false, true));
+ false, true, true));
large.recordData(ident, UID_ALL, SET_ALL, TAG_NONE, TIME_A, TIME_B,
new NetworkStats.Entry(12_730_893_164L, 1, 0, 0, 0));
diff --git a/tests/net/java/com/android/server/net/NetworkStatsObserversTest.java b/tests/net/java/com/android/server/net/NetworkStatsObserversTest.java
index 2be5dae97a10..185c3ebfbcb9 100644
--- a/tests/net/java/com/android/server/net/NetworkStatsObserversTest.java
+++ b/tests/net/java/com/android/server/net/NetworkStatsObserversTest.java
@@ -18,6 +18,8 @@ package com.android.server.net;
import static android.net.ConnectivityManager.TYPE_MOBILE;
import static android.net.ConnectivityManager.TYPE_WIFI;
+import static android.net.NetworkStats.DEFAULT_NETWORK_NO;
+import static android.net.NetworkStats.DEFAULT_NETWORK_YES;
import static android.net.NetworkStats.METERED_NO;
import static android.net.NetworkStats.ROAMING_NO;
import static android.net.NetworkStats.SET_DEFAULT;
@@ -224,6 +226,15 @@ public class NetworkStatsObserversTest {
Mockito.verifyZeroInteractions(mockBinder);
}
+ private NetworkIdentitySet makeTestIdentSet() {
+ NetworkIdentitySet identSet = new NetworkIdentitySet();
+ identSet.add(new NetworkIdentity(
+ TYPE_MOBILE, TelephonyManager.NETWORK_TYPE_UNKNOWN,
+ IMSI_1, null /* networkId */, false /* roaming */, true /* metered */,
+ true /* defaultNetwork */));
+ return identSet;
+ }
+
@Test
public void testUpdateStats_initialSample_doesNotNotify() throws Exception {
DataUsageRequest inputRequest = new DataUsageRequest(
@@ -235,10 +246,7 @@ public class NetworkStatsObserversTest {
assertTrue(Objects.equals(sTemplateImsi1, request.template));
assertEquals(THRESHOLD_BYTES, request.thresholdInBytes);
- NetworkIdentitySet identSet = new NetworkIdentitySet();
- identSet.add(new NetworkIdentity(
- TYPE_MOBILE, TelephonyManager.NETWORK_TYPE_UNKNOWN,
- IMSI_1, null /* networkId */, false /* roaming */, true /* metered */));
+ NetworkIdentitySet identSet = makeTestIdentSet();
mActiveIfaces.put(TEST_IFACE, identSet);
// Baseline
@@ -263,10 +271,7 @@ public class NetworkStatsObserversTest {
assertTrue(Objects.equals(sTemplateImsi1, request.template));
assertEquals(THRESHOLD_BYTES, request.thresholdInBytes);
- NetworkIdentitySet identSet = new NetworkIdentitySet();
- identSet.add(new NetworkIdentity(
- TYPE_MOBILE, TelephonyManager.NETWORK_TYPE_UNKNOWN,
- IMSI_1, null /* networkId */, false /* roaming */, true /* metered */));
+ NetworkIdentitySet identSet = makeTestIdentSet();
mActiveIfaces.put(TEST_IFACE, identSet);
// Baseline
@@ -298,10 +303,7 @@ public class NetworkStatsObserversTest {
assertTrue(Objects.equals(sTemplateImsi1, request.template));
assertEquals(THRESHOLD_BYTES, request.thresholdInBytes);
- NetworkIdentitySet identSet = new NetworkIdentitySet();
- identSet.add(new NetworkIdentity(
- TYPE_MOBILE, TelephonyManager.NETWORK_TYPE_UNKNOWN,
- IMSI_1, null /* networkId */, false /* roaming */, true /* metered */));
+ NetworkIdentitySet identSet = makeTestIdentSet();
mActiveIfaces.put(TEST_IFACE, identSet);
// Baseline
@@ -334,17 +336,14 @@ public class NetworkStatsObserversTest {
assertTrue(Objects.equals(sTemplateImsi1, request.template));
assertEquals(THRESHOLD_BYTES, request.thresholdInBytes);
- NetworkIdentitySet identSet = new NetworkIdentitySet();
- identSet.add(new NetworkIdentity(
- TYPE_MOBILE, TelephonyManager.NETWORK_TYPE_UNKNOWN,
- IMSI_1, null /* networkId */, false /* roaming */, true /* metered */));
+ NetworkIdentitySet identSet = makeTestIdentSet();
mActiveUidIfaces.put(TEST_IFACE, identSet);
// Baseline
NetworkStats xtSnapshot = null;
NetworkStats uidSnapshot = new NetworkStats(TEST_START, 2 /* initialSize */)
.addValues(TEST_IFACE, UID_RED, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_NO,
- BASE_BYTES, 2L, BASE_BYTES, 2L, 0L);
+ DEFAULT_NETWORK_YES, BASE_BYTES, 2L, BASE_BYTES, 2L, 0L);
mStatsObservers.updateStats(
xtSnapshot, uidSnapshot, mActiveIfaces, mActiveUidIfaces,
VPN_INFO, TEST_START);
@@ -352,7 +351,8 @@ public class NetworkStatsObserversTest {
// Delta
uidSnapshot = new NetworkStats(TEST_START + 2 * MINUTE_IN_MILLIS, 2 /* initialSize */)
.addValues(TEST_IFACE, UID_RED, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_NO,
- BASE_BYTES + THRESHOLD_BYTES, 2L, BASE_BYTES + THRESHOLD_BYTES, 2L, 0L);
+ DEFAULT_NETWORK_NO, BASE_BYTES + THRESHOLD_BYTES, 2L,
+ BASE_BYTES + THRESHOLD_BYTES, 2L, 0L);
mStatsObservers.updateStats(
xtSnapshot, uidSnapshot, mActiveIfaces, mActiveUidIfaces,
VPN_INFO, TEST_START);
@@ -371,17 +371,14 @@ public class NetworkStatsObserversTest {
assertTrue(Objects.equals(sTemplateImsi1, request.template));
assertEquals(THRESHOLD_BYTES, request.thresholdInBytes);
- NetworkIdentitySet identSet = new NetworkIdentitySet();
- identSet.add(new NetworkIdentity(
- TYPE_MOBILE, TelephonyManager.NETWORK_TYPE_UNKNOWN,
- IMSI_1, null /* networkId */, false /* roaming */, true /* metered */));
+ NetworkIdentitySet identSet = makeTestIdentSet();
mActiveUidIfaces.put(TEST_IFACE, identSet);
// Baseline
NetworkStats xtSnapshot = null;
NetworkStats uidSnapshot = new NetworkStats(TEST_START, 2 /* initialSize */)
.addValues(TEST_IFACE, UID_RED, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_NO,
- BASE_BYTES, 2L, BASE_BYTES, 2L, 0L);
+ DEFAULT_NETWORK_NO, BASE_BYTES, 2L, BASE_BYTES, 2L, 0L);
mStatsObservers.updateStats(
xtSnapshot, uidSnapshot, mActiveIfaces, mActiveUidIfaces,
VPN_INFO, TEST_START);
@@ -389,7 +386,8 @@ public class NetworkStatsObserversTest {
// Delta
uidSnapshot = new NetworkStats(TEST_START + 2 * MINUTE_IN_MILLIS, 2 /* initialSize */)
.addValues(TEST_IFACE, UID_RED, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_NO,
- BASE_BYTES + THRESHOLD_BYTES, 2L, BASE_BYTES + THRESHOLD_BYTES, 2L, 0L);
+ DEFAULT_NETWORK_NO, BASE_BYTES + THRESHOLD_BYTES, 2L,
+ BASE_BYTES + THRESHOLD_BYTES, 2L, 0L);
mStatsObservers.updateStats(
xtSnapshot, uidSnapshot, mActiveIfaces, mActiveUidIfaces,
VPN_INFO, TEST_START);
@@ -407,17 +405,14 @@ public class NetworkStatsObserversTest {
assertTrue(Objects.equals(sTemplateImsi1, request.template));
assertEquals(THRESHOLD_BYTES, request.thresholdInBytes);
- NetworkIdentitySet identSet = new NetworkIdentitySet();
- identSet.add(new NetworkIdentity(
- TYPE_MOBILE, TelephonyManager.NETWORK_TYPE_UNKNOWN,
- IMSI_1, null /* networkId */, false /* roaming */, true /* metered */));
+ NetworkIdentitySet identSet = makeTestIdentSet();
mActiveUidIfaces.put(TEST_IFACE, identSet);
// Baseline
NetworkStats xtSnapshot = null;
NetworkStats uidSnapshot = new NetworkStats(TEST_START, 2 /* initialSize */)
.addValues(TEST_IFACE, UID_RED, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_NO,
- BASE_BYTES, 2L, BASE_BYTES, 2L, 0L);
+ DEFAULT_NETWORK_YES, BASE_BYTES, 2L, BASE_BYTES, 2L, 0L);
mStatsObservers.updateStats(
xtSnapshot, uidSnapshot, mActiveIfaces, mActiveUidIfaces,
VPN_INFO, TEST_START);
@@ -425,7 +420,8 @@ public class NetworkStatsObserversTest {
// Delta
uidSnapshot = new NetworkStats(TEST_START + 2 * MINUTE_IN_MILLIS, 2 /* initialSize */)
.addValues(TEST_IFACE, UID_RED, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_NO,
- BASE_BYTES + THRESHOLD_BYTES, 2L, BASE_BYTES + THRESHOLD_BYTES, 2L, 0L);
+ DEFAULT_NETWORK_YES, BASE_BYTES + THRESHOLD_BYTES, 2L,
+ BASE_BYTES + THRESHOLD_BYTES, 2L, 0L);
mStatsObservers.updateStats(
xtSnapshot, uidSnapshot, mActiveIfaces, mActiveUidIfaces,
VPN_INFO, TEST_START);
@@ -444,17 +440,14 @@ public class NetworkStatsObserversTest {
assertTrue(Objects.equals(sTemplateImsi1, request.template));
assertEquals(THRESHOLD_BYTES, request.thresholdInBytes);
- NetworkIdentitySet identSet = new NetworkIdentitySet();
- identSet.add(new NetworkIdentity(
- TYPE_MOBILE, TelephonyManager.NETWORK_TYPE_UNKNOWN,
- IMSI_1, null /* networkId */, false /* roaming */, true /* metered */));
+ NetworkIdentitySet identSet = makeTestIdentSet();
mActiveUidIfaces.put(TEST_IFACE, identSet);
// Baseline
NetworkStats xtSnapshot = null;
NetworkStats uidSnapshot = new NetworkStats(TEST_START, 2 /* initialSize */)
.addValues(TEST_IFACE, UID_ANOTHER_USER, SET_DEFAULT, TAG_NONE, METERED_NO,
- ROAMING_NO, BASE_BYTES, 2L, BASE_BYTES, 2L, 0L);
+ ROAMING_NO, DEFAULT_NETWORK_YES, BASE_BYTES, 2L, BASE_BYTES, 2L, 0L);
mStatsObservers.updateStats(
xtSnapshot, uidSnapshot, mActiveIfaces, mActiveUidIfaces,
VPN_INFO, TEST_START);
@@ -462,8 +455,8 @@ public class NetworkStatsObserversTest {
// Delta
uidSnapshot = new NetworkStats(TEST_START + 2 * MINUTE_IN_MILLIS, 2 /* initialSize */)
.addValues(TEST_IFACE, UID_ANOTHER_USER, SET_DEFAULT, TAG_NONE, METERED_NO,
- ROAMING_NO, BASE_BYTES + THRESHOLD_BYTES, 2L, BASE_BYTES + THRESHOLD_BYTES,
- 2L, 0L);
+ ROAMING_NO, DEFAULT_NETWORK_NO, BASE_BYTES + THRESHOLD_BYTES, 2L,
+ BASE_BYTES + THRESHOLD_BYTES, 2L, 0L);
mStatsObservers.updateStats(
xtSnapshot, uidSnapshot, mActiveIfaces, mActiveUidIfaces,
VPN_INFO, TEST_START);
diff --git a/tests/net/java/com/android/server/net/NetworkStatsServiceTest.java b/tests/net/java/com/android/server/net/NetworkStatsServiceTest.java
index 65be5ffb32a2..0f26edb28009 100644
--- a/tests/net/java/com/android/server/net/NetworkStatsServiceTest.java
+++ b/tests/net/java/com/android/server/net/NetworkStatsServiceTest.java
@@ -21,6 +21,9 @@ import static android.content.Intent.EXTRA_UID;
import static android.net.ConnectivityManager.TYPE_MOBILE;
import static android.net.ConnectivityManager.TYPE_WIFI;
import static android.net.ConnectivityManager.TYPE_WIMAX;
+import static android.net.NetworkStats.DEFAULT_NETWORK_ALL;
+import static android.net.NetworkStats.DEFAULT_NETWORK_NO;
+import static android.net.NetworkStats.DEFAULT_NETWORK_YES;
import static android.net.NetworkStats.IFACE_ALL;
import static android.net.NetworkStats.METERED_ALL;
import static android.net.NetworkStats.METERED_NO;
@@ -67,6 +70,7 @@ import android.net.IConnectivityManager;
import android.net.INetworkManagementEventObserver;
import android.net.INetworkStatsSession;
import android.net.LinkProperties;
+import android.net.Network;
import android.net.NetworkCapabilities;
import android.net.NetworkInfo;
import android.net.NetworkInfo.DetailedState;
@@ -136,6 +140,12 @@ public class NetworkStatsServiceTest {
private static final int UID_BLUE = 1002;
private static final int UID_GREEN = 1003;
+
+ private static final Network WIFI_NETWORK = new Network(100);
+ private static final Network MOBILE_NETWORK = new Network(101);
+ private static final Network[] NETWORKS_WIFI = new Network[]{ WIFI_NETWORK };
+ private static final Network[] NETWORKS_MOBILE = new Network[]{ MOBILE_NETWORK };
+
private static final long WAIT_TIMEOUT = 2 * 1000; // 2 secs
private static final int INVALID_TYPE = -1;
@@ -230,7 +240,7 @@ public class NetworkStatsServiceTest {
expectNetworkStatsUidDetail(buildEmptyStats());
expectBandwidthControlCheck();
- mService.forceUpdateIfaces();
+ mService.forceUpdateIfaces(NETWORKS_WIFI);
// verify service has empty history for wifi
assertNetworkTotal(sTemplateWifi, 0L, 0L, 0L, 0L, 0);
@@ -277,7 +287,7 @@ public class NetworkStatsServiceTest {
expectNetworkStatsUidDetail(buildEmptyStats());
expectBandwidthControlCheck();
- mService.forceUpdateIfaces();
+ mService.forceUpdateIfaces(NETWORKS_WIFI);
// verify service has empty history for wifi
assertNetworkTotal(sTemplateWifi, 0L, 0L, 0L, 0L, 0);
@@ -305,10 +315,10 @@ public class NetworkStatsServiceTest {
// verify service recorded history
assertNetworkTotal(sTemplateWifi, 1024L, 8L, 2048L, 16L, 0);
assertUidTotal(sTemplateWifi, UID_RED, 1024L, 8L, 512L, 4L, 10);
- assertUidTotal(sTemplateWifi, UID_RED, SET_DEFAULT, METERED_NO, ROAMING_NO, 512L, 4L, 256L,
- 2L, 4);
- assertUidTotal(sTemplateWifi, UID_RED, SET_FOREGROUND, METERED_NO, ROAMING_NO, 512L, 4L,
- 256L, 2L, 6);
+ assertUidTotal(sTemplateWifi, UID_RED, SET_DEFAULT, METERED_NO, ROAMING_NO,
+ DEFAULT_NETWORK_YES, 512L, 4L, 256L, 2L, 4);
+ assertUidTotal(sTemplateWifi, UID_RED, SET_FOREGROUND, METERED_NO, ROAMING_NO,
+ DEFAULT_NETWORK_YES, 512L, 4L, 256L, 2L, 6);
assertUidTotal(sTemplateWifi, UID_BLUE, 128L, 1L, 128L, 1L, 0);
@@ -330,10 +340,10 @@ public class NetworkStatsServiceTest {
// after systemReady(), we should have historical stats loaded again
assertNetworkTotal(sTemplateWifi, 1024L, 8L, 2048L, 16L, 0);
assertUidTotal(sTemplateWifi, UID_RED, 1024L, 8L, 512L, 4L, 10);
- assertUidTotal(sTemplateWifi, UID_RED, SET_DEFAULT, METERED_NO, ROAMING_NO, 512L, 4L, 256L,
- 2L, 4);
- assertUidTotal(sTemplateWifi, UID_RED, SET_FOREGROUND, METERED_NO, ROAMING_NO, 512L, 4L,
- 256L, 2L, 6);
+ assertUidTotal(sTemplateWifi, UID_RED, SET_DEFAULT, METERED_NO, ROAMING_NO,
+ DEFAULT_NETWORK_YES, 512L, 4L, 256L, 2L, 4);
+ assertUidTotal(sTemplateWifi, UID_RED, SET_FOREGROUND, METERED_NO, ROAMING_NO,
+ DEFAULT_NETWORK_YES, 512L, 4L, 256L, 2L, 6);
assertUidTotal(sTemplateWifi, UID_BLUE, 128L, 1L, 128L, 1L, 0);
}
@@ -355,7 +365,7 @@ public class NetworkStatsServiceTest {
expectNetworkStatsUidDetail(buildEmptyStats());
expectBandwidthControlCheck();
- mService.forceUpdateIfaces();
+ mService.forceUpdateIfaces(NETWORKS_WIFI);
// modify some number on wifi, and trigger poll event
@@ -400,7 +410,7 @@ public class NetworkStatsServiceTest {
expectNetworkStatsUidDetail(buildEmptyStats());
expectBandwidthControlCheck();
- mService.forceUpdateIfaces();
+ mService.forceUpdateIfaces(NETWORKS_MOBILE);
// create some traffic on first network
@@ -438,7 +448,7 @@ public class NetworkStatsServiceTest {
.addValues(TEST_IFACE, UID_BLUE, SET_DEFAULT, TAG_NONE, 512L, 4L, 0L, 0L, 0L));
expectBandwidthControlCheck();
- mService.forceUpdateIfaces();
+ mService.forceUpdateIfaces(NETWORKS_MOBILE);
forcePollAndWaitForIdle();
@@ -480,7 +490,7 @@ public class NetworkStatsServiceTest {
expectNetworkStatsUidDetail(buildEmptyStats());
expectBandwidthControlCheck();
- mService.forceUpdateIfaces();
+ mService.forceUpdateIfaces(NETWORKS_WIFI);
// create some traffic
@@ -542,7 +552,7 @@ public class NetworkStatsServiceTest {
expectNetworkStatsUidDetail(buildEmptyStats());
expectBandwidthControlCheck();
- mService.forceUpdateIfaces();
+ mService.forceUpdateIfaces(NETWORKS_MOBILE);
// create some traffic
@@ -572,7 +582,7 @@ public class NetworkStatsServiceTest {
.addValues(TEST_IFACE, UID_RED, SET_DEFAULT, 0xF00D, 512L, 4L, 512L, 4L, 0L));
expectBandwidthControlCheck();
- mService.forceUpdateIfaces();
+ mService.forceUpdateIfaces(NETWORKS_MOBILE);
forcePollAndWaitForIdle();
@@ -604,7 +614,7 @@ public class NetworkStatsServiceTest {
expectNetworkStatsUidDetail(buildEmptyStats());
expectBandwidthControlCheck();
- mService.forceUpdateIfaces();
+ mService.forceUpdateIfaces(NETWORKS_WIFI);
// create some traffic for two apps
@@ -640,12 +650,12 @@ public class NetworkStatsServiceTest {
NetworkStats stats = mSession.getSummaryForAllUid(
sTemplateWifi, Long.MIN_VALUE, Long.MAX_VALUE, true);
assertEquals(3, stats.size());
- assertValues(stats, IFACE_ALL, UID_RED, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_NO, 50L,
- 5L, 50L, 5L, 1);
- assertValues(stats, IFACE_ALL, UID_RED, SET_DEFAULT, 0xF00D, METERED_NO, ROAMING_NO, 10L,
- 1L, 10L, 1L, 1);
+ assertValues(stats, IFACE_ALL, UID_RED, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_NO,
+ DEFAULT_NETWORK_YES, 50L, 5L, 50L, 5L, 1);
+ assertValues(stats, IFACE_ALL, UID_RED, SET_DEFAULT, 0xF00D, METERED_NO, ROAMING_NO,
+ DEFAULT_NETWORK_YES, 10L, 1L, 10L, 1L, 1);
assertValues(stats, IFACE_ALL, UID_BLUE, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_NO,
- 2048L, 16L, 1024L, 8L, 0);
+ DEFAULT_NETWORK_YES, 2048L, 16L, 1024L, 8L, 0);
// now verify that recent history only contains one uid
final long currentTime = currentTimeMillis();
@@ -653,7 +663,7 @@ public class NetworkStatsServiceTest {
sTemplateWifi, currentTime - HOUR_IN_MILLIS, currentTime, true);
assertEquals(1, stats.size());
assertValues(stats, IFACE_ALL, UID_BLUE, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_NO,
- 1024L, 8L, 512L, 4L, 0);
+ DEFAULT_NETWORK_YES, 1024L, 8L, 512L, 4L, 0);
}
@Test
@@ -666,7 +676,7 @@ public class NetworkStatsServiceTest {
expectNetworkStatsUidDetail(buildEmptyStats());
expectBandwidthControlCheck();
- mService.forceUpdateIfaces();
+ mService.forceUpdateIfaces(NETWORKS_WIFI);
// create some initial traffic
@@ -707,14 +717,14 @@ public class NetworkStatsServiceTest {
final NetworkStats stats = mSession.getSummaryForAllUid(
sTemplateWifi, Long.MIN_VALUE, Long.MAX_VALUE, true);
assertEquals(4, stats.size());
- assertValues(stats, IFACE_ALL, UID_RED, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_NO, 128L,
- 2L, 128L, 2L, 1);
- assertValues(stats, IFACE_ALL, UID_RED, SET_DEFAULT, 0xF00D, METERED_NO, ROAMING_NO, 64L,
- 1L, 64L, 1L, 1);
+ assertValues(stats, IFACE_ALL, UID_RED, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_NO,
+ DEFAULT_NETWORK_YES, 128L, 2L, 128L, 2L, 1);
+ assertValues(stats, IFACE_ALL, UID_RED, SET_DEFAULT, 0xF00D, METERED_NO, ROAMING_NO,
+ DEFAULT_NETWORK_YES, 64L, 1L, 64L, 1L, 1);
assertValues(stats, IFACE_ALL, UID_RED, SET_FOREGROUND, TAG_NONE, METERED_NO, ROAMING_NO,
- 32L, 2L, 32L, 2L, 1);
- assertValues(stats, IFACE_ALL, UID_RED, SET_FOREGROUND, 0xFAAD, METERED_NO, ROAMING_NO, 1L,
- 1L, 1L, 1L, 1);
+ DEFAULT_NETWORK_YES, 32L, 2L, 32L, 2L, 1);
+ assertValues(stats, IFACE_ALL, UID_RED, SET_FOREGROUND, 0xFAAD, METERED_NO, ROAMING_NO,
+ DEFAULT_NETWORK_YES, 1L, 1L, 1L, 1L, 1);
}
@Test
@@ -727,7 +737,7 @@ public class NetworkStatsServiceTest {
expectNetworkStatsUidDetail(buildEmptyStats());
expectBandwidthControlCheck();
- mService.forceUpdateIfaces();
+ mService.forceUpdateIfaces(NETWORKS_WIFI);
// create some initial traffic
@@ -735,14 +745,14 @@ public class NetworkStatsServiceTest {
expectCurrentTime();
expectDefaultSettings();
expectNetworkStatsSummary(buildEmptyStats());
- // Note that all traffic from NetworkManagementService is tagged as METERED_NO and
- // ROAMING_NO, because metered and roaming isn't tracked at that layer. We layer it
- // on top by inspecting the iface properties.
+ // Note that all traffic from NetworkManagementService is tagged as METERED_NO, ROAMING_NO
+ // and DEFAULT_NETWORK_YES, because these three properties aren't tracked at that layer.
+ // We layer them on top by inspecting the iface properties.
expectNetworkStatsUidDetail(new NetworkStats(getElapsedRealtime(), 1)
- .addValues(TEST_IFACE, UID_RED, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_NO, 128L,
- 2L, 128L, 2L, 0L)
- .addValues(TEST_IFACE, UID_RED, SET_DEFAULT, 0xF00D, METERED_NO, ROAMING_NO, 64L,
- 1L, 64L, 1L, 0L));
+ .addValues(TEST_IFACE, UID_RED, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_NO,
+ DEFAULT_NETWORK_YES, 128L, 2L, 128L, 2L, 0L)
+ .addValues(TEST_IFACE, UID_RED, SET_DEFAULT, 0xF00D, METERED_NO, ROAMING_NO,
+ DEFAULT_NETWORK_YES, 64L, 1L, 64L, 1L, 0L));
mService.incrementOperationCount(UID_RED, 0xF00D, 1);
forcePollAndWaitForIdle();
@@ -754,9 +764,9 @@ public class NetworkStatsServiceTest {
sTemplateWifi, Long.MIN_VALUE, Long.MAX_VALUE, true);
assertEquals(2, stats.size());
assertValues(stats, IFACE_ALL, UID_RED, SET_DEFAULT, TAG_NONE, METERED_YES, ROAMING_NO,
- 128L, 2L, 128L, 2L, 1);
- assertValues(stats, IFACE_ALL, UID_RED, SET_DEFAULT, 0xF00D, METERED_YES, ROAMING_NO, 64L,
- 1L, 64L, 1L, 1);
+ DEFAULT_NETWORK_YES, 128L, 2L, 128L, 2L, 1);
+ assertValues(stats, IFACE_ALL, UID_RED, SET_DEFAULT, 0xF00D, METERED_YES, ROAMING_NO,
+ DEFAULT_NETWORK_YES, 64L, 1L, 64L, 1L, 1);
}
@Test
@@ -769,7 +779,7 @@ public class NetworkStatsServiceTest {
expectNetworkStatsUidDetail(buildEmptyStats());
expectBandwidthControlCheck();
- mService.forceUpdateIfaces();
+ mService.forceUpdateIfaces(NETWORKS_MOBILE);
// Create some traffic
@@ -782,9 +792,9 @@ public class NetworkStatsServiceTest {
// on top by inspecting the iface properties.
expectNetworkStatsUidDetail(new NetworkStats(getElapsedRealtime(), 1)
.addValues(TEST_IFACE, UID_RED, SET_DEFAULT, TAG_NONE, METERED_ALL, ROAMING_NO,
- 128L, 2L, 128L, 2L, 0L)
- .addValues(TEST_IFACE, UID_RED, SET_DEFAULT, 0xF00D, METERED_ALL, ROAMING_NO, 64L,
- 1L, 64L, 1L, 0L));
+ DEFAULT_NETWORK_YES, 128L, 2L, 128L, 2L, 0L)
+ .addValues(TEST_IFACE, UID_RED, SET_DEFAULT, 0xF00D, METERED_ALL, ROAMING_NO,
+ DEFAULT_NETWORK_YES, 64L, 1L, 64L, 1L, 0L));
forcePollAndWaitForIdle();
// verify service recorded history
@@ -795,9 +805,9 @@ public class NetworkStatsServiceTest {
sTemplateImsi1, Long.MIN_VALUE, Long.MAX_VALUE, true);
assertEquals(2, stats.size());
assertValues(stats, IFACE_ALL, UID_RED, SET_DEFAULT, TAG_NONE, METERED_ALL, ROAMING_YES,
- 128L, 2L, 128L, 2L, 0);
- assertValues(stats, IFACE_ALL, UID_RED, SET_DEFAULT, 0xF00D, METERED_ALL, ROAMING_YES, 64L,
- 1L, 64L, 1L, 0);
+ DEFAULT_NETWORK_YES, 128L, 2L, 128L, 2L, 0);
+ assertValues(stats, IFACE_ALL, UID_RED, SET_DEFAULT, 0xF00D, METERED_ALL, ROAMING_YES,
+ DEFAULT_NETWORK_YES, 64L, 1L, 64L, 1L, 0);
}
@Test
@@ -810,7 +820,7 @@ public class NetworkStatsServiceTest {
expectNetworkStatsUidDetail(buildEmptyStats());
expectBandwidthControlCheck();
- mService.forceUpdateIfaces();
+ mService.forceUpdateIfaces(NETWORKS_MOBILE);
// create some tethering traffic
@@ -855,7 +865,7 @@ public class NetworkStatsServiceTest {
expectNetworkStatsUidDetail(buildEmptyStats());
expectBandwidthControlCheck();
- mService.forceUpdateIfaces();
+ mService.forceUpdateIfaces(NETWORKS_WIFI);
// verify service has empty history for wifi
assertNetworkTotal(sTemplateWifi, 0L, 0L, 0L, 0L, 0);
@@ -976,18 +986,18 @@ public class NetworkStatsServiceTest {
// verify summary API
final NetworkStats stats = mSession.getSummaryForNetwork(template, start, end);
assertValues(stats, IFACE_ALL, UID_ALL, SET_ALL, TAG_NONE, METERED_ALL, ROAMING_ALL,
- rxBytes, rxPackets, txBytes, txPackets, operations);
+ DEFAULT_NETWORK_ALL, rxBytes, rxPackets, txBytes, txPackets, operations);
}
private void assertUidTotal(NetworkTemplate template, int uid, long rxBytes, long rxPackets,
long txBytes, long txPackets, int operations) throws Exception {
- assertUidTotal(template, uid, SET_ALL, METERED_ALL, ROAMING_ALL, rxBytes, rxPackets,
- txBytes, txPackets, operations);
+ assertUidTotal(template, uid, SET_ALL, METERED_ALL, ROAMING_ALL, DEFAULT_NETWORK_ALL,
+ rxBytes, rxPackets, txBytes, txPackets, operations);
}
private void assertUidTotal(NetworkTemplate template, int uid, int set, int metered,
- int roaming, long rxBytes, long rxPackets, long txBytes, long txPackets, int operations)
- throws Exception {
+ int roaming, int defaultNetwork, long rxBytes, long rxPackets, long txBytes,
+ long txPackets, int operations) throws Exception {
// verify history API
final NetworkStatsHistory history = mSession.getHistoryForUid(
template, uid, set, TAG_NONE, FIELD_ALL);
@@ -997,8 +1007,8 @@ public class NetworkStatsServiceTest {
// verify summary API
final NetworkStats stats = mSession.getSummaryForAllUid(
template, Long.MIN_VALUE, Long.MAX_VALUE, false);
- assertValues(stats, IFACE_ALL, uid, set, TAG_NONE, metered, roaming, rxBytes, rxPackets,
- txBytes, txPackets, operations);
+ assertValues(stats, IFACE_ALL, uid, set, TAG_NONE, metered, roaming, defaultNetwork,
+ rxBytes, rxPackets, txBytes, txPackets, operations);
}
private void expectSystemReady() throws Exception {
@@ -1096,8 +1106,8 @@ public class NetworkStatsServiceTest {
}
private static void assertValues(NetworkStats stats, String iface, int uid, int set,
- int tag, int metered, int roaming, long rxBytes, long rxPackets, long txBytes,
- long txPackets, int operations) {
+ int tag, int metered, int roaming, int defaultNetwork, long rxBytes, long rxPackets,
+ long txBytes, long txPackets, int operations) {
final NetworkStats.Entry entry = new NetworkStats.Entry();
final int[] sets;
if (set == SET_ALL) {
@@ -1120,12 +1130,22 @@ public class NetworkStatsServiceTest {
meterings = new int[] { metered };
}
+ final int[] defaultNetworks;
+ if (defaultNetwork == DEFAULT_NETWORK_ALL) {
+ defaultNetworks = new int[] { DEFAULT_NETWORK_ALL, DEFAULT_NETWORK_YES,
+ DEFAULT_NETWORK_NO };
+ } else {
+ defaultNetworks = new int[] { defaultNetwork };
+ }
+
for (int s : sets) {
for (int r : roamings) {
for (int m : meterings) {
- final int i = stats.findIndex(iface, uid, s, tag, m, r);
- if (i != -1) {
- entry.add(stats.getValues(i, null));
+ for (int d : defaultNetworks) {
+ final int i = stats.findIndex(iface, uid, s, tag, m, r, d);
+ if (i != -1) {
+ entry.add(stats.getValues(i, null));
+ }
}
}
}
@@ -1160,7 +1180,7 @@ public class NetworkStatsServiceTest {
final NetworkCapabilities capabilities = new NetworkCapabilities();
capabilities.setCapability(NetworkCapabilities.NET_CAPABILITY_NOT_METERED, !isMetered);
capabilities.setCapability(NetworkCapabilities.NET_CAPABILITY_NOT_ROAMING, true);
- return new NetworkState(info, prop, capabilities, null, null, TEST_SSID);
+ return new NetworkState(info, prop, capabilities, WIFI_NETWORK, null, TEST_SSID);
}
private static NetworkState buildMobile3gState(String subscriberId) {
@@ -1177,7 +1197,7 @@ public class NetworkStatsServiceTest {
final NetworkCapabilities capabilities = new NetworkCapabilities();
capabilities.setCapability(NetworkCapabilities.NET_CAPABILITY_NOT_METERED, false);
capabilities.setCapability(NetworkCapabilities.NET_CAPABILITY_NOT_ROAMING, !isRoaming);
- return new NetworkState(info, prop, capabilities, null, subscriberId, null);
+ return new NetworkState(info, prop, capabilities, MOBILE_NETWORK, subscriberId, null);
}
private static NetworkState buildMobile4gState(String iface) {
@@ -1188,7 +1208,7 @@ public class NetworkStatsServiceTest {
final NetworkCapabilities capabilities = new NetworkCapabilities();
capabilities.setCapability(NetworkCapabilities.NET_CAPABILITY_NOT_METERED, false);
capabilities.setCapability(NetworkCapabilities.NET_CAPABILITY_NOT_ROAMING, true);
- return new NetworkState(info, prop, capabilities, null, null, null);
+ return new NetworkState(info, prop, capabilities, MOBILE_NETWORK, null, null);
}
private NetworkStats buildEmptyStats() {
diff --git a/tests/permission/src/com/android/framework/permission/tests/ServiceManagerPermissionTests.java b/tests/permission/src/com/android/framework/permission/tests/ServiceManagerPermissionTests.java
index 4098b989a16b..0504c79c55bd 100644
--- a/tests/permission/src/com/android/framework/permission/tests/ServiceManagerPermissionTests.java
+++ b/tests/permission/src/com/android/framework/permission/tests/ServiceManagerPermissionTests.java
@@ -62,6 +62,11 @@ public class ServiceManagerPermissionTests extends TestCase {
public boolean isRuntimePermission(String permission) {
return false;
}
+
+ @Override
+ public int getPackageUid(String packageName, int flags) {
+ return -1;
+ }
};
ServiceManagerNative.asInterface(BinderInternal.getContextObject())
.setPermissionController(pc);
diff --git a/tools/aapt2/ResourceTable.cpp b/tools/aapt2/ResourceTable.cpp
index 9905f827d663..95bf9210ba97 100644
--- a/tools/aapt2/ResourceTable.cpp
+++ b/tools/aapt2/ResourceTable.cpp
@@ -47,6 +47,13 @@ static bool less_than_struct_with_name(const std::unique_ptr<T>& lhs, const Stri
return lhs->name.compare(0, lhs->name.size(), rhs.data(), rhs.size()) < 0;
}
+template <typename T>
+static bool less_than_struct_with_name_and_id(const std::unique_ptr<T>& lhs,
+ const std::pair<StringPiece, Maybe<uint8_t>>& rhs) {
+ int name_cmp = lhs->name.compare(0, lhs->name.size(), rhs.first.data(), rhs.first.size());
+ return name_cmp < 0 || (name_cmp == 0 && lhs->id < rhs.second);
+}
+
ResourceTablePackage* ResourceTable::FindPackage(const StringPiece& name) const {
const auto last = packages.end();
auto iter = std::lower_bound(packages.begin(), last, name,
@@ -79,6 +86,22 @@ ResourceTablePackage* ResourceTable::CreatePackage(const StringPiece& name, Mayb
return package;
}
+ResourceTablePackage* ResourceTable::CreatePackageAllowingDuplicateNames(const StringPiece& name,
+ const Maybe<uint8_t> id) {
+ const auto last = packages.end();
+ auto iter = std::lower_bound(packages.begin(), last, std::make_pair(name, id),
+ less_than_struct_with_name_and_id<ResourceTablePackage>);
+
+ if (iter != last && name == (*iter)->name && id == (*iter)->id) {
+ return iter->get();
+ }
+
+ std::unique_ptr<ResourceTablePackage> new_package = util::make_unique<ResourceTablePackage>();
+ new_package->name = name.to_string();
+ new_package->id = id;
+ return packages.emplace(iter, std::move(new_package))->get();
+}
+
ResourceTablePackage* ResourceTable::FindOrCreatePackage(const StringPiece& name) {
const auto last = packages.end();
auto iter = std::lower_bound(packages.begin(), last, name,
diff --git a/tools/aapt2/ResourceTable.h b/tools/aapt2/ResourceTable.h
index 95e30c442042..374fe1ea66a1 100644
--- a/tools/aapt2/ResourceTable.h
+++ b/tools/aapt2/ResourceTable.h
@@ -229,6 +229,11 @@ class ResourceTable {
ResourceTablePackage* CreatePackage(const android::StringPiece& name, Maybe<uint8_t> id = {});
+ // Attempts to find a package having the specified name and ID. If not found, a new package
+ // of the specified parameters is created and returned.
+ ResourceTablePackage* CreatePackageAllowingDuplicateNames(const android::StringPiece& name,
+ const Maybe<uint8_t> id);
+
std::unique_ptr<ResourceTable> Clone() const;
// The string pool used by this resource table. Values that reference strings must use
@@ -239,7 +244,8 @@ class ResourceTable {
// destroyed.
StringPool string_pool;
- // The list of packages in this table, sorted alphabetically by package name.
+ // The list of packages in this table, sorted alphabetically by package name and increasing
+ // package ID (missing ID being the lowest).
std::vector<std::unique_ptr<ResourceTablePackage>> packages;
// Set of dynamic packages that this table may reference. Their package names get encoded
diff --git a/tools/aapt2/Resources.proto b/tools/aapt2/Resources.proto
index 8552195d338d..069360e3d6f3 100644
--- a/tools/aapt2/Resources.proto
+++ b/tools/aapt2/Resources.proto
@@ -306,10 +306,25 @@ message FileReference {
}
// A value that represents a primitive data type (float, int, boolean, etc.).
-// Corresponds to the fields (type/data) of the C struct android::Res_value.
message Primitive {
- uint32 type = 1;
- uint32 data = 2;
+ message NullType {
+ }
+ message EmptyType {
+ }
+ oneof oneof_value {
+ NullType null_value = 1;
+ EmptyType empty_value = 2;
+ float float_value = 3;
+ float dimension_value = 4;
+ float fraction_value = 5;
+ int32 int_decimal_value = 6;
+ uint32 int_hexidecimal_value = 7;
+ bool boolean_value = 8;
+ uint32 color_argb8_value = 9;
+ uint32 color_rgb8_value = 10;
+ uint32 color_argb4_value = 11;
+ uint32 color_rgb4_value = 12;
+ }
}
// A value that represents an XML attribute and what values it accepts.
diff --git a/tools/aapt2/format/proto/ProtoDeserialize.cpp b/tools/aapt2/format/proto/ProtoDeserialize.cpp
index d8635a989bed..81bc2c88939e 100644
--- a/tools/aapt2/format/proto/ProtoDeserialize.cpp
+++ b/tools/aapt2/format/proto/ProtoDeserialize.cpp
@@ -23,6 +23,7 @@
#include "Locale.h"
#include "ResourceTable.h"
#include "ResourceUtils.h"
+#include "ResourceValues.h"
#include "ValueVisitor.h"
using ::android::ResStringPool;
@@ -380,7 +381,8 @@ static bool DeserializePackageFromPb(const pb::Package& pb_package, const ResStr
std::map<ResourceId, ResourceNameRef> id_index;
- ResourceTablePackage* pkg = out_table->CreatePackage(pb_package.package_name(), id);
+ ResourceTablePackage* pkg =
+ out_table->CreatePackageAllowingDuplicateNames(pb_package.package_name(), id);
for (const pb::Type& pb_type : pb_package.type()) {
const ResourceType* res_type = ParseResourceType(pb_type.name());
if (res_type == nullptr) {
@@ -761,8 +763,66 @@ std::unique_ptr<Item> DeserializeItemFromPb(const pb::Item& pb_item,
case pb::Item::kPrim: {
const pb::Primitive& pb_prim = pb_item.prim();
- return util::make_unique<BinaryPrimitive>(static_cast<uint8_t>(pb_prim.type()),
- pb_prim.data());
+ android::Res_value val = {};
+ switch (pb_prim.oneof_value_case()) {
+ case pb::Primitive::kNullValue: {
+ val.dataType = android::Res_value::TYPE_NULL;
+ val.data = android::Res_value::DATA_NULL_UNDEFINED;
+ } break;
+ case pb::Primitive::kEmptyValue: {
+ val.dataType = android::Res_value::TYPE_NULL;
+ val.data = android::Res_value::DATA_NULL_EMPTY;
+ } break;
+ case pb::Primitive::kFloatValue: {
+ val.dataType = android::Res_value::TYPE_FLOAT;
+ float float_val = pb_prim.float_value();
+ val.data = *(uint32_t*)&float_val;
+ } break;
+ case pb::Primitive::kDimensionValue: {
+ val.dataType = android::Res_value::TYPE_DIMENSION;
+ float dimen_val = pb_prim.dimension_value();
+ val.data = *(uint32_t*)&dimen_val;
+ } break;
+ case pb::Primitive::kFractionValue: {
+ val.dataType = android::Res_value::TYPE_FRACTION;
+ float fraction_val = pb_prim.fraction_value();
+ val.data = *(uint32_t*)&fraction_val;
+ } break;
+ case pb::Primitive::kIntDecimalValue: {
+ val.dataType = android::Res_value::TYPE_INT_DEC;
+ val.data = static_cast<uint32_t>(pb_prim.int_decimal_value());
+ } break;
+ case pb::Primitive::kIntHexidecimalValue: {
+ val.dataType = android::Res_value::TYPE_INT_HEX;
+ val.data = pb_prim.int_hexidecimal_value();
+ } break;
+ case pb::Primitive::kBooleanValue: {
+ val.dataType = android::Res_value::TYPE_INT_BOOLEAN;
+ val.data = pb_prim.boolean_value() ? 0xFFFFFFFF : 0x0;
+ } break;
+ case pb::Primitive::kColorArgb8Value: {
+ val.dataType = android::Res_value::TYPE_INT_COLOR_ARGB8;
+ val.data = pb_prim.color_argb8_value();
+ } break;
+ case pb::Primitive::kColorRgb8Value: {
+ val.dataType = android::Res_value::TYPE_INT_COLOR_RGB8;
+ val.data = pb_prim.color_rgb8_value();
+ } break;
+ case pb::Primitive::kColorArgb4Value: {
+ val.dataType = android::Res_value::TYPE_INT_COLOR_ARGB4;
+ val.data = pb_prim.color_argb4_value();
+ } break;
+ case pb::Primitive::kColorRgb4Value: {
+ val.dataType = android::Res_value::TYPE_INT_COLOR_RGB4;
+ val.data = pb_prim.color_rgb4_value();
+ } break;
+ default: {
+ LOG(FATAL) << "Unexpected Primitive type: "
+ << static_cast<uint32_t>(pb_prim.oneof_value_case());
+ return {};
+ } break;
+ }
+ return util::make_unique<BinaryPrimitive>(val);
} break;
case pb::Item::kId: {
diff --git a/tools/aapt2/format/proto/ProtoSerialize.cpp b/tools/aapt2/format/proto/ProtoSerialize.cpp
index 78f12814389d..e9622f54f6ae 100644
--- a/tools/aapt2/format/proto/ProtoSerialize.cpp
+++ b/tools/aapt2/format/proto/ProtoSerialize.cpp
@@ -436,8 +436,51 @@ class ValueSerializer : public ConstValueVisitor {
prim->Flatten(&val);
pb::Primitive* pb_prim = out_value_->mutable_item()->mutable_prim();
- pb_prim->set_type(val.dataType);
- pb_prim->set_data(val.data);
+
+ switch (val.dataType) {
+ case android::Res_value::TYPE_NULL: {
+ if (val.data == android::Res_value::DATA_NULL_UNDEFINED) {
+ pb_prim->set_allocated_null_value(new pb::Primitive_NullType());
+ } else if (val.data == android::Res_value::DATA_NULL_EMPTY) {
+ pb_prim->set_allocated_empty_value(new pb::Primitive_EmptyType());
+ } else {
+ LOG(FATAL) << "Unexpected data value for TYPE_NULL BinaryPrimitive: " << val.data;
+ }
+ } break;
+ case android::Res_value::TYPE_FLOAT: {
+ pb_prim->set_float_value(*(float*)&val.data);
+ } break;
+ case android::Res_value::TYPE_DIMENSION: {
+ pb_prim->set_dimension_value(*(float*)&val.data);
+ } break;
+ case android::Res_value::TYPE_FRACTION: {
+ pb_prim->set_fraction_value(*(float*)&val.data);
+ } break;
+ case android::Res_value::TYPE_INT_DEC: {
+ pb_prim->set_int_decimal_value(static_cast<int32_t>(val.data));
+ } break;
+ case android::Res_value::TYPE_INT_HEX: {
+ pb_prim->set_int_hexidecimal_value(val.data);
+ } break;
+ case android::Res_value::TYPE_INT_BOOLEAN: {
+ pb_prim->set_boolean_value(static_cast<bool>(val.data));
+ } break;
+ case android::Res_value::TYPE_INT_COLOR_ARGB8: {
+ pb_prim->set_color_argb8_value(val.data);
+ } break;
+ case android::Res_value::TYPE_INT_COLOR_RGB8: {
+ pb_prim->set_color_rgb8_value(val.data);
+ } break;
+ case android::Res_value::TYPE_INT_COLOR_ARGB4: {
+ pb_prim->set_color_argb4_value(val.data);
+ } break;
+ case android::Res_value::TYPE_INT_COLOR_RGB4: {
+ pb_prim->set_color_rgb4_value(val.data);
+ } break;
+ default:
+ LOG(FATAL) << "Unexpected BinaryPrimitive type: " << val.dataType;
+ break;
+ }
}
void Visit(const Attribute* attr) override {
diff --git a/tools/aapt2/format/proto/ProtoSerialize_test.cpp b/tools/aapt2/format/proto/ProtoSerialize_test.cpp
index ccba5c652822..9081ab6abd0a 100644
--- a/tools/aapt2/format/proto/ProtoSerialize_test.cpp
+++ b/tools/aapt2/format/proto/ProtoSerialize_test.cpp
@@ -254,6 +254,111 @@ TEST(ProtoSerializeTest, SerializeAndDeserializeXml) {
EXPECT_THAT(child_text->text, StrEq("woah there"));
}
+TEST(ProtoSerializeTest, SerializeAndDeserializePrimitives) {
+ std::unique_ptr<ResourceTable> table =
+ test::ResourceTableBuilder()
+ .AddValue("android:bool/boolean_true",
+ test::BuildPrimitive(android::Res_value::TYPE_INT_BOOLEAN, true))
+ .AddValue("android:bool/boolean_false",
+ test::BuildPrimitive(android::Res_value::TYPE_INT_BOOLEAN, false))
+ .AddValue("android:color/color_rgb8", ResourceUtils::TryParseColor("#AABBCC"))
+ .AddValue("android:color/color_argb8", ResourceUtils::TryParseColor("#11223344"))
+ .AddValue("android:color/color_rgb4", ResourceUtils::TryParseColor("#DEF"))
+ .AddValue("android:color/color_argb4", ResourceUtils::TryParseColor("#5678"))
+ .AddValue("android:integer/integer_444", ResourceUtils::TryParseInt("444"))
+ .AddValue("android:integer/integer_neg_333", ResourceUtils::TryParseInt("-333"))
+ .AddValue("android:integer/hex_int_abcd", ResourceUtils::TryParseInt("0xABCD"))
+ .AddValue("android:dimen/dimen_1.39mm", ResourceUtils::TryParseFloat("1.39mm"))
+ .AddValue("android:fraction/fraction_27", ResourceUtils::TryParseFloat("27%"))
+ .AddValue("android:integer/null", ResourceUtils::MakeEmpty())
+ .Build();
+
+ pb::ResourceTable pb_table;
+ SerializeTableToPb(*table, &pb_table);
+
+ test::TestFile file_a("res/layout/main.xml");
+ MockFileCollection files;
+ EXPECT_CALL(files, FindFile(Eq("res/layout/main.xml")))
+ .WillRepeatedly(::testing::Return(&file_a));
+
+ ResourceTable new_table;
+ std::string error;
+ ASSERT_TRUE(DeserializeTableFromPb(pb_table, &files, &new_table, &error));
+ EXPECT_THAT(error, IsEmpty());
+
+ BinaryPrimitive* bp = test::GetValueForConfigAndProduct<BinaryPrimitive>(
+ &new_table, "android:bool/boolean_true", ConfigDescription::DefaultConfig(), "");
+ ASSERT_THAT(bp, NotNull());
+ EXPECT_THAT(bp->value.dataType, Eq(android::Res_value::TYPE_INT_BOOLEAN));
+ EXPECT_THAT(bp->value.data, Eq(ResourceUtils::TryParseBool("true")->value.data));
+
+ bp = test::GetValueForConfigAndProduct<BinaryPrimitive>(&new_table, "android:bool/boolean_false",
+ ConfigDescription::DefaultConfig(), "");
+ ASSERT_THAT(bp, NotNull());
+ EXPECT_THAT(bp->value.dataType, Eq(android::Res_value::TYPE_INT_BOOLEAN));
+ EXPECT_THAT(bp->value.data, Eq(ResourceUtils::TryParseBool("false")->value.data));
+
+ bp = test::GetValueForConfigAndProduct<BinaryPrimitive>(&new_table, "android:color/color_rgb8",
+ ConfigDescription::DefaultConfig(), "");
+ ASSERT_THAT(bp, NotNull());
+ EXPECT_THAT(bp->value.dataType, Eq(android::Res_value::TYPE_INT_COLOR_RGB8));
+ EXPECT_THAT(bp->value.data, Eq(ResourceUtils::TryParseColor("#AABBCC")->value.data));
+
+ bp = test::GetValueForConfigAndProduct<BinaryPrimitive>(&new_table, "android:color/color_argb8",
+ ConfigDescription::DefaultConfig(), "");
+ ASSERT_THAT(bp, NotNull());
+ EXPECT_THAT(bp->value.dataType, Eq(android::Res_value::TYPE_INT_COLOR_ARGB8));
+ EXPECT_THAT(bp->value.data, Eq(ResourceUtils::TryParseColor("#11223344")->value.data));
+
+ bp = test::GetValueForConfigAndProduct<BinaryPrimitive>(&new_table, "android:color/color_rgb4",
+ ConfigDescription::DefaultConfig(), "");
+ ASSERT_THAT(bp, NotNull());
+ EXPECT_THAT(bp->value.dataType, Eq(android::Res_value::TYPE_INT_COLOR_RGB4));
+ EXPECT_THAT(bp->value.data, Eq(ResourceUtils::TryParseColor("#DEF")->value.data));
+
+ bp = test::GetValueForConfigAndProduct<BinaryPrimitive>(&new_table, "android:color/color_argb4",
+ ConfigDescription::DefaultConfig(), "");
+ ASSERT_THAT(bp, NotNull());
+ EXPECT_THAT(bp->value.dataType, Eq(android::Res_value::TYPE_INT_COLOR_ARGB4));
+ EXPECT_THAT(bp->value.data, Eq(ResourceUtils::TryParseColor("#5678")->value.data));
+
+ bp = test::GetValueForConfigAndProduct<BinaryPrimitive>(&new_table, "android:integer/integer_444",
+ ConfigDescription::DefaultConfig(), "");
+ ASSERT_THAT(bp, NotNull());
+ EXPECT_THAT(bp->value.dataType, Eq(android::Res_value::TYPE_INT_DEC));
+ EXPECT_THAT(bp->value.data, Eq(ResourceUtils::TryParseInt("444")->value.data));
+
+ bp = test::GetValueForConfigAndProduct<BinaryPrimitive>(
+ &new_table, "android:integer/integer_neg_333", ConfigDescription::DefaultConfig(), "");
+ ASSERT_THAT(bp, NotNull());
+ EXPECT_THAT(bp->value.dataType, Eq(android::Res_value::TYPE_INT_DEC));
+ EXPECT_THAT(bp->value.data, Eq(ResourceUtils::TryParseInt("-333")->value.data));
+
+ bp = test::GetValueForConfigAndProduct<BinaryPrimitive>(
+ &new_table, "android:integer/hex_int_abcd", ConfigDescription::DefaultConfig(), "");
+ ASSERT_THAT(bp, NotNull());
+ EXPECT_THAT(bp->value.dataType, Eq(android::Res_value::TYPE_INT_HEX));
+ EXPECT_THAT(bp->value.data, Eq(ResourceUtils::TryParseInt("0xABCD")->value.data));
+
+ bp = test::GetValueForConfigAndProduct<BinaryPrimitive>(&new_table, "android:dimen/dimen_1.39mm",
+ ConfigDescription::DefaultConfig(), "");
+ ASSERT_THAT(bp, NotNull());
+ EXPECT_THAT(bp->value.dataType, Eq(android::Res_value::TYPE_DIMENSION));
+ EXPECT_THAT(bp->value.data, Eq(ResourceUtils::TryParseFloat("1.39mm")->value.data));
+
+ bp = test::GetValueForConfigAndProduct<BinaryPrimitive>(
+ &new_table, "android:fraction/fraction_27", ConfigDescription::DefaultConfig(), "");
+ ASSERT_THAT(bp, NotNull());
+ EXPECT_THAT(bp->value.dataType, Eq(android::Res_value::TYPE_FRACTION));
+ EXPECT_THAT(bp->value.data, Eq(ResourceUtils::TryParseFloat("27%")->value.data));
+
+ bp = test::GetValueForConfigAndProduct<BinaryPrimitive>(&new_table, "android:integer/null",
+ ConfigDescription::DefaultConfig(), "");
+ ASSERT_THAT(bp, NotNull());
+ EXPECT_THAT(bp->value.dataType, Eq(android::Res_value::TYPE_NULL));
+ EXPECT_THAT(bp->value.data, Eq(ResourceUtils::MakeEmpty()->value.data));
+}
+
static void ExpectConfigSerializes(const StringPiece& config_str) {
const ConfigDescription expected_config = test::ParseConfigOrDie(config_str);
pb::Configuration pb_config;
diff --git a/tools/aapt2/link/ManifestFixer.cpp b/tools/aapt2/link/ManifestFixer.cpp
index ccc3470fd7f4..713db5b7ed86 100644
--- a/tools/aapt2/link/ManifestFixer.cpp
+++ b/tools/aapt2/link/ManifestFixer.cpp
@@ -319,6 +319,7 @@ bool ManifestFixer::BuildRules(xml::XmlActionExecutor* executor,
manifest_action["original-package"];
manifest_action["overlay"];
manifest_action["protected-broadcast"];
+ manifest_action["adopt-permissions"];
manifest_action["uses-permission"];
manifest_action["uses-permission-sdk-23"];
manifest_action["permission"];
diff --git a/tools/fonts/fontchain_linter.py b/tools/fonts/fontchain_linter.py
index 15d39fdfd6ea..ec40a2229c33 100755
--- a/tools/fonts/fontchain_linter.py
+++ b/tools/fonts/fontchain_linter.py
@@ -270,6 +270,9 @@ def parse_fonts_xml(fonts_xml_path):
if index:
index = int(index)
+ if not path.exists(path.join(_fonts_dir, font_file)):
+ continue # Missing font is a valid case. Just ignore the missing font files.
+
record = FontRecord(
name,
frozenset(scripts),
diff --git a/wifi/java/android/net/wifi/WifiConfiguration.java b/wifi/java/android/net/wifi/WifiConfiguration.java
index 6438631cb8ed..2c6011823828 100644
--- a/wifi/java/android/net/wifi/WifiConfiguration.java
+++ b/wifi/java/android/net/wifi/WifiConfiguration.java
@@ -267,8 +267,15 @@ public class WifiConfiguration implements Parcelable {
public static final int AP_BAND_5GHZ = 1;
/**
+ * Device is allowed to choose the optimal band (2Ghz or 5Ghz) based on device capability,
+ * operating country code and current radio conditions.
+ * @hide
+ */
+ public static final int AP_BAND_ANY = -1;
+
+ /**
* The band which AP resides on
- * 0-2G 1-5G
+ * -1:Any 0:2G 1:5G
* By default, 2G is chosen
* @hide
*/