summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Android.bp16
-rw-r--r--apex/appsearch/Android.bp37
-rw-r--r--apex/appsearch/apex_manifest.json4
-rw-r--r--apex/appsearch/com.android.appsearch.avbpubkeybin1032 -> 0 bytes
-rw-r--r--apex/appsearch/com.android.appsearch.pem51
-rw-r--r--apex/appsearch/com.android.appsearch.pk8bin2373 -> 0 bytes
-rw-r--r--apex/appsearch/com.android.appsearch.x509.pem35
-rw-r--r--apex/appsearch/framework/Android.bp83
-rw-r--r--apex/appsearch/framework/java/android/app/TEST_MAPPING7
-rw-r--r--apex/appsearch/framework/java/android/app/appsearch/AppSearchBatchResult.java150
-rw-r--r--apex/appsearch/framework/java/android/app/appsearch/AppSearchDocument.java724
-rw-r--r--apex/appsearch/framework/java/android/app/appsearch/AppSearchEmail.java255
-rw-r--r--apex/appsearch/framework/java/android/app/appsearch/AppSearchManager.java293
-rw-r--r--apex/appsearch/framework/java/android/app/appsearch/AppSearchManagerFrameworkInitializer.java43
-rw-r--r--apex/appsearch/framework/java/android/app/appsearch/AppSearchSchema.java369
-rw-r--r--apex/appsearch/framework/java/android/app/appsearch/IAppSearchManager.aidl60
-rw-r--r--apex/appsearch/framework/java/android/app/appsearch/IllegalSchemaException.java36
-rw-r--r--apex/appsearch/framework/java/android/app/appsearch/MatchInfo.java182
-rw-r--r--apex/appsearch/framework/java/android/app/appsearch/SearchResults.java128
-rw-r--r--apex/appsearch/framework/java/android/app/appsearch/SearchSpec.java260
-rw-r--r--apex/appsearch/service/Android.bp24
-rw-r--r--apex/appsearch/service/java/com/android/server/appsearch/AppSearchManagerService.java125
-rw-r--r--apex/appsearch/service/java/com/android/server/appsearch/TEST_MAPPING23
-rw-r--r--apex/appsearch/service/java/com/android/server/appsearch/impl/AppSearchImpl.java168
-rw-r--r--apex/appsearch/service/java/com/android/server/appsearch/impl/FakeIcing.java169
-rw-r--r--apex/appsearch/service/java/com/android/server/appsearch/impl/ImplInstanceManager.java56
-rw-r--r--apex/blobstore/framework/java/android/app/blob/AccessorInfo.java119
-rw-r--r--apex/blobstore/framework/java/android/app/blob/BlobInfo.aidl19
-rw-r--r--apex/blobstore/framework/java/android/app/blob/BlobInfo.java109
-rw-r--r--apex/blobstore/framework/java/android/app/blob/BlobStoreManager.java49
-rw-r--r--apex/blobstore/framework/java/android/app/blob/IBlobStoreManager.aidl6
-rw-r--r--apex/blobstore/framework/java/android/app/blob/XmlTags.java2
-rw-r--r--apex/blobstore/service/java/com/android/server/blob/BlobMetadata.java108
-rw-r--r--apex/blobstore/service/java/com/android/server/blob/BlobStoreConfig.java101
-rw-r--r--apex/blobstore/service/java/com/android/server/blob/BlobStoreManagerService.java243
-rw-r--r--apex/blobstore/service/java/com/android/server/blob/BlobStoreManagerShellCommand.java9
-rw-r--r--apex/blobstore/service/java/com/android/server/blob/BlobStoreSession.java16
-rw-r--r--apex/blobstore/service/java/com/android/server/blob/BlobStoreUtils.java50
-rw-r--r--apex/jobscheduler/service/java/com/android/server/job/TEST_MAPPING7
-rw-r--r--apex/media/framework/java/android/media/MediaParser.java51
-rw-r--r--apex/permission/service/java/com/android/permission/persistence/RuntimePermissionsPersistenceImpl.java6
-rw-r--r--apex/permission/service/java/com/android/role/persistence/RolesPersistenceImpl.java6
-rw-r--r--apex/statsd/aidl/android/os/IStatsManagerService.aidl2
-rw-r--r--apex/statsd/aidl/android/os/IStatsd.aidl5
-rw-r--r--apex/statsd/framework/Android.bp26
-rw-r--r--apex/statsd/framework/java/android/app/StatsManager.java82
-rw-r--r--apex/statsd/framework/test/AndroidManifest.xml26
-rw-r--r--apex/statsd/framework/test/TEST_MAPPING7
-rw-r--r--apex/statsd/framework/test/src/android/app/PullAtomMetadataTest.java (renamed from core/tests/coretests/src/android/app/PullAtomMetadataTest.java)40
-rw-r--r--apex/statsd/framework/test/src/android/util/StatsEventTest.java (renamed from core/tests/coretests/src/android/util/StatsEventTest.java)0
-rw-r--r--apex/statsd/service/java/com/android/server/stats/StatsCompanionService.java319
-rw-r--r--apex/statsd/service/java/com/android/server/stats/StatsManagerService.java31
-rw-r--r--apex/statsd/tests/libstatspull/jni/stats_pull_helper.cpp13
-rw-r--r--apex/statsd/tests/libstatspull/src/com/android/internal/os/statsd/libstats/LibStatsPullTests.java2
-rw-r--r--api/current.txt123
-rw-r--r--api/module-lib-current.txt5
-rwxr-xr-xapi/system-current.txt132
-rw-r--r--api/system-removed.txt6
-rw-r--r--api/test-current.txt42
-rw-r--r--cmds/incident/main.cpp38
-rw-r--r--cmds/incidentd/src/Reporter.cpp60
-rw-r--r--cmds/incidentd/src/Reporter.h7
-rw-r--r--cmds/incidentd/src/WorkDirectory.cpp36
-rw-r--r--cmds/incidentd/src/incidentd_util.cpp107
-rw-r--r--cmds/incidentd/src/incidentd_util.h23
-rw-r--r--cmds/incidentd/src/report_file.proto5
-rw-r--r--cmds/statsd/Android.bp10
-rw-r--r--cmds/statsd/src/HashableDimensionKey.cpp81
-rw-r--r--cmds/statsd/src/StatsService.cpp13
-rw-r--r--cmds/statsd/src/StatsService.h5
-rw-r--r--cmds/statsd/src/anomaly/AlarmMonitor.cpp2
-rw-r--r--cmds/statsd/src/atom_field_options.proto2
-rw-r--r--cmds/statsd/src/atoms.proto10
-rw-r--r--cmds/statsd/src/config/ConfigManager.cpp55
-rw-r--r--cmds/statsd/src/config/ConfigManager.h13
-rw-r--r--cmds/statsd/src/external/StatsPullerManager.cpp11
-rw-r--r--cmds/statsd/src/subscriber/SubscriberReporter.cpp46
-rw-r--r--cmds/statsd/src/subscriber/SubscriberReporter.h10
-rw-r--r--core/java/android/accessibilityservice/AccessibilityService.java9
-rw-r--r--core/java/android/app/Activity.java3
-rw-r--r--core/java/android/app/AppOpsManager.java226
-rw-r--r--core/java/android/app/ApplicationExitInfo.java174
-rw-r--r--core/java/android/app/AsyncNotedAppOp.java51
-rw-r--r--core/java/android/app/NotificationHistory.java5
-rw-r--r--core/java/android/app/SyncNotedAppOp.java4
-rw-r--r--core/java/android/app/SystemServiceRegistry.java5
-rw-r--r--core/java/android/app/WindowContext.java1
-rw-r--r--core/java/android/app/admin/DevicePolicyManager.java71
-rw-r--r--core/java/android/bluetooth/BluetoothA2dp.java34
-rw-r--r--core/java/android/bluetooth/BluetoothAdapter.java7
-rw-r--r--core/java/android/content/ApexEnvironment.java (renamed from core/java/android/content/ApexContext.java)20
-rw-r--r--core/java/android/content/ContentResolver.java44
-rw-r--r--core/java/android/content/Context.java12
-rw-r--r--core/java/android/content/Intent.java14
-rw-r--r--core/java/android/content/om/OverlayManager.java40
-rw-r--r--core/java/android/content/pm/ActivityInfo.java47
-rw-r--r--core/java/android/content/pm/ApplicationInfo.java4
-rw-r--r--core/java/android/content/pm/IPackageManager.aidl1
-rw-r--r--core/java/android/content/pm/InstallationFile.java36
-rw-r--r--core/java/android/content/pm/PackageManager.java28
-rw-r--r--core/java/android/content/pm/PackageParser.java8
-rw-r--r--core/java/android/content/pm/parsing/PackageInfoWithoutStateUtils.java1
-rw-r--r--core/java/android/content/pm/parsing/component/ParsedActivity.java9
-rw-r--r--core/java/android/content/pm/parsing/component/ParsedActivityUtils.java4
-rw-r--r--core/java/android/database/ContentObserver.java163
-rw-r--r--core/java/android/database/CursorToBulkCursorAdaptor.java18
-rw-r--r--core/java/android/database/IContentObserver.aidl10
-rw-r--r--core/java/android/hardware/fingerprint/FingerprintManager.java7
-rw-r--r--core/java/android/inputmethodservice/InputMethodService.java4
-rw-r--r--core/java/android/net/ConnectivityManager.java60
-rw-r--r--core/java/android/net/EthernetManager.java15
-rw-r--r--core/java/android/net/NetworkAgent.java15
-rw-r--r--core/java/android/net/NetworkScore.java162
-rw-r--r--core/java/android/os/BatteryStatsManager.java14
-rw-r--r--core/java/android/os/Binder.java21
-rw-r--r--core/java/android/os/BinderProxy.java13
-rw-r--r--core/java/android/os/Environment.java45
-rw-r--r--core/java/android/os/IPowerManager.aidl2
-rw-r--r--core/java/android/os/ParcelFileDescriptor.java2
-rw-r--r--core/java/android/os/PowerManagerInternal.java113
-rw-r--r--core/java/android/os/UpdateEngine.java35
-rw-r--r--core/java/android/os/connectivity/WifiBatteryStats.java4
-rw-r--r--core/java/android/os/incremental/IIncrementalManager.aidl36
-rw-r--r--core/java/android/permission/PermissionControllerService.java3
-rw-r--r--core/java/android/provider/DeviceConfig.java8
-rw-r--r--core/java/android/provider/DocumentsContract.java3
-rw-r--r--core/java/android/provider/Settings.java29
-rw-r--r--core/java/android/provider/Telephony.java2
-rw-r--r--core/java/android/service/autofill/FillResponse.java19
-rw-r--r--core/java/android/service/autofill/InlineAction.aidl19
-rw-r--r--core/java/android/service/autofill/InlineAction.java205
-rw-r--r--core/java/android/service/autofill/augmented/AugmentedAutofillService.java4
-rw-r--r--core/java/android/service/autofill/augmented/FillResponse.java41
-rw-r--r--core/java/android/service/autofill/augmented/IFillCallback.aidl4
-rw-r--r--core/java/android/service/contentcapture/DataShareReadAdapter.java3
-rw-r--r--core/java/android/service/controls/Control.java4
-rw-r--r--core/java/android/service/controls/ControlsProviderService.java3
-rw-r--r--core/java/android/service/controls/DeviceTypes.java22
-rw-r--r--core/java/android/service/controls/TokenProvider.aidl7
-rw-r--r--core/java/android/service/controls/actions/ControlAction.java56
-rw-r--r--core/java/android/service/controls/actions/MultiFloatAction.java82
-rw-r--r--core/java/android/service/controls/templates/ControlTemplate.java47
-rw-r--r--core/java/android/service/controls/templates/TemperatureControlTemplate.java37
-rw-r--r--core/java/android/service/controls/templates/ThumbnailTemplate.java98
-rw-r--r--core/java/android/service/dataloader/DataLoaderService.java2
-rw-r--r--core/java/android/service/notification/StatusBarNotification.java18
-rw-r--r--core/java/android/timezone/CountryTimeZones.java2
-rw-r--r--core/java/android/util/FeatureFlagUtils.java2
-rw-r--r--core/java/android/view/IWindowManager.aidl7
-rw-r--r--core/java/android/view/InsetsAnimationControlImpl.java11
-rw-r--r--core/java/android/view/InsetsController.java24
-rw-r--r--core/java/android/view/InsetsSourceConsumer.java33
-rw-r--r--core/java/android/view/InsetsSourceControl.java6
-rw-r--r--core/java/android/view/InsetsState.java20
-rw-r--r--core/java/android/view/RemoteAnimationTarget.java36
-rw-r--r--core/java/android/view/SurfaceView.java2
-rw-r--r--core/java/android/view/SyncRtSurfaceTransactionApplier.java13
-rw-r--r--core/java/android/view/ViewGroup.java2
-rw-r--r--core/java/android/view/ViewRootImpl.java2
-rw-r--r--core/java/android/view/Window.java2
-rw-r--r--core/java/android/view/WindowContainerTransaction.java42
-rw-r--r--core/java/android/view/WindowManager.java4
-rw-r--r--core/java/android/view/WindowManagerImpl.java44
-rw-r--r--core/java/android/view/accessibility/AccessibilityNodeInfo.java102
-rw-r--r--core/java/android/view/contentcapture/ContentCaptureManager.java9
-rw-r--r--core/java/android/view/contentcapture/DataShareWriteAdapter.java3
-rw-r--r--core/java/android/widget/Editor.java53
-rw-r--r--core/java/android/widget/TextView.java17
-rw-r--r--core/java/com/android/internal/accessibility/common/ShortcutConstants.java136
-rw-r--r--core/java/com/android/internal/accessibility/util/AccessibilityUtils.java131
-rw-r--r--core/java/com/android/internal/accessibility/util/ShortcutUtils.java185
-rw-r--r--core/java/com/android/internal/app/AbstractMultiProfilePagerAdapter.java44
-rw-r--r--core/java/com/android/internal/app/AccessibilityButtonChooserActivity.java672
-rw-r--r--core/java/com/android/internal/app/ChooserActivity.java5
-rw-r--r--core/java/com/android/internal/app/ChooserMultiProfilePagerAdapter.java27
-rw-r--r--core/java/com/android/internal/app/IAppOpsService.aidl2
-rw-r--r--core/java/com/android/internal/app/ResolverActivity.java80
-rw-r--r--core/java/com/android/internal/app/ResolverListAdapter.java14
-rw-r--r--core/java/com/android/internal/app/ResolverMultiProfilePagerAdapter.java27
-rw-r--r--core/java/com/android/internal/compat/CompatibilityChangeInfo.java10
-rw-r--r--core/java/com/android/internal/compat/OverrideAllowedState.java37
-rw-r--r--core/java/com/android/internal/content/om/OverlayConfig.java23
-rw-r--r--core/java/com/android/internal/logging/InstanceId.java11
-rw-r--r--core/java/com/android/internal/logging/testing/UiEventLoggerFake.java23
-rw-r--r--core/java/com/android/internal/net/VpnConfig.java2
-rw-r--r--core/java/com/android/internal/util/DataClass.java15
-rw-r--r--core/java/com/android/internal/widget/ResolverDrawerLayout.java41
-rw-r--r--core/java/com/android/server/SystemConfig.java14
-rw-r--r--core/jni/Android.bp11
-rw-r--r--core/jni/AndroidRuntime.cpp2
-rw-r--r--core/jni/android_media_AudioTrack.cpp33
-rw-r--r--core/jni/android_media_AudioTrackCallback.cpp99
-rw-r--r--core/jni/android_media_AudioTrackCallback.h45
-rw-r--r--core/jni/com_android_internal_os_Zygote.cpp21
-rw-r--r--core/jni/fd_utils.cpp1
-rw-r--r--core/proto/android/app/appexit_enums.proto240
-rw-r--r--core/proto/android/app/appexitinfo.proto146
-rw-r--r--core/proto/android/bluetooth/enums.proto1
-rw-r--r--core/proto/android/providers/settings/config.proto1
-rw-r--r--core/proto/android/providers/settings/secure.proto1
-rw-r--r--core/proto/android/server/windowmanagerservice.proto43
-rw-r--r--core/proto/android/view/remote_animation_target.proto2
-rw-r--r--core/res/res/drawable/ic_pan_tool.xml26
-rw-r--r--core/res/res/drawable/ic_visibility.xml (renamed from core/res/res/drawable/ic_delete_item.xml)4
-rw-r--r--core/res/res/layout/accessibility_button_chooser_item.xml44
-rw-r--r--core/res/res/layout/accessibility_enable_service_encryption_warning.xml175
-rw-r--r--core/res/res/layout/chooser_list_per_profile.xml4
-rw-r--r--core/res/res/layout/resolver_list.xml3
-rw-r--r--core/res/res/layout/resolver_list_per_profile.xml4
-rw-r--r--core/res/res/layout/resolver_list_with_default.xml3
-rw-r--r--core/res/res/values-af/strings.xml29
-rw-r--r--core/res/res/values-am/strings.xml42
-rw-r--r--core/res/res/values-ar/strings.xml48
-rw-r--r--core/res/res/values-as/strings.xml39
-rw-r--r--core/res/res/values-az/strings.xml42
-rw-r--r--core/res/res/values-b+sr+Latn/strings.xml42
-rw-r--r--core/res/res/values-be/strings.xml44
-rw-r--r--core/res/res/values-bg/strings.xml42
-rw-r--r--core/res/res/values-bn/strings.xml39
-rw-r--r--core/res/res/values-bs/strings.xml42
-rw-r--r--core/res/res/values-ca/strings.xml42
-rw-r--r--core/res/res/values-cs/strings.xml42
-rw-r--r--core/res/res/values-da/strings.xml42
-rw-r--r--core/res/res/values-de/strings.xml39
-rw-r--r--core/res/res/values-el/strings.xml36
-rw-r--r--core/res/res/values-en-rAU/strings.xml23
-rw-r--r--core/res/res/values-en-rCA/strings.xml23
-rw-r--r--core/res/res/values-en-rGB/strings.xml23
-rw-r--r--core/res/res/values-en-rIN/strings.xml23
-rw-r--r--core/res/res/values-en-rXC/strings.xml23
-rw-r--r--core/res/res/values-es-rUS/strings.xml42
-rw-r--r--core/res/res/values-es/strings.xml42
-rw-r--r--core/res/res/values-et/strings.xml42
-rw-r--r--core/res/res/values-eu/strings.xml44
-rw-r--r--core/res/res/values-fa/strings.xml42
-rw-r--r--core/res/res/values-fi/strings.xml42
-rw-r--r--core/res/res/values-fr-rCA/strings.xml42
-rw-r--r--core/res/res/values-fr/strings.xml42
-rw-r--r--core/res/res/values-gl/strings.xml42
-rw-r--r--core/res/res/values-gu/strings.xml39
-rw-r--r--core/res/res/values-hi/strings.xml52
-rw-r--r--core/res/res/values-hr/strings.xml42
-rw-r--r--core/res/res/values-hu/strings.xml42
-rw-r--r--core/res/res/values-hy/strings.xml42
-rw-r--r--core/res/res/values-in/strings.xml44
-rw-r--r--core/res/res/values-is/strings.xml42
-rw-r--r--core/res/res/values-it/strings.xml42
-rw-r--r--core/res/res/values-iw/strings.xml42
-rw-r--r--core/res/res/values-ja/strings.xml33
-rw-r--r--core/res/res/values-ka/strings.xml42
-rw-r--r--core/res/res/values-kk/strings.xml42
-rw-r--r--core/res/res/values-km/strings.xml42
-rw-r--r--core/res/res/values-kn/strings.xml39
-rw-r--r--core/res/res/values-ko/strings.xml42
-rw-r--r--core/res/res/values-ky/strings.xml42
-rw-r--r--core/res/res/values-lo/strings.xml42
-rw-r--r--core/res/res/values-lt/strings.xml42
-rw-r--r--core/res/res/values-lv/strings.xml42
-rw-r--r--core/res/res/values-ml/strings.xml39
-rw-r--r--core/res/res/values-mn/strings.xml29
-rw-r--r--core/res/res/values-mr/strings.xml51
-rw-r--r--core/res/res/values-ms/strings.xml42
-rw-r--r--core/res/res/values-my/strings.xml42
-rw-r--r--core/res/res/values-nb/strings.xml42
-rw-r--r--core/res/res/values-ne/strings.xml39
-rw-r--r--core/res/res/values-nl/strings.xml42
-rw-r--r--core/res/res/values-or/strings.xml39
-rw-r--r--core/res/res/values-pa/strings.xml51
-rw-r--r--core/res/res/values-pl/strings.xml42
-rw-r--r--core/res/res/values-pt-rBR/strings.xml42
-rw-r--r--core/res/res/values-pt-rPT/strings.xml42
-rw-r--r--core/res/res/values-pt/strings.xml42
-rw-r--r--core/res/res/values-ro/strings.xml42
-rw-r--r--core/res/res/values-ru/strings.xml42
-rw-r--r--core/res/res/values-si/strings.xml42
-rw-r--r--core/res/res/values-sk/strings.xml42
-rw-r--r--core/res/res/values-sl/strings.xml42
-rw-r--r--core/res/res/values-sq/strings.xml42
-rw-r--r--core/res/res/values-sr/strings.xml42
-rw-r--r--core/res/res/values-sv/strings.xml42
-rw-r--r--core/res/res/values-sw/strings.xml42
-rw-r--r--core/res/res/values-sw600dp/config.xml10
-rw-r--r--core/res/res/values-ta/strings.xml61
-rw-r--r--core/res/res/values-te/strings.xml39
-rw-r--r--core/res/res/values-th/strings.xml42
-rw-r--r--core/res/res/values-tl/strings.xml42
-rw-r--r--core/res/res/values-tr/strings.xml42
-rw-r--r--core/res/res/values-uk/strings.xml42
-rw-r--r--core/res/res/values-ur/strings.xml39
-rw-r--r--core/res/res/values-uz/strings.xml42
-rw-r--r--core/res/res/values-vi/strings.xml42
-rw-r--r--core/res/res/values-zh-rCN/strings.xml42
-rw-r--r--core/res/res/values-zh-rHK/strings.xml42
-rw-r--r--core/res/res/values-zh-rTW/strings.xml42
-rw-r--r--core/res/res/values-zu/strings.xml42
-rw-r--r--core/res/res/values/attrs.xml2
-rw-r--r--core/res/res/values/attrs_manifest.xml8
-rw-r--r--core/res/res/values/config.xml16
-rw-r--r--core/res/res/values/dimens.xml4
-rw-r--r--core/res/res/values/public.xml6
-rw-r--r--core/res/res/values/strings.xml106
-rw-r--r--core/res/res/values/symbols.xml39
-rw-r--r--core/res/res/values/themes_material.xml4
-rw-r--r--core/tests/coretests/Android.bp3
-rw-r--r--core/tests/coretests/src/android/app/NotificationHistoryTest.java2
-rw-r--r--core/tests/coretests/src/android/app/appsearch/AppSearchDocumentTest.java262
-rw-r--r--core/tests/coretests/src/android/app/appsearch/AppSearchEmailTest.java53
-rw-r--r--core/tests/coretests/src/android/app/appsearch/AppSearchSchemaTest.java166
-rw-r--r--core/tests/coretests/src/android/app/appsearch/SearchResultsTest.java66
-rw-r--r--core/tests/coretests/src/android/app/appsearch/SnippetTest.java200
-rw-r--r--core/tests/coretests/src/android/app/appsearch/impl/CustomerDocumentTest.java98
-rw-r--r--core/tests/coretests/src/android/content/ApexEnvironmentTest.java (renamed from core/tests/coretests/src/android/content/ApexContextTest.java)11
-rw-r--r--core/tests/coretests/src/android/os/EnvironmentTest.java41
-rw-r--r--core/tests/coretests/src/android/service/controls/actions/ControlActionTest.java10
-rw-r--r--core/tests/coretests/src/android/service/controls/templates/ControlTemplateTest.java10
-rw-r--r--core/tests/coretests/src/android/widget/EditorCursorDragTest.java204
-rw-r--r--core/tests/coretests/src/android/widget/TextViewActivityTest.java10
-rw-r--r--core/tests/coretests/src/com/android/internal/app/ChooserActivityTest.java2
-rw-r--r--core/tests/coretests/src/com/android/internal/app/ResolverActivityTest.java2
-rw-r--r--data/etc/com.android.systemui.xml1
-rw-r--r--data/etc/privapp-permissions-platform.xml1
-rw-r--r--identity/java/android/security/identity/CredstoreResultData.java2
-rw-r--r--identity/java/android/security/identity/CredstoreWritableIdentityCredential.java6
-rw-r--r--identity/java/android/security/identity/IdentityCredential.java5
-rw-r--r--identity/java/android/security/identity/PersonalizationData.java4
-rw-r--r--identity/java/android/security/identity/ResultData.java5
-rw-r--r--keystore/java/android/security/keystore/KeyGenParameterSpec.java11
-rw-r--r--keystore/java/android/security/keystore/KeyProtection.java11
-rw-r--r--libs/WindowManager/Jetpack/Android.bp38
-rw-r--r--libs/WindowManager/Jetpack/androidx.window.extensions.xml21
-rw-r--r--libs/WindowManager/Jetpack/src/androidx/window/extensions/ExtensionHelper.java130
-rw-r--r--libs/WindowManager/Jetpack/src/androidx/window/extensions/ExtensionProvider.java42
-rw-r--r--libs/WindowManager/Jetpack/src/androidx/window/extensions/SettingsExtensionImpl.java217
-rw-r--r--libs/WindowManager/Jetpack/window-extensions-release.aarbin0 -> 6427 bytes
-rw-r--r--libs/hwui/Readback.cpp5
-rw-r--r--libs/hwui/RenderNode.cpp2
-rw-r--r--libs/hwui/RenderNode.h3
-rw-r--r--libs/hwui/jni/FontFamily.cpp4
-rw-r--r--libs/hwui/jni/fonts/Font.cpp4
-rw-r--r--libs/hwui/pipeline/skia/ReorderBarrierDrawables.h2
-rw-r--r--libs/hwui/renderthread/RenderThread.cpp3
-rw-r--r--libs/hwui/renderthread/VulkanManager.cpp2
-rw-r--r--libs/hwui/tests/unit/FatVectorTests.cpp2
-rw-r--r--libs/hwui/utils/FatVector.h96
-rw-r--r--libs/incident/include_priv/android/os/IncidentReportArgs.h3
-rw-r--r--libs/incident/src/IncidentReportArgs.cpp26
-rw-r--r--location/java/android/location/LocationManager.java26
-rw-r--r--location/java/com/android/internal/location/gnssmetrics/GnssMetrics.java2
-rw-r--r--media/java/android/media/AudioMetadata.java492
-rw-r--r--media/java/android/media/AudioTrack.java11
-rw-r--r--media/java/android/media/IMediaRoute2ProviderService.aidl14
-rw-r--r--media/java/android/media/IMediaRoute2ProviderServiceCallback.aidl3
-rw-r--r--media/java/android/media/IMediaRouter2.aidl2
-rw-r--r--media/java/android/media/IMediaRouterService.aidl30
-rw-r--r--media/java/android/media/MediaPlayer.java1
-rw-r--r--media/java/android/media/MediaRoute2Info.java53
-rw-r--r--media/java/android/media/MediaRoute2ProviderService.java51
-rw-r--r--media/java/android/media/MediaRouter2.java75
-rw-r--r--media/java/android/media/MediaRouter2Manager.java24
-rw-r--r--media/java/android/media/RoutingSessionInfo.java10
-rw-r--r--media/java/android/media/session/ISessionManager.aidl2
-rw-r--r--media/java/android/media/session/MediaSessionManager.java38
-rw-r--r--media/java/android/media/tv/TvInputManager.java42
-rw-r--r--media/java/android/media/tv/tuner/Lnb.java2
-rw-r--r--media/java/android/media/tv/tuner/Tuner.java2
-rw-r--r--media/java/android/media/tv/tuner/dvr/DvrPlayback.java13
-rw-r--r--media/java/android/media/tv/tuner/dvr/DvrRecorder.java13
-rw-r--r--media/java/android/media/tv/tuner/filter/AlpFilterConfiguration.java28
-rw-r--r--media/java/android/media/tv/tuner/filter/Filter.java12
-rw-r--r--media/java/android/media/tv/tuner/filter/FilterConfiguration.java24
-rw-r--r--media/java/android/media/tv/tuner/filter/TlvFilterConfiguration.java28
-rw-r--r--media/jni/android_media_MediaCodec.cpp14
-rw-r--r--media/jni/android_media_MediaCodec.h1
-rw-r--r--media/jni/android_media_tv_Tuner.cpp72
-rw-r--r--media/jni/android_media_tv_Tuner.h8
-rw-r--r--media/tests/MediaRouter/src/com/android/mediaroutertest/RoutingSessionInfoTest.java96
-rw-r--r--media/tests/MediaRouter/src/com/android/mediaroutertest/SampleMediaRoute2ProviderService.java5
-rw-r--r--packages/CarSystemUI/res/layout/car_fullscreen_user_switcher.xml8
-rw-r--r--packages/CarSystemUI/res/layout/car_qs_panel.xml2
-rw-r--r--packages/CarSystemUI/res/layout/super_notification_shade.xml5
-rw-r--r--packages/CarSystemUI/res/layout/sysui_overlay_window.xml (renamed from packages/CarSystemUI/res/layout/sysui_primary_window.xml)0
-rw-r--r--packages/CarSystemUI/res/values/config.xml6
-rw-r--r--packages/CarSystemUI/src/com/android/systemui/CarSystemUIBinder.java12
-rw-r--r--packages/CarSystemUI/src/com/android/systemui/CarSystemUIModule.java17
-rw-r--r--packages/CarSystemUI/src/com/android/systemui/car/CarDeviceProvisionedControllerImpl.java3
-rw-r--r--packages/CarSystemUI/src/com/android/systemui/car/notification/CarHeadsUpNotificationSystemContainer.java118
-rw-r--r--packages/CarSystemUI/src/com/android/systemui/car/notification/CarNotificationModule.java84
-rw-r--r--packages/CarSystemUI/src/com/android/systemui/car/userswitcher/CarTrustAgentUnlockDialogHelper.java (renamed from packages/CarSystemUI/src/com/android/systemui/statusbar/car/CarTrustAgentUnlockDialogHelper.java)8
-rw-r--r--packages/CarSystemUI/src/com/android/systemui/car/userswitcher/FullScreenUserSwitcherViewController.java124
-rw-r--r--packages/CarSystemUI/src/com/android/systemui/car/userswitcher/FullscreenUserSwitcherViewMediator.java291
-rw-r--r--packages/CarSystemUI/src/com/android/systemui/car/userswitcher/UserGridRecyclerView.java (renamed from packages/CarSystemUI/src/com/android/systemui/statusbar/car/UserGridRecyclerView.java)17
-rw-r--r--packages/CarSystemUI/src/com/android/systemui/car/userswitcher/UserIconProvider.java (renamed from packages/CarSystemUI/src/com/android/systemui/statusbar/car/UserIconProvider.java)4
-rw-r--r--packages/CarSystemUI/src/com/android/systemui/navigationbar/car/CarNavigationBar.java10
-rw-r--r--packages/CarSystemUI/src/com/android/systemui/navigationbar/car/CarNavigationBarController.java24
-rw-r--r--packages/CarSystemUI/src/com/android/systemui/qs/car/CarQSFragment.java2
-rw-r--r--packages/CarSystemUI/src/com/android/systemui/statusbar/car/CarStatusBar.java194
-rw-r--r--packages/CarSystemUI/src/com/android/systemui/statusbar/car/CarStatusBarKeyguardViewManager.java39
-rw-r--r--packages/CarSystemUI/src/com/android/systemui/statusbar/car/CarStatusBarModule.java24
-rw-r--r--packages/CarSystemUI/src/com/android/systemui/statusbar/car/FullscreenUserSwitcher.java271
-rw-r--r--packages/CarSystemUI/src/com/android/systemui/window/OverlayViewController.java123
-rw-r--r--packages/CarSystemUI/src/com/android/systemui/window/OverlayViewGlobalStateController.java112
-rw-r--r--packages/CarSystemUI/src/com/android/systemui/window/OverlayViewMediator.java (renamed from apex/appsearch/framework/java/android/app/appsearch/IllegalSearchSpecException.java)26
-rw-r--r--packages/CarSystemUI/src/com/android/systemui/window/OverlayWindowModule.java37
-rw-r--r--packages/CarSystemUI/src/com/android/systemui/window/SystemUIOverlayWindowController.java (renamed from packages/CarSystemUI/src/com/android/systemui/car/SystemUIPrimaryWindowController.java)10
-rw-r--r--packages/CarSystemUI/src/com/android/systemui/window/SystemUIOverlayWindowManager.java92
-rw-r--r--packages/CarSystemUI/tests/res/layout/overlay_view_controller_stub.xml22
-rw-r--r--packages/CarSystemUI/tests/res/layout/overlay_view_controller_test.xml30
-rw-r--r--packages/CarSystemUI/tests/src/com/android/systemui/car/notification/CarHeadsUpNotificationSystemContainerTest.java134
-rw-r--r--packages/CarSystemUI/tests/src/com/android/systemui/navigationbar/car/CarNavigationBarTest.java122
-rw-r--r--packages/CarSystemUI/tests/src/com/android/systemui/window/OverlayViewControllerTest.java158
-rw-r--r--packages/CarSystemUI/tests/src/com/android/systemui/window/OverlayViewGlobalStateControllerTest.java250
-rw-r--r--packages/DynamicSystemInstallationService/src/com/android/dynsystem/DynamicSystemInstallationService.java26
-rw-r--r--packages/SettingsLib/Android.bp35
-rw-r--r--packages/SettingsLib/HelpUtils/src/com/android/settingslib/HelpUtils.java7
-rw-r--r--packages/SettingsLib/SchedulesProvider/src/com/android/settingslib/schedulesprovider/ScheduleInfo.java39
-rw-r--r--packages/SettingsLib/res/values-as/strings.xml3
-rw-r--r--packages/SettingsLib/res/values-bn/strings.xml3
-rw-r--r--packages/SettingsLib/res/values-de/strings.xml3
-rw-r--r--packages/SettingsLib/res/values-eu/strings.xml3
-rw-r--r--packages/SettingsLib/res/values-fr-rCA/strings.xml3
-rw-r--r--packages/SettingsLib/res/values-gu/strings.xml3
-rw-r--r--packages/SettingsLib/res/values-hi/strings.xml9
-rw-r--r--packages/SettingsLib/res/values-is/strings.xml3
-rw-r--r--packages/SettingsLib/res/values-iw/strings.xml2
-rw-r--r--packages/SettingsLib/res/values-km/strings.xml2
-rw-r--r--packages/SettingsLib/res/values-kn/strings.xml3
-rw-r--r--packages/SettingsLib/res/values-ml/strings.xml3
-rw-r--r--packages/SettingsLib/res/values-mr/strings.xml3
-rw-r--r--packages/SettingsLib/res/values-ne/strings.xml3
-rw-r--r--packages/SettingsLib/res/values-or/strings.xml3
-rw-r--r--packages/SettingsLib/res/values-pa/strings.xml3
-rw-r--r--packages/SettingsLib/res/values-ta/strings.xml15
-rw-r--r--packages/SettingsLib/res/values-te/strings.xml3
-rw-r--r--packages/SettingsLib/res/values-ur/strings.xml3
-rw-r--r--packages/SettingsLib/res/values-zh-rCN/strings.xml3
-rw-r--r--packages/SettingsLib/src/com/android/settingslib/bluetooth/A2dpProfile.java35
-rw-r--r--packages/SettingsLib/src/com/android/settingslib/media/InfoMediaManager.java57
-rw-r--r--packages/SettingsLib/src/com/android/settingslib/media/LocalMediaManager.java56
-rw-r--r--packages/SettingsLib/src/com/android/settingslib/media/MediaManager.java18
-rw-r--r--packages/SettingsLib/src/com/android/settingslib/wifi/WifiEntryPreference.java6
-rw-r--r--packages/SettingsLib/tests/robotests/src/com/android/settingslib/bluetooth/A2dpProfileTest.java21
-rw-r--r--packages/SettingsLib/tests/robotests/src/com/android/settingslib/media/InfoMediaManagerTest.java62
-rw-r--r--packages/SettingsLib/tests/robotests/src/com/android/settingslib/media/LocalMediaManagerTest.java9
-rw-r--r--packages/SettingsLib/tests/robotests/src/com/android/settingslib/media/MediaManagerTest.java10
-rw-r--r--packages/SettingsLib/tests/robotests/src/com/android/settingslib/schedulesprovider/ScheduleInfoTest.java41
-rw-r--r--packages/SettingsLib/tests/robotests/src/com/android/settingslib/schedulesprovider/SchedulesProviderTest.java64
-rw-r--r--packages/SettingsProvider/res/values-ta/strings.xml6
-rw-r--r--packages/SettingsProvider/src/android/provider/settings/backup/SecureSettings.java1
-rw-r--r--packages/SettingsProvider/src/android/provider/settings/validators/SecureSettingsValidators.java3
-rw-r--r--packages/SettingsProvider/src/com/android/providers/settings/SettingsProtoDumpUtil.java5
-rw-r--r--packages/Shell/AndroidManifest.xml1
-rw-r--r--packages/SystemUI/Android.bp2
-rw-r--r--packages/SystemUI/AndroidManifest.xml21
-rw-r--r--packages/SystemUI/res/drawable/control_spinner_background.xml35
-rw-r--r--packages/SystemUI/res/drawable/dismiss_circle_background.xml28
-rw-r--r--packages/SystemUI/res/drawable/dismiss_target_x.xml28
-rw-r--r--packages/SystemUI/res/layout-land-television/volume_dialog.xml101
-rw-r--r--packages/SystemUI/res/layout-land-television/volume_dialog_row.xml69
-rw-r--r--packages/SystemUI/res/layout/controls_base_item.xml11
-rw-r--r--packages/SystemUI/res/layout/controls_dialog.xml34
-rw-r--r--packages/SystemUI/res/layout/controls_dialog_pin.xml36
-rw-r--r--packages/SystemUI/res/layout/controls_management.xml51
-rw-r--r--packages/SystemUI/res/layout/controls_management_apps.xml18
-rw-r--r--packages/SystemUI/res/layout/controls_management_favorites.xml16
-rw-r--r--packages/SystemUI/res/layout/controls_no_favorites.xml1
-rw-r--r--packages/SystemUI/res/layout/controls_spinner_item.xml31
-rw-r--r--packages/SystemUI/res/layout/controls_structure_page.xml31
-rw-r--r--packages/SystemUI/res/layout/controls_with_favorites.xml64
-rw-r--r--packages/SystemUI/res/layout/global_actions_grid_v2.xml114
-rw-r--r--packages/SystemUI/res/layout/global_actions_wrapped.xml38
-rw-r--r--packages/SystemUI/res/layout/notification_conversation_info.xml1
-rw-r--r--packages/SystemUI/res/layout/notification_info.xml217
-rw-r--r--packages/SystemUI/res/layout/qs_media_panel.xml3
-rw-r--r--packages/SystemUI/res/values-af/strings.xml16
-rw-r--r--packages/SystemUI/res/values-am/strings.xml16
-rw-r--r--packages/SystemUI/res/values-ar/strings.xml22
-rw-r--r--packages/SystemUI/res/values-as/strings.xml23
-rw-r--r--packages/SystemUI/res/values-az/strings.xml16
-rw-r--r--packages/SystemUI/res/values-b+sr+Latn/strings.xml16
-rw-r--r--packages/SystemUI/res/values-be/strings.xml16
-rw-r--r--packages/SystemUI/res/values-bg/strings.xml16
-rw-r--r--packages/SystemUI/res/values-bn/strings.xml23
-rw-r--r--packages/SystemUI/res/values-bs/strings.xml16
-rw-r--r--packages/SystemUI/res/values-ca/strings.xml16
-rw-r--r--packages/SystemUI/res/values-cs/strings.xml16
-rw-r--r--packages/SystemUI/res/values-da/strings.xml16
-rw-r--r--packages/SystemUI/res/values-de/strings.xml17
-rw-r--r--packages/SystemUI/res/values-el/strings.xml7
-rw-r--r--packages/SystemUI/res/values-en-rAU/strings.xml4
-rw-r--r--packages/SystemUI/res/values-en-rCA/strings.xml4
-rw-r--r--packages/SystemUI/res/values-en-rGB/strings.xml4
-rw-r--r--packages/SystemUI/res/values-en-rIN/strings.xml4
-rw-r--r--packages/SystemUI/res/values-en-rXC/strings.xml4
-rw-r--r--packages/SystemUI/res/values-es-rUS/strings.xml16
-rw-r--r--packages/SystemUI/res/values-es/strings.xml16
-rw-r--r--packages/SystemUI/res/values-et/strings.xml16
-rw-r--r--packages/SystemUI/res/values-eu/strings.xml16
-rw-r--r--packages/SystemUI/res/values-fa/strings.xml18
-rw-r--r--packages/SystemUI/res/values-fi/strings.xml16
-rw-r--r--packages/SystemUI/res/values-fr-rCA/strings.xml16
-rw-r--r--packages/SystemUI/res/values-fr/strings.xml16
-rw-r--r--packages/SystemUI/res/values-gl/strings.xml16
-rw-r--r--packages/SystemUI/res/values-gu/strings.xml23
-rw-r--r--packages/SystemUI/res/values-hi/strings.xml25
-rw-r--r--packages/SystemUI/res/values-hr/strings.xml16
-rw-r--r--packages/SystemUI/res/values-hu/strings.xml16
-rw-r--r--packages/SystemUI/res/values-hy/strings.xml7
-rw-r--r--packages/SystemUI/res/values-in/strings.xml7
-rw-r--r--packages/SystemUI/res/values-is/strings.xml16
-rw-r--r--packages/SystemUI/res/values-it/strings.xml16
-rw-r--r--packages/SystemUI/res/values-iw/strings.xml16
-rw-r--r--packages/SystemUI/res/values-ja/strings.xml16
-rw-r--r--packages/SystemUI/res/values-ka/strings.xml16
-rw-r--r--packages/SystemUI/res/values-kk/strings.xml16
-rw-r--r--packages/SystemUI/res/values-km/strings.xml16
-rw-r--r--packages/SystemUI/res/values-kn/strings.xml23
-rw-r--r--packages/SystemUI/res/values-ko/strings.xml16
-rw-r--r--packages/SystemUI/res/values-ky/strings.xml16
-rw-r--r--packages/SystemUI/res/values-land-television/dimens.xml21
-rw-r--r--packages/SystemUI/res/values-lo/strings.xml16
-rw-r--r--packages/SystemUI/res/values-lt/strings.xml16
-rw-r--r--packages/SystemUI/res/values-lv/strings.xml16
-rw-r--r--packages/SystemUI/res/values-ml/strings.xml23
-rw-r--r--packages/SystemUI/res/values-mn/strings.xml16
-rw-r--r--packages/SystemUI/res/values-mr/strings.xml23
-rw-r--r--packages/SystemUI/res/values-ms/strings.xml16
-rw-r--r--packages/SystemUI/res/values-my/strings.xml7
-rw-r--r--packages/SystemUI/res/values-nb/strings.xml16
-rw-r--r--packages/SystemUI/res/values-ne/strings.xml23
-rw-r--r--packages/SystemUI/res/values-nl/strings.xml16
-rw-r--r--packages/SystemUI/res/values-or/strings.xml23
-rw-r--r--packages/SystemUI/res/values-pa/strings.xml23
-rw-r--r--packages/SystemUI/res/values-pl/strings.xml16
-rw-r--r--packages/SystemUI/res/values-pt-rBR/strings.xml16
-rw-r--r--packages/SystemUI/res/values-pt-rPT/strings.xml16
-rw-r--r--packages/SystemUI/res/values-pt/strings.xml16
-rw-r--r--packages/SystemUI/res/values-ro/strings.xml16
-rw-r--r--packages/SystemUI/res/values-ru/strings.xml16
-rw-r--r--packages/SystemUI/res/values-si/strings.xml16
-rw-r--r--packages/SystemUI/res/values-sk/strings.xml16
-rw-r--r--packages/SystemUI/res/values-sl/strings.xml16
-rw-r--r--packages/SystemUI/res/values-sq/strings.xml16
-rw-r--r--packages/SystemUI/res/values-sr/strings.xml16
-rw-r--r--packages/SystemUI/res/values-sv/strings.xml16
-rw-r--r--packages/SystemUI/res/values-sw/strings.xml16
-rw-r--r--packages/SystemUI/res/values-ta/strings.xml46
-rw-r--r--packages/SystemUI/res/values-te/strings.xml23
-rw-r--r--packages/SystemUI/res/values-television/integers.xml22
-rw-r--r--packages/SystemUI/res/values-th/strings.xml16
-rw-r--r--packages/SystemUI/res/values-tl/strings.xml16
-rw-r--r--packages/SystemUI/res/values-tr/strings.xml16
-rw-r--r--packages/SystemUI/res/values-uk/strings.xml16
-rw-r--r--packages/SystemUI/res/values-ur/strings.xml17
-rw-r--r--packages/SystemUI/res/values-uz/strings.xml16
-rw-r--r--packages/SystemUI/res/values-vi/strings.xml16
-rw-r--r--packages/SystemUI/res/values-zh-rCN/strings.xml16
-rw-r--r--packages/SystemUI/res/values-zh-rHK/strings.xml16
-rw-r--r--packages/SystemUI/res/values-zh-rTW/strings.xml16
-rw-r--r--packages/SystemUI/res/values-zu/strings.xml16
-rw-r--r--packages/SystemUI/res/values/colors.xml10
-rw-r--r--packages/SystemUI/res/values/config.xml17
-rw-r--r--packages/SystemUI/res/values/dimens.xml24
-rw-r--r--packages/SystemUI/res/values/integers.xml4
-rw-r--r--packages/SystemUI/res/values/strings.xml14
-rw-r--r--packages/SystemUI/res/values/styles.xml37
-rw-r--r--packages/SystemUI/shared/src/com/android/systemui/shared/system/InputConsumerController.java2
-rw-r--r--packages/SystemUI/shared/src/com/android/systemui/shared/system/QuickStepContract.java9
-rw-r--r--packages/SystemUI/shared/src/com/android/systemui/shared/system/RemoteAnimationTargetCompat.java4
-rw-r--r--packages/SystemUI/shared/src/com/android/systemui/shared/system/SurfaceViewRequestReceiver.java96
-rw-r--r--packages/SystemUI/shared/src/com/android/systemui/shared/system/SurfaceViewRequestUtils.java55
-rw-r--r--packages/SystemUI/shared/src/com/android/systemui/shared/system/UniversalSmartspaceUtils.java29
-rw-r--r--packages/SystemUI/src/com/android/keyguard/KeyguardStatusView.java41
-rw-r--r--packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java3
-rw-r--r--packages/SystemUI/src/com/android/keyguard/KeyguardViewController.java174
-rw-r--r--packages/SystemUI/src/com/android/systemui/CameraAvailabilityListener.kt138
-rw-r--r--packages/SystemUI/src/com/android/systemui/HardwareUiLayout.java570
-rw-r--r--packages/SystemUI/src/com/android/systemui/ScreenDecorations.java121
-rw-r--r--packages/SystemUI/src/com/android/systemui/SizeCompatModeActivityController.java3
-rw-r--r--packages/SystemUI/src/com/android/systemui/assist/AssistManager.java5
-rw-r--r--packages/SystemUI/src/com/android/systemui/assist/ui/DefaultUiController.java6
-rw-r--r--packages/SystemUI/src/com/android/systemui/bubbles/Bubble.java3
-rw-r--r--packages/SystemUI/src/com/android/systemui/bubbles/BubbleController.java20
-rw-r--r--packages/SystemUI/src/com/android/systemui/bubbles/BubbleDebugConfig.java6
-rw-r--r--packages/SystemUI/src/com/android/systemui/bubbles/BubbleExpandedView.java14
-rw-r--r--packages/SystemUI/src/com/android/systemui/bubbles/BubbleExperimentConfig.java12
-rw-r--r--packages/SystemUI/src/com/android/systemui/bubbles/BubbleOverflow.java18
-rw-r--r--packages/SystemUI/src/com/android/systemui/bubbles/BubbleStackView.java349
-rw-r--r--packages/SystemUI/src/com/android/systemui/bubbles/BubbleTouchHandler.java142
-rw-r--r--packages/SystemUI/src/com/android/systemui/bubbles/BubbleViewProvider.java2
-rw-r--r--packages/SystemUI/src/com/android/systemui/bubbles/animation/ExpandedAnimationController.java127
-rw-r--r--packages/SystemUI/src/com/android/systemui/bubbles/animation/StackAnimationController.java183
-rw-r--r--packages/SystemUI/src/com/android/systemui/controls/ControlStatus.kt4
-rw-r--r--packages/SystemUI/src/com/android/systemui/controls/controller/ControlsController.kt12
-rw-r--r--packages/SystemUI/src/com/android/systemui/controls/controller/ControlsControllerImpl.kt76
-rw-r--r--packages/SystemUI/src/com/android/systemui/controls/dagger/ControlsModule.kt8
-rw-r--r--packages/SystemUI/src/com/android/systemui/controls/management/AllModel.kt17
-rw-r--r--packages/SystemUI/src/com/android/systemui/controls/management/ControlAdapter.kt16
-rw-r--r--packages/SystemUI/src/com/android/systemui/controls/management/ControlsFavoritingActivity.kt179
-rw-r--r--packages/SystemUI/src/com/android/systemui/controls/management/ControlsListingControllerImpl.kt15
-rw-r--r--packages/SystemUI/src/com/android/systemui/controls/management/ControlsRequestDialog.kt177
-rw-r--r--packages/SystemUI/src/com/android/systemui/controls/management/ControlsRequestReceiver.kt78
-rw-r--r--packages/SystemUI/src/com/android/systemui/controls/management/ManagementPageIndicator.kt43
-rw-r--r--packages/SystemUI/src/com/android/systemui/controls/management/StructureAdapter.kt73
-rw-r--r--packages/SystemUI/src/com/android/systemui/controls/ui/ChallengeDialogs.kt102
-rw-r--r--packages/SystemUI/src/com/android/systemui/controls/ui/ControlActionCoordinator.kt5
-rw-r--r--packages/SystemUI/src/com/android/systemui/controls/ui/ControlViewHolder.kt28
-rw-r--r--packages/SystemUI/src/com/android/systemui/controls/ui/ControlsUiControllerImpl.kt215
-rw-r--r--packages/SystemUI/src/com/android/systemui/controls/ui/DefaultBehavior.kt3
-rw-r--r--packages/SystemUI/src/com/android/systemui/controls/ui/RenderInfo.kt60
-rw-r--r--packages/SystemUI/src/com/android/systemui/controls/ui/StaticBehavior.kt67
-rw-r--r--packages/SystemUI/src/com/android/systemui/controls/ui/TemperatureControlBehavior.kt5
-rw-r--r--packages/SystemUI/src/com/android/systemui/controls/ui/ToggleBehavior.kt7
-rw-r--r--packages/SystemUI/src/com/android/systemui/controls/ui/ToggleRangeBehavior.kt7
-rw-r--r--packages/SystemUI/src/com/android/systemui/controls/ui/TouchBehavior.kt58
-rw-r--r--packages/SystemUI/src/com/android/systemui/controls/ui/UnknownBehavior.kt3
-rw-r--r--packages/SystemUI/src/com/android/systemui/dagger/DependencyBinder.java8
-rw-r--r--packages/SystemUI/src/com/android/systemui/dagger/SystemUIDefaultModule.java13
-rw-r--r--packages/SystemUI/src/com/android/systemui/doze/DozeSensors.java2
-rw-r--r--packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsDialog.java19
-rw-r--r--packages/SystemUI/src/com/android/systemui/globalactions/MinHeightScrollView.java43
-rw-r--r--packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java70
-rw-r--r--packages/SystemUI/src/com/android/systemui/keyguard/dagger/KeyguardModule.java4
-rw-r--r--packages/SystemUI/src/com/android/systemui/media/MediaControlPanel.java425
-rw-r--r--packages/SystemUI/src/com/android/systemui/pip/PipAnimationController.java117
-rw-r--r--packages/SystemUI/src/com/android/systemui/pip/PipBoundsHandler.java9
-rw-r--r--packages/SystemUI/src/com/android/systemui/pip/PipSnapAlgorithm.java232
-rw-r--r--packages/SystemUI/src/com/android/systemui/pip/PipTaskOrganizer.java358
-rw-r--r--packages/SystemUI/src/com/android/systemui/pip/phone/PipManager.java17
-rw-r--r--packages/SystemUI/src/com/android/systemui/pip/phone/PipMenuActivity.java10
-rw-r--r--packages/SystemUI/src/com/android/systemui/pip/phone/PipMotionHelper.java131
-rw-r--r--packages/SystemUI/src/com/android/systemui/pip/phone/PipResizeGestureHandler.java21
-rw-r--r--packages/SystemUI/src/com/android/systemui/pip/phone/PipTouchHandler.java138
-rw-r--r--packages/SystemUI/src/com/android/systemui/pip/phone/PipUpdateThread.java (renamed from packages/SystemUI/src/com/android/systemui/pip/phone/ForegroundThread.java)25
-rw-r--r--packages/SystemUI/src/com/android/systemui/pip/tv/PipManager.java12
-rw-r--r--packages/SystemUI/src/com/android/systemui/qs/QSMediaPlayer.java362
-rw-r--r--packages/SystemUI/src/com/android/systemui/qs/QSPanel.java20
-rw-r--r--packages/SystemUI/src/com/android/systemui/qs/QuickQSMediaPlayer.java202
-rw-r--r--packages/SystemUI/src/com/android/systemui/qs/QuickQSPanel.java13
-rw-r--r--packages/SystemUI/src/com/android/systemui/screenshot/TakeScreenshotService.java8
-rw-r--r--packages/SystemUI/src/com/android/systemui/stackdivider/Divider.java361
-rw-r--r--packages/SystemUI/src/com/android/systemui/stackdivider/DividerView.java3
-rw-r--r--packages/SystemUI/src/com/android/systemui/stackdivider/DividerWindowManager.java3
-rw-r--r--packages/SystemUI/src/com/android/systemui/stackdivider/SplitDisplayLayout.java21
-rw-r--r--packages/SystemUI/src/com/android/systemui/stackdivider/WindowManagerProxy.java21
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/MediaArtworkProcessor.kt24
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/NavigationBarController.java1
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/NotificationMediaManager.java4
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/NotificationShadeWindowBlurController.kt19
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/ScrimView.java5
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/ActivityLaunchAnimator.java2
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/ForegroundServiceDismissalFeatureController.kt4
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotificationRankingManager.kt23
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/provider/HighPriorityProvider.java4
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/dagger/NotificationsModule.java24
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/logging/NotificationLogger.java7
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/logging/NotificationPanelLogger.java95
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/logging/NotificationPanelLoggerImpl.java41
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/logging/Notifications.proto49
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/people/PeopleHub.kt6
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/people/PeopleHubNotificationListener.kt89
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/people/PeopleHubViewController.kt4
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/people/PeopleNotificationIdentifier.kt89
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationGutsManager.java4
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationInfo.java270
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationUndoLayout.java139
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationSectionsManager.java9
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayout.java44
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/LockIcon.java83
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/LockscreenLockIconController.java70
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarFragment.java49
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationModeController.java110
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimController.java26
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java2
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java51
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/policy/BatteryController.java9
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/policy/BatteryControllerImpl.java6
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/policy/DeviceProvisionedControllerImpl.java2
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkControllerImpl.java3
-rw-r--r--packages/SystemUI/src/com/android/systemui/theme/ThemeOverlayController.java4
-rw-r--r--packages/SystemUI/src/com/android/systemui/tuner/TunerServiceImpl.java7
-rw-r--r--packages/SystemUI/src/com/android/systemui/util/DismissCircleView.java62
-rw-r--r--packages/SystemUI/src/com/android/systemui/util/magnetictarget/MagnetizedObject.kt2
-rw-r--r--packages/SystemUI/src/com/android/systemui/util/sensors/ProximitySensor.java6
-rw-r--r--packages/SystemUI/src/com/android/systemui/volume/VolumeDialogImpl.java5
-rw-r--r--packages/SystemUI/src/com/android/systemui/wm/DisplayImeController.java80
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/bubbles/BubbleControllerTest.java15
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/bubbles/NewNotifPipelineBubbleControllerTest.java23
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/bubbles/animation/ExpandedAnimationControllerTest.java113
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/bubbles/animation/StackAnimationControllerTest.java57
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/controls/controller/ControlsControllerImplTest.kt26
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/controls/management/AllModelTest.kt4
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/controls/management/ControlsListingControllerImplTest.kt72
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/controls/management/ControlsRequestReceiverTest.kt161
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/controls/management/FavoriteModelTest.kt4
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/pip/PipAnimationControllerTest.java56
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/pip/PipBoundsHandlerTest.java2
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/pip/phone/PipTouchHandlerTest.java168
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/qs/QSPanelTest.java8
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/MediaArtworkProcessorTest.kt24
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/SbnBuilder.java15
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/HighPriorityProviderTest.java33
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/NotificationEntryBuilder.java6
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/NotificationRankingManagerTest.kt26
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/logging/NotificationLoggerTest.java47
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/logging/NotificationPanelLoggerFake.java51
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/people/PeopleHubViewControllerTest.kt4
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationEntryManagerInflationTest.java63
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationGutsManagerTest.java74
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationInfoTest.java424
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationSectionsManagerTest.java18
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutTest.java25
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/LockscreenIconControllerTest.java12
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarTest.java3
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/util/sensors/ProximitySensorTest.java24
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/volume/EventsTest.java4
-rw-r--r--packages/Tethering/common/TetheringLib/src/android/net/ITetheringEventCallback.aidl1
-rw-r--r--packages/Tethering/common/TetheringLib/src/android/net/TetheringCallbackStartedParcel.aidl3
-rw-r--r--packages/Tethering/common/TetheringLib/src/android/net/TetheringManager.java56
-rw-r--r--packages/Tethering/src/android/net/ip/IpServer.java21
-rw-r--r--packages/Tethering/src/com/android/server/connectivity/tethering/OffloadController.java11
-rw-r--r--packages/Tethering/src/com/android/server/connectivity/tethering/Tethering.java52
-rw-r--r--packages/Tethering/tests/unit/src/android/net/ip/IpServerTest.java62
-rw-r--r--packages/Tethering/tests/unit/src/com/android/server/connectivity/tethering/TetheringTest.java98
-rw-r--r--services/art-profile6
-rw-r--r--services/autofill/java/com/android/server/autofill/RemoteAugmentedAutofillService.java8
-rw-r--r--services/autofill/java/com/android/server/autofill/Session.java6
-rw-r--r--services/autofill/java/com/android/server/autofill/ui/InlineSuggestionFactory.java54
-rw-r--r--services/core/Android.bp1
-rw-r--r--services/core/java/android/content/pm/PackageManagerInternal.java17
-rw-r--r--services/core/java/com/android/server/BluetoothManagerService.java104
-rw-r--r--services/core/java/com/android/server/ConnectivityService.java56
-rw-r--r--services/core/java/com/android/server/DynamicSystemService.java48
-rw-r--r--services/core/java/com/android/server/PackageWatchdog.java18
-rw-r--r--services/core/java/com/android/server/StorageManagerService.java3
-rw-r--r--services/core/java/com/android/server/TelephonyRegistry.java37
-rw-r--r--services/core/java/com/android/server/UiModeManagerService.java8
-rw-r--r--services/core/java/com/android/server/Watchdog.java71
-rw-r--r--services/core/java/com/android/server/am/ActivityManagerConstants.java44
-rw-r--r--services/core/java/com/android/server/am/ActivityManagerService.java64
-rw-r--r--services/core/java/com/android/server/am/AppErrors.java14
-rw-r--r--services/core/java/com/android/server/am/AppExitInfoTracker.java43
-rw-r--r--services/core/java/com/android/server/am/CachedAppOptimizer.java130
-rw-r--r--services/core/java/com/android/server/am/OWNERS6
-rw-r--r--services/core/java/com/android/server/am/OomAdjuster.java55
-rw-r--r--services/core/java/com/android/server/am/ProcessList.java41
-rw-r--r--services/core/java/com/android/server/am/ProcessRecord.java3
-rw-r--r--services/core/java/com/android/server/appop/AppOpsService.java230
-rw-r--r--services/core/java/com/android/server/biometrics/BiometricService.java5
-rw-r--r--services/core/java/com/android/server/compat/CompatChange.java15
-rw-r--r--services/core/java/com/android/server/compat/CompatConfig.java27
-rw-r--r--services/core/java/com/android/server/compat/OverrideValidatorImpl.java19
-rw-r--r--services/core/java/com/android/server/connectivity/NetworkAgentInfo.java27
-rw-r--r--services/core/java/com/android/server/connectivity/NetworkNotificationManager.java19
-rw-r--r--services/core/java/com/android/server/connectivity/Vpn.java44
-rw-r--r--services/core/java/com/android/server/connectivity/VpnIkev2Utils.java14
-rw-r--r--services/core/java/com/android/server/content/ContentService.java153
-rw-r--r--services/core/java/com/android/server/content/SyncStorageEngine.java7
-rw-r--r--services/core/java/com/android/server/incremental/IncrementalManagerService.java146
-rw-r--r--services/core/java/com/android/server/inputmethod/InputMethodManagerService.java5
-rw-r--r--services/core/java/com/android/server/integrity/AppIntegrityManagerServiceImpl.java17
-rw-r--r--services/core/java/com/android/server/integrity/TEST_MAPPING8
-rw-r--r--services/core/java/com/android/server/locksettings/LockSettingsService.java20
-rw-r--r--services/core/java/com/android/server/media/MediaKeyDispatcher.java19
-rw-r--r--services/core/java/com/android/server/media/MediaRoute2Provider.java17
-rw-r--r--services/core/java/com/android/server/media/MediaRoute2ProviderServiceProxy.java99
-rw-r--r--services/core/java/com/android/server/media/MediaRouter2ServiceImpl.java348
-rw-r--r--services/core/java/com/android/server/media/MediaRouterService.java48
-rw-r--r--services/core/java/com/android/server/media/MediaSession2Record.java1
-rw-r--r--services/core/java/com/android/server/media/MediaSessionService.java94
-rw-r--r--services/core/java/com/android/server/media/MediaSessionStack.java6
-rw-r--r--services/core/java/com/android/server/media/SessionPolicyProvider.java19
-rw-r--r--services/core/java/com/android/server/media/SystemMediaRoute2Provider.java17
-rw-r--r--services/core/java/com/android/server/notification/NotificationHistoryManager.java9
-rwxr-xr-xservices/core/java/com/android/server/notification/NotificationManagerService.java7
-rw-r--r--services/core/java/com/android/server/om/OverlayActorEnforcer.java11
-rw-r--r--services/core/java/com/android/server/pm/AppsFilter.java111
-rw-r--r--services/core/java/com/android/server/pm/DataLoaderManagerService.java5
-rw-r--r--services/core/java/com/android/server/pm/PackageManagerService.java41
-rw-r--r--services/core/java/com/android/server/pm/PackageManagerShellCommand.java37
-rw-r--r--services/core/java/com/android/server/pm/PackageSetting.java2
-rw-r--r--services/core/java/com/android/server/pm/Settings.java59
-rw-r--r--services/core/java/com/android/server/pm/StagingManager.java28
-rw-r--r--services/core/java/com/android/server/pm/permission/DefaultPermissionGrantPolicy.java14
-rw-r--r--services/core/java/com/android/server/pm/permission/PermissionManagerService.java9
-rw-r--r--services/core/java/com/android/server/pm/permission/PermissionManagerServiceInternal.java6
-rw-r--r--services/core/java/com/android/server/pm/pkg/PackageStateUnserialized.java17
-rw-r--r--services/core/java/com/android/server/policy/PermissionPolicyService.java4
-rw-r--r--services/core/java/com/android/server/power/PowerManagerService.java53
-rw-r--r--services/core/java/com/android/server/soundtrigger_middleware/SoundTriggerMiddlewareValidation.java38
-rw-r--r--services/core/java/com/android/server/stats/pull/StatsPullAtomService.java328
-rw-r--r--services/core/java/com/android/server/statusbar/StatusBarManagerService.java3
-rw-r--r--services/core/java/com/android/server/timezonedetector/TimeZoneDetectorCallbackImpl.java16
-rw-r--r--services/core/java/com/android/server/tv/TvRemoteProviderWatcher.java5
-rw-r--r--services/core/java/com/android/server/tv/tunerresourcemanager/ClientProfile.java8
-rw-r--r--services/core/java/com/android/server/tv/tunerresourcemanager/FrontendResource.java37
-rw-r--r--services/core/java/com/android/server/tv/tunerresourcemanager/TunerResourceManagerService.java236
-rw-r--r--services/core/java/com/android/server/tv/tunerresourcemanager/UseCasePriorityHints.java6
-rw-r--r--services/core/java/com/android/server/updates/ConfigUpdateInstallReceiver.java8
-rw-r--r--services/core/java/com/android/server/wm/AccessibilityController.java5
-rw-r--r--services/core/java/com/android/server/wm/ActivityRecord.java374
-rw-r--r--services/core/java/com/android/server/wm/ActivityStack.java48
-rw-r--r--services/core/java/com/android/server/wm/ActivityStarter.java46
-rw-r--r--services/core/java/com/android/server/wm/ActivityTaskManagerService.java61
-rw-r--r--services/core/java/com/android/server/wm/AppTransitionController.java2
-rw-r--r--services/core/java/com/android/server/wm/BLASTSyncEngine.java1
-rw-r--r--services/core/java/com/android/server/wm/DisplayArea.java25
-rw-r--r--services/core/java/com/android/server/wm/DisplayContent.java18
-rw-r--r--services/core/java/com/android/server/wm/DisplayPolicy.java43
-rw-r--r--services/core/java/com/android/server/wm/EmbeddedWindowController.java59
-rw-r--r--services/core/java/com/android/server/wm/ImeInsetsSourceProvider.java7
-rw-r--r--services/core/java/com/android/server/wm/InsetsControlTarget.java7
-rw-r--r--services/core/java/com/android/server/wm/InsetsPolicy.java86
-rw-r--r--services/core/java/com/android/server/wm/InsetsSourceProvider.java2
-rw-r--r--services/core/java/com/android/server/wm/InsetsStateController.java37
-rw-r--r--services/core/java/com/android/server/wm/RecentTasks.java17
-rw-r--r--services/core/java/com/android/server/wm/RecentsAnimationController.java23
-rw-r--r--services/core/java/com/android/server/wm/RemoteAnimationController.java20
-rw-r--r--services/core/java/com/android/server/wm/RootWindowContainer.java29
-rw-r--r--services/core/java/com/android/server/wm/RunningTasks.java5
-rw-r--r--services/core/java/com/android/server/wm/SeamlessRotator.java4
-rw-r--r--services/core/java/com/android/server/wm/SurfaceAnimator.java4
-rw-r--r--services/core/java/com/android/server/wm/Task.java83
-rw-r--r--services/core/java/com/android/server/wm/TaskOrganizerController.java16
-rw-r--r--services/core/java/com/android/server/wm/TaskPositioner.java106
-rw-r--r--services/core/java/com/android/server/wm/TaskTile.java14
-rw-r--r--services/core/java/com/android/server/wm/WallpaperAnimationAdapter.java2
-rw-r--r--services/core/java/com/android/server/wm/WindowAnimator.java2
-rw-r--r--services/core/java/com/android/server/wm/WindowContainer.java27
-rw-r--r--services/core/java/com/android/server/wm/WindowManagerService.java30
-rw-r--r--services/core/java/com/android/server/wm/WindowProcessController.java38
-rw-r--r--services/core/java/com/android/server/wm/WindowState.java29
-rw-r--r--services/core/java/com/android/server/wm/WindowStateAnimator.java26
-rw-r--r--services/core/java/com/android/server/wm/WindowSurfaceController.java10
-rw-r--r--services/core/java/com/android/server/wm/WindowToken.java21
-rw-r--r--services/core/jni/Android.bp2
-rw-r--r--services/core/jni/com_android_server_SystemServer.cpp30
-rw-r--r--services/core/jni/com_android_server_am_BatteryStatsService.cpp22
-rw-r--r--services/core/jni/com_android_server_incremental_IncrementalManagerService.cpp52
-rw-r--r--services/core/jni/com_android_server_power_PowerManagerService.cpp309
-rw-r--r--services/core/jni/onload.cpp2
-rw-r--r--services/core/xsd/platform-compat-config.xsd1
-rw-r--r--services/core/xsd/platform-compat-schema/current.txt2
-rw-r--r--services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java81
-rw-r--r--services/incremental/BinderIncrementalService.h2
-rw-r--r--services/incremental/IncrementalService.cpp36
-rw-r--r--services/incremental/IncrementalService.h3
-rw-r--r--services/incremental/ServiceWrappers.cpp10
-rw-r--r--services/incremental/ServiceWrappers.h49
-rw-r--r--services/incremental/test/IncrementalServiceTest.cpp122
-rw-r--r--services/java/com/android/server/SystemServer.java29
-rw-r--r--services/people/java/com/android/server/people/PeopleService.java8
-rw-r--r--services/people/java/com/android/server/people/data/DataManager.java6
-rw-r--r--services/tests/mockingservicestests/src/com/android/server/am/ApplicationExitInfoTest.java4
-rw-r--r--services/tests/mockingservicestests/src/com/android/server/am/CachedAppOptimizerTest.java5
-rw-r--r--services/tests/mockingservicestests/src/com/android/server/blob/BlobStoreConfigTest.java94
-rw-r--r--services/tests/mockingservicestests/src/com/android/server/blob/BlobStoreManagerServiceTest.java31
-rw-r--r--services/tests/mockingservicestests/src/com/android/server/testables/TestableDeviceConfig.java52
-rw-r--r--services/tests/mockingservicestests/src/com/android/server/testables/TestableDeviceConfigTest.java40
-rw-r--r--services/tests/servicestests/Android.bp1
-rw-r--r--services/tests/servicestests/src/com/android/server/appsearch/impl/AppSearchImplTest.java109
-rw-r--r--services/tests/servicestests/src/com/android/server/appsearch/impl/FakeIcingTest.java127
-rw-r--r--services/tests/servicestests/src/com/android/server/compat/CompatConfigBuilder.java25
-rw-r--r--services/tests/servicestests/src/com/android/server/compat/CompatConfigTest.java11
-rw-r--r--services/tests/servicestests/src/com/android/server/compat/OverrideValidatorImplTest.java44
-rw-r--r--services/tests/servicestests/src/com/android/server/content/ObserverNodeTest.java113
-rw-r--r--services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerServiceTestable.java12
-rw-r--r--services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java39
-rw-r--r--services/tests/servicestests/src/com/android/server/devicepolicy/DpmMockContext.java2
-rw-r--r--services/tests/servicestests/src/com/android/server/devicepolicy/MockSystemServices.java6
-rw-r--r--services/tests/servicestests/src/com/android/server/integrity/AppIntegrityManagerServiceImplTest.java8
-rw-r--r--services/tests/servicestests/src/com/android/server/locksettings/LockSettingsServiceTests.java1
-rw-r--r--services/tests/servicestests/src/com/android/server/people/data/DataManagerTest.java2
-rw-r--r--services/tests/servicestests/src/com/android/server/tv/TvRemoteProviderWatcherTest.java146
-rw-r--r--services/tests/servicestests/src/com/android/server/tv/tunerresourcemanager/TunerResourceManagerServiceTest.java120
-rw-r--r--services/tests/uiservicestests/src/com/android/server/notification/NotificationHistoryManagerTest.java96
-rwxr-xr-xservices/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java1
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/ActivityTestsBase.java14
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/AppWindowTokenTests.java45
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/InsetsPolicyTest.java9
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/RecentTasksTest.java32
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/RemoteAnimationControllerTest.java23
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/RunningTasksTest.java38
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/SizeCompatTests.java289
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/TaskOrganizerTests.java31
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/TaskPositionerTests.java38
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/TaskRecordTests.java10
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/TestDisplayContent.java26
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/WindowManagerServiceTests.java28
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/WindowTokenTests.java26
-rwxr-xr-xtelecomm/java/android/telecom/Connection.java2
-rw-r--r--telephony/java/android/telephony/AccessNetworkConstants.java280
-rwxr-xr-xtelephony/java/android/telephony/CarrierConfigManager.java3
-rw-r--r--telephony/java/android/telephony/CdmaEriInformation.java1
-rw-r--r--telephony/java/android/telephony/ImsManager.java17
-rw-r--r--telephony/java/android/telephony/ServiceState.java1
-rw-r--r--telephony/java/android/telephony/SmsManager.java2
-rw-r--r--telephony/java/android/telephony/SmsMessage.java20
-rw-r--r--telephony/java/android/telephony/TelephonyManager.java81
-rw-r--r--telephony/java/android/telephony/ims/ImsCallProfile.java12
-rw-r--r--telephony/java/android/telephony/ims/ImsCallSessionListener.java80
-rw-r--r--telephony/java/android/telephony/ims/ImsUtListener.java8
-rw-r--r--telephony/java/android/telephony/ims/ProvisioningManager.java26
-rw-r--r--telephony/java/android/telephony/ims/RcsUceAdapter.java8
-rw-r--r--telephony/java/com/android/ims/ImsConfig.java5
-rw-r--r--telephony/java/com/android/internal/telephony/ITelephony.aidl10
-rw-r--r--tests/BootImageProfileTest/src/com/android/bootimageprofile/BootImageProfileTest.java5
-rw-r--r--tests/Codegen/src/com/android/codegentest/HierrarchicalDataClassBase.java8
-rw-r--r--tests/Codegen/src/com/android/codegentest/HierrarchicalDataClassChild.java6
-rw-r--r--tests/Codegen/src/com/android/codegentest/ParcelAllTheThingsDataClass.java8
-rw-r--r--tests/Codegen/src/com/android/codegentest/SampleDataClass.java36
-rw-r--r--tests/Codegen/src/com/android/codegentest/SampleWithCustomBuilder.java6
-rw-r--r--tests/Codegen/src/com/android/codegentest/SampleWithNestedDataClasses.java18
-rw-r--r--tests/Codegen/src/com/android/codegentest/StaleDataclassDetectorFalsePositivesTest.java6
-rw-r--r--tests/PackageWatchdog/src/com/android/server/ExplicitHealthCheckServiceTest.java61
-rw-r--r--tests/PackageWatchdog/src/com/android/server/PackageWatchdogTest.java52
-rw-r--r--tests/RollbackTest/RollbackTest/src/com/android/tests/rollback/StagedRollbackTest.java8
-rw-r--r--tests/RollbackTest/StagedRollbackTest/src/com/android/tests/rollback/host/StagedRollbackTest.java6
-rw-r--r--tests/net/common/java/android/net/CaptivePortalTest.java8
-rw-r--r--tests/net/common/java/android/net/LinkAddressTest.java46
-rw-r--r--tests/net/common/java/android/net/LinkPropertiesTest.java21
-rw-r--r--tests/net/common/java/android/net/NetworkAgentConfigTest.kt9
-rw-r--r--tests/net/common/java/android/net/NetworkScoreTest.kt104
-rw-r--r--tests/net/java/com/android/server/ConnectivityServiceTest.java62
-rw-r--r--tests/net/java/com/android/server/connectivity/LingerMonitorTest.java5
-rw-r--r--tests/net/java/com/android/server/connectivity/NetworkNotificationManagerTest.java44
-rw-r--r--tools/codegen/src/com/android/codegen/ClassPrinter.kt2
-rw-r--r--tools/codegen/src/com/android/codegen/FieldInfo.kt14
-rw-r--r--tools/codegen/src/com/android/codegen/Generators.kt2
-rw-r--r--tools/codegen/src/com/android/codegen/ImportsProvider.kt1
-rw-r--r--tools/codegen/src/com/android/codegen/SharedConstants.kt2
-rw-r--r--tools/stats_log_api_gen/Android.bp2
-rw-r--r--tools/stats_log_api_gen/Collation.cpp48
-rw-r--r--tools/stats_log_api_gen/Collation.h3
-rw-r--r--tools/stats_log_api_gen/atoms_info_writer.cpp49
-rw-r--r--tools/stats_log_api_gen/atoms_info_writer.h2
-rw-r--r--tools/stats_log_api_gen/java_writer.cpp6
-rw-r--r--tools/stats_log_api_gen/java_writer_q.cpp64
-rw-r--r--tools/stats_log_api_gen/java_writer_q.h4
-rw-r--r--tools/stats_log_api_gen/main.cpp525
-rw-r--r--tools/stats_log_api_gen/native_writer.cpp22
-rw-r--r--tools/stats_log_api_gen/native_writer_q.cpp276
-rw-r--r--tools/stats_log_api_gen/native_writer_q.h49
-rw-r--r--tools/stats_log_api_gen/test.proto40
-rw-r--r--tools/stats_log_api_gen/test_collation.cpp25
-rw-r--r--tools/stats_log_api_gen/utils.cpp14
-rw-r--r--tools/stats_log_api_gen/utils.h2
-rw-r--r--wifi/java/android/net/wifi/EasyConnectStatusCallback.java2
-rw-r--r--wifi/java/android/net/wifi/IScoreUpdateObserver.aidl (renamed from wifi/java/android/net/wifi/IScoreChangeCallback.aidl)6
-rw-r--r--wifi/java/android/net/wifi/IWifiConnectedNetworkScorer.aidl8
-rw-r--r--wifi/java/android/net/wifi/ScanResult.java18
-rw-r--r--wifi/java/android/net/wifi/WifiAnnotations.java20
-rw-r--r--wifi/java/android/net/wifi/WifiConfiguration.java2
-rw-r--r--wifi/java/android/net/wifi/WifiInfo.java6
-rw-r--r--wifi/java/android/net/wifi/WifiManager.java77
-rw-r--r--wifi/java/android/net/wifi/nl80211/DeviceWiphyCapabilities.java19
-rw-r--r--wifi/tests/src/android/net/wifi/ScanResultTest.java2
-rw-r--r--wifi/tests/src/android/net/wifi/WifiConfigurationTest.java2
-rw-r--r--wifi/tests/src/android/net/wifi/WifiManagerTest.java19
958 files changed, 23407 insertions, 18378 deletions
diff --git a/Android.bp b/Android.bp
index 9152843b06ae..78d38c5c2537 100644
--- a/Android.bp
+++ b/Android.bp
@@ -271,7 +271,6 @@ filegroup {
// etc.
":framework-javastream-protos",
- ":framework-statslog-gen", // StatsLogInternal.java
":statslog-framework-java-gen", // FrameworkStatsLog.java
// telephony annotations
@@ -282,7 +281,6 @@ filegroup {
filegroup {
name: "framework-updatable-sources",
srcs: [
- ":framework-appsearch-sources",
":framework-sdkextensions-sources",
":framework-statsd-sources",
":framework-tethering-srcs",
@@ -468,7 +466,6 @@ java_library {
defaults: ["framework-defaults"],
srcs: [":framework-non-updatable-sources"],
libs: [
- "framework-appsearch-stubs",
"framework-sdkextensions-stubs-systemapi",
"framework-statsd-stubs-module_libs_api",
"framework-permission-stubs-systemapi",
@@ -494,7 +491,6 @@ java_library {
visibility: [
"//frameworks/base",
// TODO(b/147128803) remove the below lines
- "//frameworks/base/apex/appsearch/framework",
"//frameworks/base/apex/blobstore/framework",
"//frameworks/base/apex/jobscheduler/framework",
"//frameworks/base/packages/Tethering/tests/unit",
@@ -516,7 +512,6 @@ java_library {
installable: false, // this lib is a build-only library
static_libs: [
"framework-minus-apex",
- "framework-appsearch", // TODO(b/146218515): should be framework-appsearch-stubs
"framework-media-stubs-systemapi",
"framework-mediaprovider-stubs-systemapi",
"framework-permission-stubs-systemapi",
@@ -541,7 +536,6 @@ java_library {
"exoplayer2-extractor",
"android.hardware.wifi-V1.0-java-constants",
],
- libs: ["icing-java-proto-lite"],
apex_available: ["//apex_available:platform"],
visibility: [
// DO NOT ADD ANY MORE ENTRIES TO THIS LIST
@@ -562,7 +556,6 @@ java_library {
libs: [
"app-compat-annotations",
"ext",
- "icing-java-proto-lite",
"unsupportedappusage",
],
@@ -617,13 +610,6 @@ java_library {
}
genrule {
- name: "framework-statslog-gen",
- tools: ["stats-log-api-gen"],
- cmd: "$(location stats-log-api-gen) --java $(out) --worksource",
- out: ["android/util/StatsLogInternal.java"],
-}
-
-genrule {
name: "statslog-framework-java-gen",
tools: ["stats-log-api-gen"],
cmd: "$(location stats-log-api-gen) --java $(out) --module framework" +
@@ -715,6 +701,7 @@ filegroup {
"core/java/android/annotation/SystemApi.java",
"core/java/android/annotation/SystemService.java",
"core/java/android/annotation/TestApi.java",
+ "core/java/android/annotation/WorkerThread.java",
"core/java/com/android/internal/annotations/GuardedBy.java",
"core/java/com/android/internal/annotations/VisibleForTesting.java",
"core/java/com/android/internal/annotations/Immutable.java",
@@ -981,7 +968,6 @@ filegroup {
filegroup {
name: "incremental_manager_aidl",
srcs: [
- "core/java/android/os/incremental/IIncrementalManager.aidl",
"core/java/android/os/incremental/IIncrementalService.aidl",
"core/java/android/os/incremental/IncrementalNewFileParams.aidl",
"core/java/android/os/incremental/IncrementalSignature.aidl",
diff --git a/apex/appsearch/Android.bp b/apex/appsearch/Android.bp
deleted file mode 100644
index b014fdcb3df3..000000000000
--- a/apex/appsearch/Android.bp
+++ /dev/null
@@ -1,37 +0,0 @@
-// Copyright (C) 2019 The Android Open Source Project
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-apex {
- name: "com.android.appsearch",
- manifest: "apex_manifest.json",
- java_libs: [
- "framework-appsearch",
- "service-appsearch",
- ],
- key: "com.android.appsearch.key",
- certificate: ":com.android.appsearch.certificate",
-}
-
-apex_key {
- name: "com.android.appsearch.key",
- public_key: "com.android.appsearch.avbpubkey",
- private_key: "com.android.appsearch.pem",
-}
-
-android_app_certificate {
- name: "com.android.appsearch.certificate",
- // This will use com.android.appsearch.x509.pem (the cert) and
- // com.android.appsearch.pk8 (the private key)
- certificate: "com.android.appsearch",
-}
diff --git a/apex/appsearch/apex_manifest.json b/apex/appsearch/apex_manifest.json
deleted file mode 100644
index 39a2d38fa642..000000000000
--- a/apex/appsearch/apex_manifest.json
+++ /dev/null
@@ -1,4 +0,0 @@
-{
- "name": "com.android.appsearch",
- "version": 300000000
-}
diff --git a/apex/appsearch/com.android.appsearch.avbpubkey b/apex/appsearch/com.android.appsearch.avbpubkey
deleted file mode 100644
index 4e5acae9c1e4..000000000000
--- a/apex/appsearch/com.android.appsearch.avbpubkey
+++ /dev/null
Binary files differ
diff --git a/apex/appsearch/com.android.appsearch.pem b/apex/appsearch/com.android.appsearch.pem
deleted file mode 100644
index 4ed5945acc86..000000000000
--- a/apex/appsearch/com.android.appsearch.pem
+++ /dev/null
@@ -1,51 +0,0 @@
------BEGIN RSA PRIVATE KEY-----
-MIIJKQIBAAKCAgEAro9f/jvoIsj6ywuRmuUQS8UtprhohJitrovDMfm/T2R/WQvy
-AvUxgetyF4XvBPCDRqCsGxXCJMQOn1furrAeTmWbGHPhA0PI1Ys/qtfNMbh9THyn
-70I2c4X70CUQ+8/Y8BJ8CAB4iER/s9QtD28QLvM2BBUzRoKUSBGUYNMlYobjgRdK
-57V7yg48LkvUIg1fzIW3M5gCgOXa0u1xOadKX3m7tzCboHcXp5anfWX5PH1+okRu
-jzdI8OjtUq23qhoRw5Skz0Vbf4a+8t3kT3slF/Q7O8LoRPwpZsvIcvTyCGAqlra7
-2L2LN4H1p+u2ko3r/QmRbJn2eXW07elkyrggXMyn2rTxibQgk53wYfSavMyNd/E7
-+de/uJ60l2aPa+5KUaR8eYwchXEELdqQ+zRgSZ2711xCaY4glEj7DT6VlEEdr26x
-akX0ra7e2sVGv1um/dvSyVO5aFKKjVvo4LqhWKWO8yvDMxmDDTNatvWhY2Bhd3RA
-0hilYpWQFb9Tv5f4E0tZmfvlddgux7sw++Y/RIimBFoSyf5AezAUIFYYoYvEzytB
-muq1/ecNHr+Z2tZMxN88sJVhzRzD9tKUyXhvxOV2Lg9TIeVTWGwQqgSnHWtIe+1p
-cw8inPfYEhP4Q+3W/RlPvNdu75x8Nj2aG7bxZnhoQDRDw5ddgma27I+a8esCAwEA
-AQKCAgBsNh9I6HRAVBz8kCBkSEnw3rwtFTZdtJQ+lw+bRHpvShqT5g7R/JQDOSTS
-JkoE4uBOgT4P0E45Inz6FLW2/yDacqxR3UwJDRVMI/WFACCJCRhLuR8V+BLvTIjN
-AJ1lrPSL5rmS8E/IEcakgQyp+6ypnkXHBCl0NXCcuKEl4N7VFE+mb/0UZPHnUSnH
-fWR085uGmwH17u7mXxdnGKDPH8DALSPMLUrcj9dPIdqUpwl5kUZWa1uqVphWF98/
-GMe5oE2Q0+3TO+i7xplKz3lAOFPHZLTvmCUK1tMHkZ6ifOwpewwLwB30/5N1BpB1
-126nrWk0xKCtFUixBOHzdnLwJHKSbi7chQU5q39oAJoTfxdmAJlaG0zQHUQZ44MQ
-gemzSA7uJbtoAOAZVF1K14xbIpnfidqTB7N3RCmiJE+/Hpkq6PxgPfu5rqocPbPC
-t0FgJ4NXNmKOAuJllSlrrHATcUOhF4g5pX7tvOc8X4y7bvfwOmtw5ez3INKMF0q6
-/y0vVCi6N1Z7CTa9eY8feZ1PImk/Fkq4NInSPyx7ZE3pLYmsvuJjliFrWo9TRVae
-Dt5vvBKBOpAfhDiHkeXbX7Raj2B6c6adF4no/3SAVlAjIq1iBVjfQWyHAGUoEW1O
-u3LdHTIb6gSTLJ4AfryEKrOE+1VMlYt92GwX692KKXMaJjytSQKCAQEA3pYbl8HD
-Y++UyEN5VzWAQedT3//GDwpDfgdERe2E4smYrkVNJ2WAG2SqY1A35DIl8be3eHvl
-soaL38j48ailfDYY9tI+IlapNh+VOLej+HiOytaPlLhcv2FpSC2qZT4EiU6IBXLo
-+l6FrmD/VQXTjvoktzsDB/n1t4Dfa3Ogf+lLf1Jxr94YpEnDh18V5ofj78SplVLm
-NrzsHxAafE4Ni2a7dyWjcDYIuL7FTShT+0K4W45tRr+CGxThxu7LEe7zw4Z1IagU
-jJNtXjvDD/Zw4UTqI6RwWGZsu6UjPS6LHhOqnWqflWmFRIfMbDkuWvnGZTM9DkVg
-kk1+BNi1PECZXwKCAQEAyMOjbVo6XV3lFN0X8TpHyg/z9ar00/SE7WEJHqPSuzYT
-rSfU4vDDlaPAwkYvGi9ZKi9VM+R3CyBNxnK9Yq6NurHhhrYcAwdS/hGLT1K2o0Y8
-Pgv7gZCFb+SIwLBhlUG9otGULcBzLneqgVUqyMG6IoCjuC2LRyB71Xc2UMyg6n/f
-XpV2RTMb8f+26cgm6nj0SDAfgpr8HV6uNV80c6l1A8gq86nUWwiVAEUdmExSDe7J
-shsfWAj8RSErqDXf1BtEdPLJUSIPX5VXkzAXOXIkengwVno0vv0dBN8uraS8iQSG
-0JsJLLcw9b5kvnh6FEbE7POsIqKyCZV9VADwO6YW9QKCAQBYQsdwNqoGv6KMgozj
-8tgHyfWtVduwbQ50M+dznwpZbzz2pY5Bd/MDabhSpyVyfBwlrAa5ZM+hKc7fDu7/
-zDLKfR0LCjUPIrP4PS/LjK4dQZjFf6zxeOV2EedQcqMlgCEGXTh8iKMvXDm/+sBk
-c2n/QNs8OM8r44b2m8h78B6NefGw6/0ekn/M7V72F9M0VWAh3Cauim+09tbePmFy
-NvUR+MuPJEKZpSNyNltADCS49izqSSC1tAygNniMjHXDh6/rMS7TCLYVRARTIHlp
-o/wAp3X8aiEOPJcTFRlTElihtYSq5POgqHXqxbpek5H5CyALUvT76rCvcsDspQ3A
-dZEbAoIBAQCoLEmP5o8Rev/UdEgECB/uwWJIngYsLp3TAv/SrMRvkiL1X3JTD/+m
-L9/eXVBDjPoR/khPCcg2h77ex2qhaTrL8wnKAG6CkvYQYb3impTnPIRmLT9nDxrX
-2gY78wQrNUCXTRvlH1rcx90KLb+DH9S95ig+tdf/otRYwl27XU5GYQtJfcXuvZth
-IiWku8btjpiCh909WHpsV81yY+faI08j9d8U8WQzRYMbEMpzsyrhBO/rxBCDfDNl
-7R1W8JooYRb9KAs/bVqXZNBROW2a72RjOp6zMfdRLVHLrPC7AE32MNaFk/khfesD
-T5OwgdcxeP6oxo2hDcw5fwHXBlo2fTCpAoIBAQChgjv5AfQ50spqvHy6MNem4tV0
-L0IsxmNLsi8X2a6s4kStwUzOxDA8c/e54XabxQNZ0ERU1q+bgbG7PWC4twDMPR8i
-2DO6rgqSK4MjGOTgAoeDuy3mElFQmCLRs04Wf4jh8kPi217WFlYBynh2HmBKbh42
-JmIrLetbKEK13FXRvMkgZcX4OIDrT5TOvev4VZArU8PTRlWv3sqsKAVXjX0clGHf
-I0/2kSsr2qq1UY7JrYWZsZ9uqz2ZH0pF19a6O/Cq4uqTYoL+sYzFTSeFmChRjV1g
-ancTvTn9lcBqECDMgq5DE/p96Oxg/t8elalR6WDUlysafphVz3nTuyMTh7ka
------END RSA PRIVATE KEY-----
diff --git a/apex/appsearch/com.android.appsearch.pk8 b/apex/appsearch/com.android.appsearch.pk8
deleted file mode 100644
index 77e98b20877b..000000000000
--- a/apex/appsearch/com.android.appsearch.pk8
+++ /dev/null
Binary files differ
diff --git a/apex/appsearch/com.android.appsearch.x509.pem b/apex/appsearch/com.android.appsearch.x509.pem
deleted file mode 100644
index e37c4b9fcead..000000000000
--- a/apex/appsearch/com.android.appsearch.x509.pem
+++ /dev/null
@@ -1,35 +0,0 @@
------BEGIN CERTIFICATE-----
-MIIGETCCA/mgAwIBAgIUGl+MIvpEi0+TWzj0ieh6WtjXmP8wDQYJKoZIhvcNAQEL
-BQAwgZYxCzAJBgNVBAYTAlVTMRMwEQYDVQQIDApDYWxpZm9ybmlhMRYwFAYDVQQH
-DA1Nb3VudGFpbiBWaWV3MRAwDgYDVQQKDAdBbmRyb2lkMRAwDgYDVQQLDAdBbmRy
-b2lkMRIwEAYDVQQDDAlhcHBzZWFyY2gxIjAgBgkqhkiG9w0BCQEWE2FuZHJvaWRA
-YW5kcm9pZC5jb20wIBcNMTkxMTIwMjMxNTM1WhgPNDc1NzEwMTYyMzE1MzVaMIGW
-MQswCQYDVQQGEwJVUzETMBEGA1UECAwKQ2FsaWZvcm5pYTEWMBQGA1UEBwwNTW91
-bnRhaW4gVmlldzEQMA4GA1UECgwHQW5kcm9pZDEQMA4GA1UECwwHQW5kcm9pZDES
-MBAGA1UEAwwJYXBwc2VhcmNoMSIwIAYJKoZIhvcNAQkBFhNhbmRyb2lkQGFuZHJv
-aWQuY29tMIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEAsyPlp3q3P9Xg
-W1WhIwQiF9em9oqaGQ/3dbIxickAy591qcRbpHb4lDTZusRECfqlV215mV+lv5x4
-EhOnId3uPKBAJ/YDtL7zUW6TWL7to7zEnUqSIKTcoQzNF2EiCeGuRhrtgYvAD3HQ
-dwr4xrbSADbDArF04A49voLpsmq1fyNgl86VISiMRqoSLJnA6eghlduuOt+nf252
-6WgxDs/JrO/eK70q0+RwmWzVJ/tVr+36a65N4EHhfL4t2hdV0k0XFob7hBn7XWzC
-QrSR3jCvE3yAfAr3tq5c19/WWBA7V45nEHzXyAvBUHWubYvDi+vm/yzqU2rQwScC
-bzp4zK4CnhBHqb4gHoy0+kfFIwJ1A3GT2pl3ba/NsIYgliMtPQfkDV5PE5RTNcwH
-21ewH7vm2+spQv5Z/2TEV2lEHlp2vuAliyn2AT4u1ginr6vtBRFLmpPeziFcfB0y
-7h04GctZpX8odz+XI7aMDe47RNu9XyJX0vulntxmlDF76k8Z9DIXg02hY+yc/i7+
-2ztnj1eXL51p+HyhK5VbvJWbKkVaMQijlbuIMYNzMA6L0WHWRc2Cux9UDODMGoiC
-w09JpqudCS/95I/F1xaWJ/Kh3vKeQshHAz0hrL7v7wpjmfeXf6NGsWJGy+giCwZj
-ABtn9nFQoesgi7M1LeazD5Q/4v4AMaUCAwEAAaNTMFEwHQYDVR0OBBYEFJpHCy2Y
-3qaL6cLpE9fe53L61KEEMB8GA1UdIwQYMBaAFJpHCy2Y3qaL6cLpE9fe53L61KEE
-MA8GA1UdEwEB/wQFMAMBAf8wDQYJKoZIhvcNAQELBQADggIBAGDYAcOhbOYcDB2K
-WDZka+FCORFFvz4nLQGE7Z9TAn1g7XusM2KbXlb2drIN6CWOFlnKQrUsNsAHrc+s
-tl+A1vC3/NfYKKBVuizPx/kHUgz3k/UIJzbzEu/uCJd86idcJoUTqC/qEJAeeQqM
-XpsNP1Yg7oyzZT8sFlUAKeDeXJ7fIDXR6nduUQ6uJXkee/5JF3VedHdgHAUsC19/
-KHhyVU3MLDUNBdAmM79+DsdVYi2Pw31jojMu95Zz1MYTRBcgQAiEw5nncr38k6ac
-Gy+JffgJR68FzI4QLBSxnDRFD2zXJ09lpP6Sjb1FVcDzk7Bi/EQDLBkrkbeLsk5F
-a0xz9VoJ3kM7Cc4R9MXN4ZWuePjdJwgasnHmllsXn45R9odgJgmfzuUwtgNw/XKQ
-QcQl7Q9QUrBCqIoHijxscUZCBSmIHVNBBDckRAmSXHeWMRlO3uBR4IA/Jfrt//4f
-uc7CNUp+LQ6EzBXJOVFrXRtau6Oj+jM1+fzxKo1uV2+T+GdVEE5jeF/6nB3qna6h
-2NmyLqbqeqp2QxgzBWSGy8Ugs6zg4wItJBqOoRLKKFxTJu5OAzJ4fUA+g7WFXNhR
-kG56SJ863LZoORKHWE72oXYeIW98Tq0qKLH3NzH5L4tfX8DeBTq+APezHetH1ljA
-D0avPy62g0i643bbpwZgezBgRIKL
------END CERTIFICATE-----
diff --git a/apex/appsearch/framework/Android.bp b/apex/appsearch/framework/Android.bp
deleted file mode 100644
index 24309d7c4e0d..000000000000
--- a/apex/appsearch/framework/Android.bp
+++ /dev/null
@@ -1,83 +0,0 @@
-// Copyright (C) 2019 The Android Open Source Project
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-filegroup {
- name: "framework-appsearch-sources",
- srcs: [
- "java/**/*.java",
- "java/**/*.aidl",
- ],
- path: "java",
-}
-
-java_library {
- name: "framework-appsearch",
- installable: true,
- sdk_version: "core_platform", // TODO(b/146218515) should be core_current
- srcs: [":framework-appsearch-sources"],
- hostdex: true, // for hiddenapi check
- libs: [
- "framework-minus-apex", // TODO(b/146218515) should be framework-system-stubs
- ],
- static_libs: ["icing-java-proto-lite"],
- visibility: [
- // TODO(b/146218515) remove this when framework is built with the stub of appsearch
- "//frameworks/base",
- "//frameworks/base/apex/appsearch:__subpackages__",
- ],
- permitted_packages: ["android.app.appsearch"],
- apex_available: ["com.android.appsearch"],
-}
-
-metalava_appsearch_docs_args =
- "--hide-package com.android.server " +
- "--error UnhiddenSystemApi " +
- "--hide RequiresPermission " +
- "--hide MissingPermission " +
- "--hide BroadcastBehavior " +
- "--hide HiddenSuperclass " +
- "--hide DeprecationMismatch " +
- "--hide UnavailableSymbol " +
- "--hide SdkConstant " +
- "--hide HiddenTypeParameter " +
- "--hide Todo --hide Typo " +
- "--hide HiddenTypedefConstant " +
- "--show-annotation android.annotation.SystemApi "
-
-droidstubs {
- name: "framework-appsearch-stubs-srcs",
- srcs: [
- ":framework-annotations",
- ":framework-appsearch-sources",
- ],
- aidl: {
- include_dirs: ["frameworks/base/core/java"],
- },
- args: metalava_appsearch_docs_args,
- sdk_version: "core_current",
- libs: ["android_system_stubs_current"],
-}
-
-java_library {
- name: "framework-appsearch-stubs",
- srcs: [":framework-appsearch-stubs-srcs"],
- aidl: {
- export_include_dirs: [
- "java",
- ],
- },
- sdk_version: "core_current",
- libs: ["android_system_stubs_current"],
- installable: false,
-}
diff --git a/apex/appsearch/framework/java/android/app/TEST_MAPPING b/apex/appsearch/framework/java/android/app/TEST_MAPPING
deleted file mode 100644
index 12188f83a29f..000000000000
--- a/apex/appsearch/framework/java/android/app/TEST_MAPPING
+++ /dev/null
@@ -1,7 +0,0 @@
-{
- "imports": [
- {
- "path": "frameworks/base/apex/appsearch/service/java/com/android/server/appsearch"
- }
- ]
-}
diff --git a/apex/appsearch/framework/java/android/app/appsearch/AppSearchBatchResult.java b/apex/appsearch/framework/java/android/app/appsearch/AppSearchBatchResult.java
deleted file mode 100644
index 773db9346625..000000000000
--- a/apex/appsearch/framework/java/android/app/appsearch/AppSearchBatchResult.java
+++ /dev/null
@@ -1,150 +0,0 @@
-/*
- * Copyright (C) 2020 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.app.appsearch;
-
-import android.annotation.NonNull;
-import android.annotation.Nullable;
-import android.os.Parcel;
-import android.os.Parcelable;
-import android.util.ArrayMap;
-
-import java.util.Collections;
-import java.util.Map;
-
-/**
- * Provides access to multiple results from a batch operation accepting multiple inputs.
- *
- * @param <KeyType> The type of the keys for {@link #getResults} and {@link #getFailures}.
- * @param <ValueType> The type of result objects associated with the keys.
- * @hide
- */
-public class AppSearchBatchResult<KeyType, ValueType> implements Parcelable {
- @NonNull private final Map<KeyType, ValueType> mResults;
- @NonNull private final Map<KeyType, Throwable> mFailures;
-
- private AppSearchBatchResult(
- @NonNull Map<KeyType, ValueType> results, @NonNull Map<KeyType, Throwable> failures) {
- mResults = results;
- mFailures = failures;
- }
-
- private AppSearchBatchResult(@NonNull Parcel in) {
- mResults = Collections.unmodifiableMap(in.readHashMap(/*loader=*/ null));
- mFailures = Collections.unmodifiableMap(in.readHashMap(/*loader=*/ null));
- }
-
- @Override
- public void writeToParcel(@NonNull Parcel dest, int flags) {
- dest.writeMap(mResults);
- dest.writeMap(mFailures);
- }
-
- /** Returns {@code true} if this {@link AppSearchBatchResult} has no failures. */
- public boolean isSuccess() {
- return mFailures.isEmpty();
- }
-
- /**
- * Returns a {@link Map} of all successful keys mapped to the results they produced.
- *
- * <p>The values of the {@link Map} may be {@code null}.
- */
- @NonNull
- public Map<KeyType, ValueType> getResults() {
- return mResults;
- }
-
- /**
- * Returns a {@link Map} of all failed keys mapped to a {@link Throwable} representing the cause
- * of failure.
- *
- * <p>The values of the {@link Map} may be {@code null}.
- */
- @NonNull
- public Map<KeyType, Throwable> getFailures() {
- return mFailures;
- }
-
- @Override
- public int describeContents() {
- return 0;
- }
-
- public static final Creator<AppSearchBatchResult> CREATOR =
- new Creator<AppSearchBatchResult>() {
- @NonNull
- @Override
- public AppSearchBatchResult createFromParcel(@NonNull Parcel in) {
- return new AppSearchBatchResult(in);
- }
-
- @NonNull
- @Override
- public AppSearchBatchResult[] newArray(int size) {
- return new AppSearchBatchResult[size];
- }
- };
-
- /**
- * Creates a new {@link Builder} for this {@link AppSearchBatchResult}.
- * @hide
- */
- @NonNull
- public static <KeyType, ValueType> Builder<KeyType, ValueType> newBuilder() {
- return new Builder<>();
- }
-
- /**
- * Builder for {@link AppSearchBatchResult} objects.
- *
- * @param <KeyType> The type of keys.
- * @param <ValueType> The type of result objects associated with the keys.
- * @hide
- */
- public static final class Builder<KeyType, ValueType> {
- @NonNull private final Map<KeyType, ValueType> mResults = new ArrayMap<>();
- @NonNull private final Map<KeyType, Throwable> mFailures = new ArrayMap<>();
-
- private Builder() {}
-
- /**
- * Registers that the {@code key} was processed successfully and associates it with
- * {@code value}. Any previous mapping for a key, whether success or failure, is deleted.
- */
- public Builder setSuccess(@NonNull KeyType key, @Nullable ValueType value) {
- mResults.put(key, value);
- mFailures.remove(key);
- return this;
- }
-
- /**
- * Registers that the {@code key} failed and associates it with {@code throwable}. Any
- * previous mapping for a key, whether success or failure, is deleted.
- */
- public Builder setFailure(@NonNull KeyType key, @Nullable Throwable throwable) {
- mFailures.put(key, throwable);
- mResults.remove(key);
- return this;
- }
-
- /** Builds an {@link AppSearchBatchResult} from the contents of this {@link Builder}. */
- @NonNull
- public AppSearchBatchResult<KeyType, ValueType> build() {
- return new AppSearchBatchResult<>(mResults, mFailures);
- }
- }
-}
diff --git a/apex/appsearch/framework/java/android/app/appsearch/AppSearchDocument.java b/apex/appsearch/framework/java/android/app/appsearch/AppSearchDocument.java
deleted file mode 100644
index ff0f0dda55b9..000000000000
--- a/apex/appsearch/framework/java/android/app/appsearch/AppSearchDocument.java
+++ /dev/null
@@ -1,724 +0,0 @@
-/*
- * Copyright (C) 2020 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.app.appsearch;
-
-import android.annotation.CurrentTimeMillisLong;
-import android.annotation.DurationMillisLong;
-import android.annotation.IntRange;
-import android.annotation.NonNull;
-import android.annotation.Nullable;
-import android.util.ArrayMap;
-import android.util.Log;
-
-import com.android.internal.annotations.VisibleForTesting;
-import com.android.internal.util.ArrayUtils;
-import com.android.internal.util.Preconditions;
-
-import com.google.android.icing.proto.DocumentProto;
-import com.google.android.icing.proto.PropertyProto;
-import com.google.android.icing.protobuf.ByteString;
-
-import java.util.ArrayList;
-import java.util.Collections;
-import java.util.List;
-import java.util.Map;
-import java.util.Objects;
-
-/**
- * Represents a document unit.
- *
- * <p>Documents are constructed via {@link AppSearchDocument.Builder}.
- * @hide
- */
-public class AppSearchDocument {
- private static final String TAG = "AppSearchDocument";
-
- /**
- * The maximum number of elements in a repeatable field. Will reject the request if exceed
- * this limit.
- */
- private static final int MAX_REPEATED_PROPERTY_LENGTH = 100;
-
- /**
- * The maximum {@link String#length} of a {@link String} field. Will reject the request if
- * {@link String}s longer than this.
- */
- private static final int MAX_STRING_LENGTH = 20_000;
-
- /**
- * Contains {@link AppSearchDocument} basic information (uri, schemaType etc) and properties
- * ordered by keys.
- */
- @NonNull
- private final DocumentProto mProto;
-
- /** Contains all properties in {@link #mProto} to support getting properties via keys. */
- @NonNull
- private final Map<String, Object> mProperties;
-
- /**
- * Create a new {@link AppSearchDocument}.
- * @param proto Contains {@link AppSearchDocument} basic information (uri, schemaType etc) and
- * properties ordered by keys.
- * @param propertiesMap Contains all properties in {@link #mProto} to support get properties
- * via keys.
- */
- private AppSearchDocument(@NonNull DocumentProto proto,
- @NonNull Map<String, Object> propertiesMap) {
- mProto = proto;
- mProperties = propertiesMap;
- }
-
- /**
- * Create a new {@link AppSearchDocument} from an existing instance.
- *
- * <p>This method should be only used by constructor of a subclass.
- */
- protected AppSearchDocument(@NonNull AppSearchDocument document) {
- this(document.mProto, document.mProperties);
- }
-
- /** @hide */
- AppSearchDocument(@NonNull DocumentProto documentProto) {
- this(documentProto, new ArrayMap<>());
- for (int i = 0; i < documentProto.getPropertiesCount(); i++) {
- PropertyProto property = documentProto.getProperties(i);
- String name = property.getName();
- if (property.getStringValuesCount() > 0) {
- String[] values = new String[property.getStringValuesCount()];
- for (int j = 0; j < values.length; j++) {
- values[j] = property.getStringValues(j);
- }
- mProperties.put(name, values);
- } else if (property.getInt64ValuesCount() > 0) {
- long[] values = new long[property.getInt64ValuesCount()];
- for (int j = 0; j < values.length; j++) {
- values[j] = property.getInt64Values(j);
- }
- mProperties.put(property.getName(), values);
- } else if (property.getDoubleValuesCount() > 0) {
- double[] values = new double[property.getDoubleValuesCount()];
- for (int j = 0; j < values.length; j++) {
- values[j] = property.getDoubleValues(j);
- }
- mProperties.put(property.getName(), values);
- } else if (property.getBooleanValuesCount() > 0) {
- boolean[] values = new boolean[property.getBooleanValuesCount()];
- for (int j = 0; j < values.length; j++) {
- values[j] = property.getBooleanValues(j);
- }
- mProperties.put(property.getName(), values);
- } else if (property.getBytesValuesCount() > 0) {
- byte[][] values = new byte[property.getBytesValuesCount()][];
- for (int j = 0; j < values.length; j++) {
- values[j] = property.getBytesValues(j).toByteArray();
- }
- mProperties.put(name, values);
- } else if (property.getDocumentValuesCount() > 0) {
- AppSearchDocument[] values =
- new AppSearchDocument[property.getDocumentValuesCount()];
- for (int j = 0; j < values.length; j++) {
- values[j] = new AppSearchDocument(property.getDocumentValues(j));
- }
- mProperties.put(name, values);
- } else {
- throw new IllegalStateException("Unknown type of value: " + name);
- }
- }
- }
-
- /**
- * Get the {@link DocumentProto} of the {@link AppSearchDocument}.
- *
- * <p>The {@link DocumentProto} contains {@link AppSearchDocument}'s basic information and all
- * properties ordered by keys.
- * @hide
- */
- @NonNull
- @VisibleForTesting
- public DocumentProto getProto() {
- return mProto;
- }
-
- /**
- * Get the uri of the {@link AppSearchDocument}.
- *
- * @hide
- */
- @NonNull
- public String getUri() {
- return mProto.getUri();
- }
-
- /**
- * Get the schema type of the {@link AppSearchDocument}.
- * @hide
- */
- @NonNull
- public String getSchemaType() {
- return mProto.getSchema();
- }
-
- /**
- * Get the creation timestamp in milliseconds of the {@link AppSearchDocument}. Value will be in
- * the {@link System#currentTimeMillis()} time base.
- *
- * @hide
- */
- @CurrentTimeMillisLong
- public long getCreationTimestampMillis() {
- return mProto.getCreationTimestampMs();
- }
-
- /**
- * Returns the TTL (Time To Live) of the {@link AppSearchDocument}, in milliseconds.
- *
- * <p>The default value is 0, which means the document is permanent and won't be auto-deleted
- * until the app is uninstalled.
- *
- * @hide
- */
- @DurationMillisLong
- public long getTtlMillis() {
- return mProto.getTtlMs();
- }
-
- /**
- * Returns the score of the {@link AppSearchDocument}.
- *
- * <p>The score is a query-independent measure of the document's quality, relative to other
- * {@link AppSearchDocument}s of the same type.
- *
- * <p>The default value is 0.
- *
- * @hide
- */
- public int getScore() {
- return mProto.getScore();
- }
-
- /**
- * Retrieve a {@link String} value by key.
- *
- * @param key The key to look for.
- * @return The first {@link String} associated with the given key or {@code null} if there
- * is no such key or the value is of a different type.
- * @hide
- */
- @Nullable
- public String getPropertyString(@NonNull String key) {
- String[] propertyArray = getPropertyStringArray(key);
- if (ArrayUtils.isEmpty(propertyArray)) {
- return null;
- }
- warnIfSinglePropertyTooLong("String", key, propertyArray.length);
- return propertyArray[0];
- }
-
- /**
- * Retrieve a {@link Long} value by key.
- *
- * @param key The key to look for.
- * @return The first {@link Long} associated with the given key or {@code null} if there
- * is no such key or the value is of a different type.
- * @hide
- */
- @Nullable
- public Long getPropertyLong(@NonNull String key) {
- long[] propertyArray = getPropertyLongArray(key);
- if (ArrayUtils.isEmpty(propertyArray)) {
- return null;
- }
- warnIfSinglePropertyTooLong("Long", key, propertyArray.length);
- return propertyArray[0];
- }
-
- /**
- * Retrieve a {@link Double} value by key.
- *
- * @param key The key to look for.
- * @return The first {@link Double} associated with the given key or {@code null} if there
- * is no such key or the value is of a different type.
- * @hide
- */
- @Nullable
- public Double getPropertyDouble(@NonNull String key) {
- double[] propertyArray = getPropertyDoubleArray(key);
- // TODO(tytytyww): Add support double array to ArraysUtils.isEmpty().
- if (propertyArray == null || propertyArray.length == 0) {
- return null;
- }
- warnIfSinglePropertyTooLong("Double", key, propertyArray.length);
- return propertyArray[0];
- }
-
- /**
- * Retrieve a {@link Boolean} value by key.
- *
- * @param key The key to look for.
- * @return The first {@link Boolean} associated with the given key or {@code null} if there
- * is no such key or the value is of a different type.
- * @hide
- */
- @Nullable
- public Boolean getPropertyBoolean(@NonNull String key) {
- boolean[] propertyArray = getPropertyBooleanArray(key);
- if (ArrayUtils.isEmpty(propertyArray)) {
- return null;
- }
- warnIfSinglePropertyTooLong("Boolean", key, propertyArray.length);
- return propertyArray[0];
- }
-
- /**
- * Retrieve a {@code byte[]} value by key.
- *
- * @param key The key to look for.
- * @return The first {@code byte[]} associated with the given key or {@code null} if there
- * is no such key or the value is of a different type.
- */
- @Nullable
- public byte[] getPropertyBytes(@NonNull String key) {
- byte[][] propertyArray = getPropertyBytesArray(key);
- if (ArrayUtils.isEmpty(propertyArray)) {
- return null;
- }
- warnIfSinglePropertyTooLong("ByteArray", key, propertyArray.length);
- return propertyArray[0];
- }
-
- /**
- * Retrieve a {@link AppSearchDocument} value by key.
- *
- * @param key The key to look for.
- * @return The first {@link AppSearchDocument} associated with the given key or {@code null} if
- * there is no such key or the value is of a different type.
- */
- @Nullable
- public AppSearchDocument getPropertyDocument(@NonNull String key) {
- AppSearchDocument[] propertyArray = getPropertyDocumentArray(key);
- if (ArrayUtils.isEmpty(propertyArray)) {
- return null;
- }
- warnIfSinglePropertyTooLong("Document", key, propertyArray.length);
- return propertyArray[0];
- }
-
- /** Prints a warning to logcat if the given propertyLength is greater than 1. */
- private static void warnIfSinglePropertyTooLong(
- @NonNull String propertyType, @NonNull String key, int propertyLength) {
- if (propertyLength > 1) {
- Log.w(TAG, "The value for \"" + key + "\" contains " + propertyLength
- + " elements. Only the first one will be returned from "
- + "getProperty" + propertyType + "(). Try getProperty" + propertyType
- + "Array().");
- }
- }
-
- /**
- * Retrieve a repeated {@code String} property by key.
- *
- * @param key The key to look for.
- * @return The {@code String[]} associated with the given key, or {@code null} if no value
- * is set or the value is of a different type.
- * @hide
- */
- @Nullable
- public String[] getPropertyStringArray(@NonNull String key) {
- return getAndCastPropertyArray(key, String[].class);
- }
-
- /**
- * Retrieve a repeated {@code long} property by key.
- *
- * @param key The key to look for.
- * @return The {@code long[]} associated with the given key, or {@code null} if no value is
- * set or the value is of a different type.
- * @hide
- */
- @Nullable
- public long[] getPropertyLongArray(@NonNull String key) {
- return getAndCastPropertyArray(key, long[].class);
- }
-
- /**
- * Retrieve a repeated {@code double} property by key.
- *
- * @param key The key to look for.
- * @return The {@code double[]} associated with the given key, or {@code null} if no value
- * is set or the value is of a different type.
- * @hide
- */
- @Nullable
- public double[] getPropertyDoubleArray(@NonNull String key) {
- return getAndCastPropertyArray(key, double[].class);
- }
-
- /**
- * Retrieve a repeated {@code boolean} property by key.
- *
- * @param key The key to look for.
- * @return The {@code boolean[]} associated with the given key, or {@code null} if no value
- * is set or the value is of a different type.
- * @hide
- */
- @Nullable
- public boolean[] getPropertyBooleanArray(@NonNull String key) {
- return getAndCastPropertyArray(key, boolean[].class);
- }
-
- /**
- * Retrieve a {@code byte[][]} property by key.
- *
- * @param key The key to look for.
- * @return The {@code byte[][]} associated with the given key, or {@code null} if no value
- * is set or the value is of a different type.
- */
- @Nullable
- public byte[][] getPropertyBytesArray(@NonNull String key) {
- return getAndCastPropertyArray(key, byte[][].class);
- }
-
- /**
- * Retrieve a repeated {@link AppSearchDocument} property by key.
- *
- * @param key The key to look for.
- * @return The {@link AppSearchDocument[]} associated with the given key, or {@code null} if no
- * value is set or the value is of a different type.
- */
- @Nullable
- public AppSearchDocument[] getPropertyDocumentArray(@NonNull String key) {
- return getAndCastPropertyArray(key, AppSearchDocument[].class);
- }
-
- /**
- * Gets a repeated property of the given key, and casts it to the given class type, which
- * must be an array class type.
- */
- @Nullable
- private <T> T getAndCastPropertyArray(@NonNull String key, @NonNull Class<T> tClass) {
- Object value = mProperties.get(key);
- if (value == null) {
- return null;
- }
- try {
- return tClass.cast(value);
- } catch (ClassCastException e) {
- Log.w(TAG, "Error casting to requested type for key \"" + key + "\"", e);
- return null;
- }
- }
-
- @Override
- public boolean equals(@Nullable Object other) {
- // Check only proto's equality is sufficient here since all properties in
- // mProperties are ordered by keys and stored in proto.
- if (this == other) {
- return true;
- }
- if (!(other instanceof AppSearchDocument)) {
- return false;
- }
- AppSearchDocument otherDocument = (AppSearchDocument) other;
- return this.mProto.equals(otherDocument.mProto);
- }
-
- @Override
- public int hashCode() {
- // Hash only proto is sufficient here since all properties in mProperties are ordered by
- // keys and stored in proto.
- return mProto.hashCode();
- }
-
- @Override
- public String toString() {
- return mProto.toString();
- }
-
- /**
- * The builder class for {@link AppSearchDocument}.
- *
- * @param <BuilderType> Type of subclass who extend this.
- * @hide
- */
- public static class Builder<BuilderType extends Builder> {
-
- private final Map<String, Object> mProperties = new ArrayMap<>();
- private final DocumentProto.Builder mProtoBuilder = DocumentProto.newBuilder();
- private final BuilderType mBuilderTypeInstance;
-
- /**
- * Create a new {@link AppSearchDocument.Builder}.
- *
- * @param uri The uri of {@link AppSearchDocument}.
- * @param schemaType The schema type of the {@link AppSearchDocument}. The passed-in
- * {@code schemaType} must be defined using {@link AppSearchManager#setSchema} prior
- * to inserting a document of this {@code schemaType} into the AppSearch index using
- * {@link AppSearchManager#putDocuments(List)}. Otherwise, the document will be
- * rejected by {@link AppSearchManager#putDocuments(List)}.
- * @hide
- */
- public Builder(@NonNull String uri, @NonNull String schemaType) {
- mBuilderTypeInstance = (BuilderType) this;
- mProtoBuilder.setUri(uri).setSchema(schemaType);
- // Set current timestamp for creation timestamp by default.
- setCreationTimestampMillis(System.currentTimeMillis());
- }
-
- /**
- * Sets the score of the {@link AppSearchDocument}.
- *
- * <p>The score is a query-independent measure of the document's quality, relative to
- * other {@link AppSearchDocument}s of the same type.
- *
- * @throws IllegalArgumentException If the provided value is negative.
- * @hide
- */
- @NonNull
- public BuilderType setScore(@IntRange(from = 0, to = Integer.MAX_VALUE) int score) {
- if (score < 0) {
- throw new IllegalArgumentException("Document score cannot be negative.");
- }
- mProtoBuilder.setScore(score);
- return mBuilderTypeInstance;
- }
-
- /**
- * Set the creation timestamp in milliseconds of the {@link AppSearchDocument}. Should be
- * set using a value obtained from the {@link System#currentTimeMillis()} time base.
- *
- * @hide
- */
- @NonNull
- public BuilderType setCreationTimestampMillis(
- @CurrentTimeMillisLong long creationTimestampMillis) {
- mProtoBuilder.setCreationTimestampMs(creationTimestampMillis);
- return mBuilderTypeInstance;
- }
-
- /**
- * Set the TTL (Time To Live) of the {@link AppSearchDocument}, in milliseconds.
- *
- * <p>After this many milliseconds since the {@link #setCreationTimestampMillis(long)}
- * creation timestamp}, the document is deleted.
- *
- * @param ttlMillis A non-negative duration in milliseconds.
- * @throws IllegalArgumentException If the provided value is negative.
- */
- @NonNull
- public BuilderType setTtlMillis(@DurationMillisLong long ttlMillis) {
- Preconditions.checkArgumentNonNegative(
- ttlMillis, "Document ttlMillis cannot be negative.");
- mProtoBuilder.setTtlMs(ttlMillis);
- return mBuilderTypeInstance;
- }
-
- /**
- * Sets one or multiple {@code String} values for a property, replacing its previous
- * values.
- *
- * @param key The key associated with the {@code values}.
- * @param values The {@code String} values of the property.
- * @hide
- */
- @NonNull
- public BuilderType setProperty(@NonNull String key, @NonNull String... values) {
- putInPropertyMap(key, values);
- return mBuilderTypeInstance;
- }
-
- /**
- * Sets one or multiple {@code boolean} values for a property, replacing its previous
- * values.
- *
- * @param key The key associated with the {@code values}.
- * @param values The {@code boolean} values of the property.
- */
- @NonNull
- public BuilderType setProperty(@NonNull String key, @NonNull boolean... values) {
- putInPropertyMap(key, values);
- return mBuilderTypeInstance;
- }
-
- /**
- * Sets one or multiple {@code long} values for a property, replacing its previous
- * values.
- *
- * @param key The key associated with the {@code values}.
- * @param values The {@code long} values of the property.
- */
- @NonNull
- public BuilderType setProperty(@NonNull String key, @NonNull long... values) {
- putInPropertyMap(key, values);
- return mBuilderTypeInstance;
- }
-
- /**
- * Sets one or multiple {@code double} values for a property, replacing its previous
- * values.
- *
- * @param key The key associated with the {@code values}.
- * @param values The {@code double} values of the property.
- */
- @NonNull
- public BuilderType setProperty(@NonNull String key, @NonNull double... values) {
- putInPropertyMap(key, values);
- return mBuilderTypeInstance;
- }
-
- /**
- * Sets one or multiple {@code byte[]} for a property, replacing its previous values.
- *
- * @param key The key associated with the {@code values}.
- * @param values The {@code byte[]} of the property.
- */
- @NonNull
- public BuilderType setProperty(@NonNull String key, @NonNull byte[]... values) {
- putInPropertyMap(key, values);
- return mBuilderTypeInstance;
- }
-
- /**
- * Sets one or multiple {@link AppSearchDocument} values for a property, replacing its
- * previous values.
- *
- * @param key The key associated with the {@code values}.
- * @param values The {@link AppSearchDocument} values of the property.
- */
- @NonNull
- public BuilderType setProperty(@NonNull String key, @NonNull AppSearchDocument... values) {
- putInPropertyMap(key, values);
- return mBuilderTypeInstance;
- }
-
- private void putInPropertyMap(@NonNull String key, @NonNull String[] values)
- throws IllegalArgumentException {
- Objects.requireNonNull(key);
- Objects.requireNonNull(values);
- validateRepeatedPropertyLength(key, values.length);
- for (int i = 0; i < values.length; i++) {
- if (values[i] == null) {
- throw new IllegalArgumentException("The String at " + i + " is null.");
- } else if (values[i].length() > MAX_STRING_LENGTH) {
- throw new IllegalArgumentException("The String at " + i + " length is: "
- + values[i].length() + ", which exceeds length limit: "
- + MAX_STRING_LENGTH + ".");
- }
- }
- mProperties.put(key, values);
- }
-
- private void putInPropertyMap(@NonNull String key, @NonNull boolean[] values) {
- Objects.requireNonNull(key);
- Objects.requireNonNull(values);
- validateRepeatedPropertyLength(key, values.length);
- mProperties.put(key, values);
- }
-
- private void putInPropertyMap(@NonNull String key, @NonNull double[] values) {
- Objects.requireNonNull(key);
- Objects.requireNonNull(values);
- validateRepeatedPropertyLength(key, values.length);
- mProperties.put(key, values);
- }
-
- private void putInPropertyMap(@NonNull String key, @NonNull long[] values) {
- Objects.requireNonNull(key);
- Objects.requireNonNull(values);
- validateRepeatedPropertyLength(key, values.length);
- mProperties.put(key, values);
- }
-
- private void putInPropertyMap(@NonNull String key, @NonNull byte[][] values) {
- Objects.requireNonNull(key);
- Objects.requireNonNull(values);
- validateRepeatedPropertyLength(key, values.length);
- mProperties.put(key, values);
- }
-
- private void putInPropertyMap(@NonNull String key, @NonNull AppSearchDocument[] values) {
- Objects.requireNonNull(key);
- Objects.requireNonNull(values);
- for (int i = 0; i < values.length; i++) {
- if (values[i] == null) {
- throw new IllegalArgumentException("The document at " + i + " is null.");
- }
- }
- validateRepeatedPropertyLength(key, values.length);
- mProperties.put(key, values);
- }
-
- private static void validateRepeatedPropertyLength(@NonNull String key, int length) {
- if (length == 0) {
- throw new IllegalArgumentException("The input array is empty.");
- } else if (length > MAX_REPEATED_PROPERTY_LENGTH) {
- throw new IllegalArgumentException(
- "Repeated property \"" + key + "\" has length " + length
- + ", which exceeds the limit of "
- + MAX_REPEATED_PROPERTY_LENGTH);
- }
- }
-
- /**
- * Builds the {@link AppSearchDocument} object.
- * @hide
- */
- public AppSearchDocument build() {
- // Build proto by sorting the keys in mProperties to exclude the influence of
- // order. Therefore documents will generate same proto as long as the contents are
- // same. Note that the order of repeated fields is still preserved.
- ArrayList<String> keys = new ArrayList<>(mProperties.keySet());
- Collections.sort(keys);
- for (int i = 0; i < keys.size(); i++) {
- String name = keys.get(i);
- Object values = mProperties.get(name);
- PropertyProto.Builder propertyProto = PropertyProto.newBuilder().setName(name);
- if (values instanceof boolean[]) {
- for (boolean value : (boolean[]) values) {
- propertyProto.addBooleanValues(value);
- }
- } else if (values instanceof long[]) {
- for (long value : (long[]) values) {
- propertyProto.addInt64Values(value);
- }
- } else if (values instanceof double[]) {
- for (double value : (double[]) values) {
- propertyProto.addDoubleValues(value);
- }
- } else if (values instanceof String[]) {
- for (String value : (String[]) values) {
- propertyProto.addStringValues(value);
- }
- } else if (values instanceof AppSearchDocument[]) {
- for (AppSearchDocument value : (AppSearchDocument[]) values) {
- propertyProto.addDocumentValues(value.getProto());
- }
- } else if (values instanceof byte[][]) {
- for (byte[] value : (byte[][]) values) {
- propertyProto.addBytesValues(ByteString.copyFrom(value));
- }
- } else {
- throw new IllegalStateException(
- "Property \"" + name + "\" has unsupported value type \""
- + values.getClass().getSimpleName() + "\"");
- }
- mProtoBuilder.addProperties(propertyProto);
- }
- return new AppSearchDocument(mProtoBuilder.build(), mProperties);
- }
- }
-}
diff --git a/apex/appsearch/framework/java/android/app/appsearch/AppSearchEmail.java b/apex/appsearch/framework/java/android/app/appsearch/AppSearchEmail.java
deleted file mode 100644
index 5b9457b77ea0..000000000000
--- a/apex/appsearch/framework/java/android/app/appsearch/AppSearchEmail.java
+++ /dev/null
@@ -1,255 +0,0 @@
-/*
- * Copyright (C) 2020 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.app.appsearch;
-
-import android.annotation.NonNull;
-import android.annotation.Nullable;
-import android.app.appsearch.AppSearchSchema.PropertyConfig;
-
-/**
- * Encapsulates a {@link AppSearchDocument} that represent an email.
- *
- * <p>This class is a higher level implement of {@link AppSearchDocument}.
- *
- * <p>This class will eventually migrate to Jetpack, where it will become public API.
- *
- * @hide
- */
-public class AppSearchEmail extends AppSearchDocument {
- private static final String KEY_FROM = "from";
- private static final String KEY_TO = "to";
- private static final String KEY_CC = "cc";
- private static final String KEY_BCC = "bcc";
- private static final String KEY_SUBJECT = "subject";
- private static final String KEY_BODY = "body";
-
- /** The name of the schema type for {@link AppSearchEmail} documents.*/
- public static final String SCHEMA_TYPE = "builtin:Email";
-
- public static final AppSearchSchema SCHEMA = AppSearchSchema.newBuilder(SCHEMA_TYPE)
- .addProperty(AppSearchSchema.newPropertyBuilder(KEY_FROM)
- .setDataType(PropertyConfig.DATA_TYPE_STRING)
- .setCardinality(PropertyConfig.CARDINALITY_OPTIONAL)
- .setTokenizerType(PropertyConfig.TOKENIZER_TYPE_PLAIN)
- .setIndexingType(PropertyConfig.INDEXING_TYPE_PREFIXES)
- .build()
-
- ).addProperty(AppSearchSchema.newPropertyBuilder(KEY_TO)
- .setDataType(PropertyConfig.DATA_TYPE_STRING)
- .setCardinality(PropertyConfig.CARDINALITY_REPEATED)
- .setTokenizerType(PropertyConfig.TOKENIZER_TYPE_PLAIN)
- .setIndexingType(PropertyConfig.INDEXING_TYPE_PREFIXES)
- .build()
-
- ).addProperty(AppSearchSchema.newPropertyBuilder(KEY_CC)
- .setDataType(PropertyConfig.DATA_TYPE_STRING)
- .setCardinality(PropertyConfig.CARDINALITY_REPEATED)
- .setTokenizerType(PropertyConfig.TOKENIZER_TYPE_PLAIN)
- .setIndexingType(PropertyConfig.INDEXING_TYPE_PREFIXES)
- .build()
-
- ).addProperty(AppSearchSchema.newPropertyBuilder(KEY_BCC)
- .setDataType(PropertyConfig.DATA_TYPE_STRING)
- .setCardinality(PropertyConfig.CARDINALITY_REPEATED)
- .setTokenizerType(PropertyConfig.TOKENIZER_TYPE_PLAIN)
- .setIndexingType(PropertyConfig.INDEXING_TYPE_PREFIXES)
- .build()
-
- ).addProperty(AppSearchSchema.newPropertyBuilder(KEY_SUBJECT)
- .setDataType(PropertyConfig.DATA_TYPE_STRING)
- .setCardinality(PropertyConfig.CARDINALITY_OPTIONAL)
- .setTokenizerType(PropertyConfig.TOKENIZER_TYPE_PLAIN)
- .setIndexingType(PropertyConfig.INDEXING_TYPE_PREFIXES)
- .build()
-
- ).addProperty(AppSearchSchema.newPropertyBuilder(KEY_BODY)
- .setDataType(PropertyConfig.DATA_TYPE_STRING)
- .setCardinality(PropertyConfig.CARDINALITY_OPTIONAL)
- .setTokenizerType(PropertyConfig.TOKENIZER_TYPE_PLAIN)
- .setIndexingType(PropertyConfig.INDEXING_TYPE_PREFIXES)
- .build()
-
- ).build();
-
- /**
- * Creates a new {@link AppSearchEmail} from the contents of an existing
- * {@link AppSearchDocument}.
- *
- * @param document The {@link AppSearchDocument} containing the email content.
- */
- public AppSearchEmail(@NonNull AppSearchDocument document) {
- super(document);
- }
-
- /**
- * Get the from address of {@link AppSearchEmail}.
- *
- * @return Returns the subject of {@link AppSearchEmail} or {@code null} if it's not been set
- * yet.
- * @hide
- */
- @Nullable
- public String getFrom() {
- return getPropertyString(KEY_FROM);
- }
-
- /**
- * Get the destination addresses of {@link AppSearchEmail}.
- *
- * @return Returns the destination addresses of {@link AppSearchEmail} or {@code null} if it's
- * not been set yet.
- * @hide
- */
- @Nullable
- public String[] getTo() {
- return getPropertyStringArray(KEY_TO);
- }
-
- /**
- * Get the CC list of {@link AppSearchEmail}.
- *
- * @return Returns the CC list of {@link AppSearchEmail} or {@code null} if it's not been set
- * yet.
- * @hide
- */
- @Nullable
- public String[] getCc() {
- return getPropertyStringArray(KEY_CC);
- }
-
- /**
- * Get the BCC list of {@link AppSearchEmail}.
- *
- * @return Returns the BCC list of {@link AppSearchEmail} or {@code null} if it's not been set
- * yet.
- * @hide
- */
- @Nullable
- public String[] getBcc() {
- return getPropertyStringArray(KEY_BCC);
- }
-
- /**
- * Get the subject of {@link AppSearchEmail}.
- *
- * @return Returns the value subject of {@link AppSearchEmail} or {@code null} if it's not been
- * set yet.
- * @hide
- */
- @Nullable
- public String getSubject() {
- return getPropertyString(KEY_SUBJECT);
- }
-
- /**
- * Get the body of {@link AppSearchEmail}.
- *
- * @return Returns the body of {@link AppSearchEmail} or {@code null} if it's not been set yet.
- * @hide
- */
- @Nullable
- public String getBody() {
- return getPropertyString(KEY_BODY);
- }
-
- /**
- * The builder class for {@link AppSearchEmail}.
- * @hide
- */
- public static class Builder extends AppSearchDocument.Builder<AppSearchEmail.Builder> {
-
- /**
- * Create a new {@link AppSearchEmail.Builder}
- * @param uri The Uri of the Email.
- * @hide
- */
- public Builder(@NonNull String uri) {
- super(uri, SCHEMA_TYPE);
- }
-
- /**
- * Set the from address of {@link AppSearchEmail}
- * @hide
- */
- @NonNull
- public AppSearchEmail.Builder setFrom(@NonNull String from) {
- setProperty(KEY_FROM, from);
- return this;
- }
-
- /**
- * Set the destination address of {@link AppSearchEmail}
- * @hide
- */
- @NonNull
- public AppSearchEmail.Builder setTo(@NonNull String... to) {
- setProperty(KEY_TO, to);
- return this;
- }
-
- /**
- * Set the CC list of {@link AppSearchEmail}
- * @hide
- */
- @NonNull
- public AppSearchEmail.Builder setCc(@NonNull String... cc) {
- setProperty(KEY_CC, cc);
- return this;
- }
-
- /**
- * Set the BCC list of {@link AppSearchEmail}
- * @hide
- */
- @NonNull
- public AppSearchEmail.Builder setBcc(@NonNull String... bcc) {
- setProperty(KEY_BCC, bcc);
- return this;
- }
-
- /**
- * Set the subject of {@link AppSearchEmail}
- * @hide
- */
- @NonNull
- public AppSearchEmail.Builder setSubject(@NonNull String subject) {
- setProperty(KEY_SUBJECT, subject);
- return this;
- }
-
- /**
- * Set the body of {@link AppSearchEmail}
- * @hide
- */
- @NonNull
- public AppSearchEmail.Builder setBody(@NonNull String body) {
- setProperty(KEY_BODY, body);
- return this;
- }
-
- /**
- * Builds the {@link AppSearchEmail} object.
- *
- * @hide
- */
- @NonNull
- @Override
- public AppSearchEmail build() {
- return new AppSearchEmail(super.build());
- }
- }
-}
diff --git a/apex/appsearch/framework/java/android/app/appsearch/AppSearchManager.java b/apex/appsearch/framework/java/android/app/appsearch/AppSearchManager.java
deleted file mode 100644
index e2c9b0f74870..000000000000
--- a/apex/appsearch/framework/java/android/app/appsearch/AppSearchManager.java
+++ /dev/null
@@ -1,293 +0,0 @@
-/*
- * Copyright (C) 2020 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package android.app.appsearch;
-
-import android.annotation.CallbackExecutor;
-import android.annotation.NonNull;
-import android.annotation.SystemService;
-import android.content.Context;
-import android.os.RemoteException;
-
-import com.android.internal.infra.AndroidFuture;
-
-import com.google.android.icing.proto.SchemaProto;
-import com.google.android.icing.proto.SearchResultProto;
-import com.google.android.icing.proto.SearchSpecProto;
-import com.google.android.icing.proto.StatusProto;
-import com.google.android.icing.protobuf.InvalidProtocolBufferException;
-
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.List;
-import java.util.concurrent.ExecutionException;
-import java.util.concurrent.Executor;
-import java.util.function.BiConsumer;
-
-/**
- * This class provides access to the centralized AppSearch index maintained by the system.
- *
- * <p>Apps can index structured text documents with AppSearch, which can then be retrieved through
- * the query API.
- *
- * @hide
- */
-@SystemService(Context.APP_SEARCH_SERVICE)
-public class AppSearchManager {
- private final IAppSearchManager mService;
-
- /** @hide */
- public AppSearchManager(@NonNull IAppSearchManager service) {
- mService = service;
- }
-
- /**
- * Sets the schema being used by documents provided to the {@link #putDocuments} method.
- *
- * <p>The schema provided here is compared to the stored copy of the schema previously supplied
- * to {@link #setSchema}, if any, to determine how to treat existing documents. The following
- * types of schema modifications are always safe and are made without deleting any existing
- * documents:
- * <ul>
- * <li>Addition of new types
- * <li>Addition of new
- * {@link android.app.appsearch.AppSearchSchema.PropertyConfig#CARDINALITY_OPTIONAL
- * OPTIONAL} or
- * {@link android.app.appsearch.AppSearchSchema.PropertyConfig#CARDINALITY_REPEATED
- * REPEATED} properties to a type
- * <li>Changing the cardinality of a data type to be less restrictive (e.g. changing an
- * {@link android.app.appsearch.AppSearchSchema.PropertyConfig#CARDINALITY_OPTIONAL
- * OPTIONAL} property into a
- * {@link android.app.appsearch.AppSearchSchema.PropertyConfig#CARDINALITY_REPEATED
- * REPEATED} property.
- * </ul>
- *
- * <p>The following types of schema changes are not backwards-compatible. Supplying a schema
- * with such changes will result in this call throwing an {@link IllegalSchemaException}
- * describing the incompatibility, and the previously set schema will remain active:
- * <ul>
- * <li>Removal of an existing type
- * <li>Removal of a property from a type
- * <li>Changing the data type ({@code boolean}, {@code long}, etc.) of an existing property
- * <li>For properties of {@code Document} type, changing the schema type of
- * {@code Document Documents} of that property
- * <li>Changing the cardinality of a data type to be more restrictive (e.g. changing an
- * {@link android.app.appsearch.AppSearchSchema.PropertyConfig#CARDINALITY_OPTIONAL
- * OPTIONAL} property into a
- * {@link android.app.appsearch.AppSearchSchema.PropertyConfig#CARDINALITY_REQUIRED
- * REQUIRED} property).
- * <li>Adding a
- * {@link android.app.appsearch.AppSearchSchema.PropertyConfig#CARDINALITY_REQUIRED
- * REQUIRED} property.
- * </ul>
- *
- * <p>If you need to make non-backwards-compatible changes as described above, instead use the
- * {@link #setSchema(List, boolean)} method with the {@code forceOverride} parameter set to
- * {@code true}.
- *
- * <p>It is a no-op to set the same schema as has been previously set; this is handled
- * efficiently.
- *
- * @param schemas The schema configs for the types used by the calling app.
- * @throws IllegalSchemaException If the provided schema is invalid, or is incompatible with the
- * previous schema.
- *
- * @hide
- */
- public void setSchema(@NonNull AppSearchSchema... schemas) {
- setSchema(Arrays.asList(schemas), /*forceOverride=*/false);
- }
-
- /**
- * Sets the schema being used by documents provided to the {@link #putDocuments} method.
- *
- * <p>This method is similar to {@link #setSchema(AppSearchSchema...)}, except for the
- * {@code forceOverride} parameter. If a backwards-incompatible schema is specified but the
- * {@code forceOverride} parameter is set to {@code true}, instead of throwing an
- * {@link IllegalSchemaException}, all documents which are not compatible with the new schema
- * will be deleted and the incompatible schema will be applied.
- *
- * @param schemas The schema configs for the types used by the calling app.
- * @param forceOverride Whether to force the new schema to be applied even if there are
- * incompatible changes versus the previously set schema. Documents which are incompatible
- * with the new schema will be deleted.
- * @throws IllegalSchemaException If the provided schema is invalid, or is incompatible with the
- * previous schema and the {@code forceOverride} parameter is set to {@code false}.
- *
- * @hide
- */
- public void setSchema(@NonNull List<AppSearchSchema> schemas, boolean forceOverride) {
- // Prepare the merged schema for transmission.
- SchemaProto.Builder schemaProtoBuilder = SchemaProto.newBuilder();
- for (AppSearchSchema schema : schemas) {
- schemaProtoBuilder.addTypes(schema.getProto());
- }
-
- // Serialize and send the schema.
- // TODO: This should use com.android.internal.infra.RemoteStream or another mechanism to
- // avoid binder limits.
- byte[] schemaBytes = schemaProtoBuilder.build().toByteArray();
- AndroidFuture<Void> future = new AndroidFuture<>();
- try {
- mService.setSchema(schemaBytes, forceOverride, future);
- } catch (RemoteException e) {
- future.completeExceptionally(e);
- }
- getFutureOrThrow(future);
- }
-
- /**
- * Index {@link AppSearchDocument Documents} into AppSearch.
- *
- * <p>You should not call this method directly; instead, use the
- * {@code AppSearch#putDocuments()} API provided by JetPack.
- *
- * <p>Each {@link AppSearchDocument Document's} {@code schemaType} field must be set to the
- * name of a schema type previously registered via the {@link #setSchema} method.
- *
- * @param documents {@link AppSearchDocument Documents} that need to be indexed.
- * @return An {@link AppSearchBatchResult} mapping the document URIs to {@link Void} if they
- * were successfully indexed, or a {@link Throwable} describing the failure if they could
- * not be indexed.
- * @hide
- */
- public AppSearchBatchResult<String, Void> putDocuments(
- @NonNull List<AppSearchDocument> documents) {
- // TODO(b/146386470): Transmit these documents as a RemoteStream instead of sending them in
- // one big list.
- List<byte[]> documentsBytes = new ArrayList<>(documents.size());
- for (AppSearchDocument document : documents) {
- documentsBytes.add(document.getProto().toByteArray());
- }
- AndroidFuture<AppSearchBatchResult> future = new AndroidFuture<>();
- try {
- mService.putDocuments(documentsBytes, future);
- } catch (RemoteException e) {
- future.completeExceptionally(e);
- }
- return getFutureOrThrow(future);
- }
-
- /**
- * This method searches for documents based on a given query string. It also accepts
- * specifications regarding how to search and format the results.
- *
- *<p>Currently we support following features in the raw query format:
- * <ul>
- * <li>AND
- * <p>AND joins (e.g. “match documents that have both the terms ‘dog’ and
- * ‘cat’”).
- * Example: hello world matches documents that have both ‘hello’ and ‘world’
- * <li>OR
- * <p>OR joins (e.g. “match documents that have either the term ‘dog’ or
- * ‘cat’”).
- * Example: dog OR puppy
- * <li>Exclusion
- * <p>Exclude a term (e.g. “match documents that do
- * not have the term ‘dog’”).
- * Example: -dog excludes the term ‘dog’
- * <li>Grouping terms
- * <p>Allow for conceptual grouping of subqueries to enable hierarchical structures (e.g.
- * “match documents that have either ‘dog’ or ‘puppy’, and either ‘cat’ or ‘kitten’”).
- * Example: (dog puppy) (cat kitten) two one group containing two terms.
- * <li>Property restricts
- * <p> Specifies which properties of a document to specifically match terms in (e.g.
- * “match documents where the ‘subject’ property contains ‘important’”).
- * Example: subject:important matches documents with the term ‘important’ in the
- * ‘subject’ property
- * <li>Schema type restricts
- * <p>This is similar to property restricts, but allows for restricts on top-level document
- * fields, such as schema_type. Clients should be able to limit their query to documents of
- * a certain schema_type (e.g. “match documents that are of the ‘Email’ schema_type”).
- * Example: { schema_type_filters: “Email”, “Video”,query: “dog” } will match documents
- * that contain the query term ‘dog’ and are of either the ‘Email’ schema type or the
- * ‘Video’ schema type.
- * </ul>
- *
- * <p> It is strongly recommended to use Jetpack APIs.
- *
- * @param queryExpression Query String to search.
- * @param searchSpec Spec for setting filters, raw query etc.
- * @param executor Executor on which to invoke the callback.
- * @param callback Callback to receive errors resulting from the query operation. If the
- * operation succeeds, the callback will be invoked with {@code null}.
- * @hide
- */
- @NonNull
- public void query(
- @NonNull String queryExpression,
- @NonNull SearchSpec searchSpec,
- @NonNull @CallbackExecutor Executor executor,
- @NonNull BiConsumer<? super SearchResults, ? super Throwable> callback) {
- AndroidFuture<byte[]> future = new AndroidFuture<>();
- future.whenCompleteAsync((searchResultBytes, err) -> {
- if (err != null) {
- callback.accept(null, err);
- return;
- }
-
- if (searchResultBytes != null) {
- SearchResultProto searchResultProto;
- try {
- searchResultProto = SearchResultProto.parseFrom(searchResultBytes);
- } catch (InvalidProtocolBufferException e) {
- callback.accept(null, e);
- return;
- }
- if (searchResultProto.getStatus().getCode() != StatusProto.Code.OK) {
- // TODO(sidchhabra): Add better exception handling.
- callback.accept(
- null,
- new RuntimeException(searchResultProto.getStatus().getMessage()));
- return;
- }
- SearchResults searchResults = new SearchResults(searchResultProto);
- callback.accept(searchResults, null);
- return;
- }
-
- // Nothing was supplied in the future at all
- callback.accept(
- null, new IllegalStateException("Unknown failure occurred while querying"));
- }, executor);
-
- try {
- SearchSpecProto searchSpecProto = searchSpec.getSearchSpecProto();
- searchSpecProto = searchSpecProto.toBuilder().setQuery(queryExpression).build();
- mService.query(searchSpecProto.toByteArray(),
- searchSpec.getResultSpecProto().toByteArray(),
- searchSpec.getScoringSpecProto().toByteArray(), future);
- } catch (RemoteException e) {
- future.completeExceptionally(e);
- }
- }
-
- private static <T> T getFutureOrThrow(@NonNull AndroidFuture<T> future) {
- try {
- return future.get();
- } catch (Throwable e) {
- if (e instanceof ExecutionException) {
- e = e.getCause();
- }
- if (e instanceof RuntimeException) {
- throw (RuntimeException) e;
- }
- if (e instanceof Error) {
- throw (Error) e;
- }
- throw new RuntimeException(e);
- }
- }
-}
diff --git a/apex/appsearch/framework/java/android/app/appsearch/AppSearchManagerFrameworkInitializer.java b/apex/appsearch/framework/java/android/app/appsearch/AppSearchManagerFrameworkInitializer.java
deleted file mode 100644
index 02cc967e7daf..000000000000
--- a/apex/appsearch/framework/java/android/app/appsearch/AppSearchManagerFrameworkInitializer.java
+++ /dev/null
@@ -1,43 +0,0 @@
-/*
- * Copyright (C) 2019 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package android.app.appsearch;
-
-import android.annotation.SystemApi;
-import android.app.SystemServiceRegistry;
-import android.content.Context;
-
-/**
- * Class holding initialization code for the AppSearch module.
- *
- * @hide
- */
-@SystemApi
-public class AppSearchManagerFrameworkInitializer {
- private AppSearchManagerFrameworkInitializer() {}
-
- /**
- * Called by {@link SystemServiceRegistry}'s static initializer and registers all AppSearch
- * services to {@link Context}, so that {@link Context#getSystemService} can return them.
- *
- * @throws IllegalStateException if this is called from anywhere besides
- * {@link SystemServiceRegistry}
- */
- public static void initialize() {
- SystemServiceRegistry.registerStaticService(
- Context.APP_SEARCH_SERVICE, AppSearchManager.class,
- (service) -> new AppSearchManager(IAppSearchManager.Stub.asInterface(service)));
- }
-}
diff --git a/apex/appsearch/framework/java/android/app/appsearch/AppSearchSchema.java b/apex/appsearch/framework/java/android/app/appsearch/AppSearchSchema.java
deleted file mode 100644
index 1d54dc4971a6..000000000000
--- a/apex/appsearch/framework/java/android/app/appsearch/AppSearchSchema.java
+++ /dev/null
@@ -1,369 +0,0 @@
-/*
- * Copyright (C) 2019 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.app.appsearch;
-
-import android.annotation.IntDef;
-import android.annotation.NonNull;
-import android.util.ArraySet;
-
-import com.android.internal.annotations.VisibleForTesting;
-
-import com.google.android.icing.proto.PropertyConfigProto;
-import com.google.android.icing.proto.SchemaTypeConfigProto;
-import com.google.android.icing.proto.TermMatchType;
-
-import java.lang.annotation.Retention;
-import java.lang.annotation.RetentionPolicy;
-import java.util.Set;
-
-/**
- * The AppSearch Schema for a particular type of document.
- *
- * <p>For example, an e-mail message or a music recording could be a schema type.
- *
- * <p>The schema consists of type information, properties, and config (like tokenization type).
- *
- * @hide
- */
-public final class AppSearchSchema {
- private final SchemaTypeConfigProto mProto;
-
- private AppSearchSchema(SchemaTypeConfigProto proto) {
- mProto = proto;
- }
-
- /** Creates a new {@link AppSearchSchema.Builder}. */
- @NonNull
- public static AppSearchSchema.Builder newBuilder(@NonNull String typeName) {
- return new AppSearchSchema.Builder(typeName);
- }
-
- /** Creates a new {@link PropertyConfig.Builder}. */
- @NonNull
- public static PropertyConfig.Builder newPropertyBuilder(@NonNull String propertyName) {
- return new PropertyConfig.Builder(propertyName);
- }
-
- /**
- * Returns the {@link SchemaTypeConfigProto} populated by this builder.
- * @hide
- */
- @NonNull
- @VisibleForTesting
- public SchemaTypeConfigProto getProto() {
- return mProto;
- }
-
- @Override
- public String toString() {
- return mProto.toString();
- }
-
- /** Builder for {@link AppSearchSchema objects}. */
- public static final class Builder {
- private final SchemaTypeConfigProto.Builder mProtoBuilder =
- SchemaTypeConfigProto.newBuilder();
-
- private Builder(@NonNull String typeName) {
- mProtoBuilder.setSchemaType(typeName);
- }
-
- /** Adds a property to the given type. */
- @NonNull
- public AppSearchSchema.Builder addProperty(@NonNull PropertyConfig propertyConfig) {
- mProtoBuilder.addProperties(propertyConfig.mProto);
- return this;
- }
-
- /**
- * Constructs a new {@link AppSearchSchema} from the contents of this builder.
- *
- * <p>After calling this method, the builder must no longer be used.
- */
- @NonNull
- public AppSearchSchema build() {
- Set<String> propertyNames = new ArraySet<>();
- for (PropertyConfigProto propertyConfigProto : mProtoBuilder.getPropertiesList()) {
- if (!propertyNames.add(propertyConfigProto.getPropertyName())) {
- throw new IllegalSchemaException(
- "Property defined more than once: "
- + propertyConfigProto.getPropertyName());
- }
- }
- return new AppSearchSchema(mProtoBuilder.build());
- }
- }
-
- /**
- * Configuration for a single property (field) of a document type.
- *
- * <p>For example, an {@code EmailMessage} would be a type and the {@code subject} would be
- * a property.
- */
- public static final class PropertyConfig {
- /** Physical data-types of the contents of the property. */
- // NOTE: The integer values of these constants must match the proto enum constants in
- // com.google.android.icing.proto.PropertyConfigProto.DataType.Code.
- @IntDef(prefix = {"DATA_TYPE_"}, value = {
- DATA_TYPE_STRING,
- DATA_TYPE_INT64,
- DATA_TYPE_DOUBLE,
- DATA_TYPE_BOOLEAN,
- DATA_TYPE_BYTES,
- DATA_TYPE_DOCUMENT,
- })
- @Retention(RetentionPolicy.SOURCE)
- public @interface DataType {}
-
- public static final int DATA_TYPE_STRING = 1;
- public static final int DATA_TYPE_INT64 = 2;
- public static final int DATA_TYPE_DOUBLE = 3;
- public static final int DATA_TYPE_BOOLEAN = 4;
-
- /** Unstructured BLOB. */
- public static final int DATA_TYPE_BYTES = 5;
-
- /**
- * Indicates that the property itself is an Document, making it part a hierarchical
- * Document schema. Any property using this DataType MUST have a valid
- * {@code schemaType}.
- */
- public static final int DATA_TYPE_DOCUMENT = 6;
-
- /** The cardinality of the property (whether it is required, optional or repeated). */
- // NOTE: The integer values of these constants must match the proto enum constants in
- // com.google.android.icing.proto.PropertyConfigProto.Cardinality.Code.
- @IntDef(prefix = {"CARDINALITY_"}, value = {
- CARDINALITY_REPEATED,
- CARDINALITY_OPTIONAL,
- CARDINALITY_REQUIRED,
- })
- @Retention(RetentionPolicy.SOURCE)
- public @interface Cardinality {}
-
- /** Any number of items (including zero) [0...*]. */
- public static final int CARDINALITY_REPEATED = 1;
-
- /** Zero or one value [0,1]. */
- public static final int CARDINALITY_OPTIONAL = 2;
-
- /** Exactly one value [1]. */
- public static final int CARDINALITY_REQUIRED = 3;
-
- /** Encapsulates the configurations on how AppSearch should query/index these terms. */
- @IntDef(prefix = {"INDEXING_TYPE_"}, value = {
- INDEXING_TYPE_NONE,
- INDEXING_TYPE_EXACT_TERMS,
- INDEXING_TYPE_PREFIXES,
- })
- @Retention(RetentionPolicy.SOURCE)
- public @interface IndexingType {}
-
- /**
- * Content in this property will not be tokenized or indexed.
- *
- * <p>Useful if the data type is not made up of terms (e.g.
- * {@link PropertyConfig#DATA_TYPE_DOCUMENT} or {@link PropertyConfig#DATA_TYPE_BYTES}
- * type). All the properties inside the nested property won't be indexed regardless of the
- * value of {@code indexingType} for the nested properties.
- */
- public static final int INDEXING_TYPE_NONE = 0;
-
- /**
- * Content in this property should only be returned for queries matching the exact tokens
- * appearing in this property.
- *
- * <p>Ex. A property with "fool" should NOT match a query for "foo".
- */
- public static final int INDEXING_TYPE_EXACT_TERMS = 1;
-
- /**
- * Content in this property should be returned for queries that are either exact matches or
- * query matches of the tokens appearing in this property.
- *
- * <p>Ex. A property with "fool" <b>should</b> match a query for "foo".
- */
- public static final int INDEXING_TYPE_PREFIXES = 2;
-
- /** Configures how tokens should be extracted from this property. */
- // NOTE: The integer values of these constants must match the proto enum constants in
- // com.google.android.icing.proto.IndexingConfig.TokenizerType.Code.
- @IntDef(prefix = {"TOKENIZER_TYPE_"}, value = {
- TOKENIZER_TYPE_NONE,
- TOKENIZER_TYPE_PLAIN,
- })
- @Retention(RetentionPolicy.SOURCE)
- public @interface TokenizerType {}
-
- /**
- * It is only valid for tokenizer_type to be 'NONE' if the data type is
- * {@link PropertyConfig#DATA_TYPE_DOCUMENT}.
- */
- public static final int TOKENIZER_TYPE_NONE = 0;
-
- /** Tokenization for plain text. */
- public static final int TOKENIZER_TYPE_PLAIN = 1;
-
- private final PropertyConfigProto mProto;
-
- private PropertyConfig(PropertyConfigProto proto) {
- mProto = proto;
- }
-
- @Override
- public String toString() {
- return mProto.toString();
- }
-
- /**
- * Builder for {@link PropertyConfig}.
- *
- * <p>The following properties must be set, or {@link PropertyConfig} construction will
- * fail:
- * <ul>
- * <li>dataType
- * <li>cardinality
- * </ul>
- *
- * <p>In addition, if {@code schemaType} is {@link #DATA_TYPE_DOCUMENT}, {@code schemaType}
- * is also required.
- */
- public static final class Builder {
- private final PropertyConfigProto.Builder mPropertyConfigProto =
- PropertyConfigProto.newBuilder();
- private final com.google.android.icing.proto.IndexingConfig.Builder
- mIndexingConfigProto =
- com.google.android.icing.proto.IndexingConfig.newBuilder();
-
- private Builder(String propertyName) {
- mPropertyConfigProto.setPropertyName(propertyName);
- }
-
- /**
- * Type of data the property contains (e.g. string, int, bytes, etc).
- *
- * <p>This property must be set.
- */
- @NonNull
- public PropertyConfig.Builder setDataType(@DataType int dataType) {
- PropertyConfigProto.DataType.Code dataTypeProto =
- PropertyConfigProto.DataType.Code.forNumber(dataType);
- if (dataTypeProto == null) {
- throw new IllegalArgumentException("Invalid dataType: " + dataType);
- }
- mPropertyConfigProto.setDataType(dataTypeProto);
- return this;
- }
-
- /**
- * The logical schema-type of the contents of this property.
- *
- * <p>Only required when {@link #setDataType(int)} is set to
- * {@link #DATA_TYPE_DOCUMENT}. Otherwise, it is ignored.
- */
- @NonNull
- public PropertyConfig.Builder setSchemaType(@NonNull String schemaType) {
- mPropertyConfigProto.setSchemaType(schemaType);
- return this;
- }
-
- /**
- * The cardinality of the property (whether it is optional, required or repeated).
- *
- * <p>This property must be set.
- */
- @NonNull
- public PropertyConfig.Builder setCardinality(@Cardinality int cardinality) {
- PropertyConfigProto.Cardinality.Code cardinalityProto =
- PropertyConfigProto.Cardinality.Code.forNumber(cardinality);
- if (cardinalityProto == null) {
- throw new IllegalArgumentException("Invalid cardinality: " + cardinality);
- }
- mPropertyConfigProto.setCardinality(cardinalityProto);
- return this;
- }
-
- /**
- * Configures how a property should be indexed so that it can be retrieved by queries.
- */
- @NonNull
- public PropertyConfig.Builder setIndexingType(@IndexingType int indexingType) {
- TermMatchType.Code termMatchTypeProto;
- switch (indexingType) {
- case INDEXING_TYPE_NONE:
- termMatchTypeProto = TermMatchType.Code.UNKNOWN;
- break;
- case INDEXING_TYPE_EXACT_TERMS:
- termMatchTypeProto = TermMatchType.Code.EXACT_ONLY;
- break;
- case INDEXING_TYPE_PREFIXES:
- termMatchTypeProto = TermMatchType.Code.PREFIX;
- break;
- default:
- throw new IllegalArgumentException("Invalid indexingType: " + indexingType);
- }
- mIndexingConfigProto.setTermMatchType(termMatchTypeProto);
- return this;
- }
-
- /** Configures how this property should be tokenized (split into words). */
- @NonNull
- public PropertyConfig.Builder setTokenizerType(@TokenizerType int tokenizerType) {
- com.google.android.icing.proto.IndexingConfig.TokenizerType.Code
- tokenizerTypeProto =
- com.google.android.icing.proto.IndexingConfig
- .TokenizerType.Code.forNumber(tokenizerType);
- if (tokenizerTypeProto == null) {
- throw new IllegalArgumentException("Invalid tokenizerType: " + tokenizerType);
- }
- mIndexingConfigProto.setTokenizerType(tokenizerTypeProto);
- return this;
- }
-
- /**
- * Constructs a new {@link PropertyConfig} from the contents of this builder.
- *
- * <p>After calling this method, the builder must no longer be used.
- *
- * @throws IllegalSchemaException If the property is not correctly populated (e.g.
- * missing {@code dataType}).
- */
- @NonNull
- public PropertyConfig build() {
- mPropertyConfigProto.setIndexingConfig(mIndexingConfigProto);
- // TODO(b/147692920): Send the schema to Icing Lib for official validation, instead
- // of partially reimplementing some of the validation Icing does here.
- if (mPropertyConfigProto.getDataType()
- == PropertyConfigProto.DataType.Code.UNKNOWN) {
- throw new IllegalSchemaException("Missing field: dataType");
- }
- if (mPropertyConfigProto.getSchemaType().isEmpty()
- && mPropertyConfigProto.getDataType()
- == PropertyConfigProto.DataType.Code.DOCUMENT) {
- throw new IllegalSchemaException(
- "Missing field: schemaType (required for configs with "
- + "dataType = DOCUMENT)");
- }
- if (mPropertyConfigProto.getCardinality()
- == PropertyConfigProto.Cardinality.Code.UNKNOWN) {
- throw new IllegalSchemaException("Missing field: cardinality");
- }
- return new PropertyConfig(mPropertyConfigProto.build());
- }
- }
- }
-}
diff --git a/apex/appsearch/framework/java/android/app/appsearch/IAppSearchManager.aidl b/apex/appsearch/framework/java/android/app/appsearch/IAppSearchManager.aidl
deleted file mode 100644
index eef41ed7104d..000000000000
--- a/apex/appsearch/framework/java/android/app/appsearch/IAppSearchManager.aidl
+++ /dev/null
@@ -1,60 +0,0 @@
-/**
- * Copyright 2020, The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package android.app.appsearch;
-
-import com.android.internal.infra.AndroidFuture;
-
-parcelable AppSearchBatchResult;
-
-/** {@hide} */
-interface IAppSearchManager {
- /**
- * Sets the schema.
- *
- * @param schemaBytes Serialized SchemaProto.
- * @param forceOverride Whether to apply the new schema even if it is incompatible. All
- * incompatible documents will be deleted.
- * @param callback {@link AndroidFuture}&lt;{@link Void}&gt;. Will be completed with
- * {@code null} upon successful completion of the setSchema call, or completed
- * exceptionally if setSchema fails.
- */
- void setSchema(in byte[] schemaBytes, boolean forceOverride, in AndroidFuture callback);
-
- /**
- * Inserts documents into the index.
- *
- * @param documentsBytes {@link List}&lt;byte[]&gt; of serialized DocumentProtos.
- * @param callback
- * {@link AndroidFuture}&lt;{@link AppSearchBatchResult}&lt;{@link String}, {@link Void}&gt;&gt;.
- * If the call fails to start, {@code callback} will be completed exceptionally. Otherwise,
- * {@code callback} will be completed with an
- * {@link AppSearchBatchResult}&lt;{@link String}, {@link Void}&gt;
- * where the keys are document URIs, and the values are {@code null}.
- */
- void putDocuments(in List documentsBytes, in AndroidFuture<AppSearchBatchResult> callback);
-
- /**
- * Searches a document based on a given specifications.
- *
- * @param searchSpecBytes Serialized SearchSpecProto.
- * @param resultSpecBytes Serialized SearchResultsProto.
- * @param scoringSpecBytes Serialized ScoringSpecProto.
- * @param callback {@link AndroidFuture}. Will be completed with a serialized
- * {@link SearchResultsProto}, or completed exceptionally if query fails.
- */
- void query(in byte[] searchSpecBytes, in byte[] resultSpecBytes,
- in byte[] scoringSpecBytes, in AndroidFuture callback);
-}
diff --git a/apex/appsearch/framework/java/android/app/appsearch/IllegalSchemaException.java b/apex/appsearch/framework/java/android/app/appsearch/IllegalSchemaException.java
deleted file mode 100644
index f9e528cd2951..000000000000
--- a/apex/appsearch/framework/java/android/app/appsearch/IllegalSchemaException.java
+++ /dev/null
@@ -1,36 +0,0 @@
-/*
- * Copyright (C) 2019 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.app.appsearch;
-
-import android.annotation.NonNull;
-
-/**
- * Indicates that a {@link android.app.appsearch.AppSearchSchema} has logical inconsistencies such
- * as unpopulated mandatory fields or illegal combinations of parameters.
- *
- * @hide
- */
-public class IllegalSchemaException extends IllegalArgumentException {
- /**
- * Constructs a new {@link IllegalSchemaException}.
- *
- * @param message A developer-readable description of the issue with the bundle.
- */
- public IllegalSchemaException(@NonNull String message) {
- super(message);
- }
-}
diff --git a/apex/appsearch/framework/java/android/app/appsearch/MatchInfo.java b/apex/appsearch/framework/java/android/app/appsearch/MatchInfo.java
deleted file mode 100644
index 5ce296082d70..000000000000
--- a/apex/appsearch/framework/java/android/app/appsearch/MatchInfo.java
+++ /dev/null
@@ -1,182 +0,0 @@
-/*
- * Copyright (C) 2020 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.app.appsearch;
-
-import android.annotation.NonNull;
-import android.util.Range;
-
-import com.google.android.icing.proto.SnippetMatchProto;
-
-/**
- * Snippet: It refers to a substring of text from the content of document that is returned as a
- * part of search result.
- * This class represents a match objects for any Snippets that might be present in
- * {@link SearchResults} from query. Using this class user can get the full text, exact matches and
- * Snippets of document content for a given match.
- *
- * <p>Class Example 1:
- * A document contains following text in property subject:
- * <p>A commonly used fake word is foo. Another nonsense word that’s used a lot is bar.
- *
- * <p>If the queryExpression is "foo".
- *
- * <p>{@link MatchInfo#getPropertyPath()} returns "subject"
- * <p>{@link MatchInfo#getFullText()} returns "A commonly used fake word is foo. Another nonsense
- * word that’s used a lot is bar."
- * <p>{@link MatchInfo#getExactMatchPosition()} returns [29, 32]
- * <p>{@link MatchInfo#getExactMatch()} returns "foo"
- * <p>{@link MatchInfo#getSnippetPosition()} returns [29, 41]
- * <p>{@link MatchInfo#getSnippet()} returns "is foo. Another"
- * <p>
- * <p>Class Example 2:
- * A document contains a property name sender which contains 2 property names name and email, so
- * we will have 2 property paths: {@code sender.name} and {@code sender.email}.
- * <p> Let {@code sender.name = "Test Name Jr."} and {@code sender.email = "TestNameJr@gmail.com"}
- *
- * <p>If the queryExpression is "Test". We will have 2 matches.
- *
- * <p> Match-1
- * <p>{@link MatchInfo#getPropertyPath()} returns "sender.name"
- * <p>{@link MatchInfo#getFullText()} returns "Test Name Jr."
- * <p>{@link MatchInfo#getExactMatchPosition()} returns [0, 4]
- * <p>{@link MatchInfo#getExactMatch()} returns "Test"
- * <p>{@link MatchInfo#getSnippetPosition()} returns [0, 9]
- * <p>{@link MatchInfo#getSnippet()} returns "Test Name Jr."
- * <p> Match-2
- * <p>{@link MatchInfo#getPropertyPath()} returns "sender.email"
- * <p>{@link MatchInfo#getFullText()} returns "TestNameJr@gmail.com"
- * <p>{@link MatchInfo#getExactMatchPosition()} returns [0, 20]
- * <p>{@link MatchInfo#getExactMatch()} returns "TestNameJr@gmail.com"
- * <p>{@link MatchInfo#getSnippetPosition()} returns [0, 20]
- * <p>{@link MatchInfo#getSnippet()} returns "TestNameJr@gmail.com"
- * @hide
- */
-// TODO(sidchhabra): Capture real snippet after integration with icingLib.
-public final class MatchInfo {
-
- private final String mPropertyPath;
- private final SnippetMatchProto mSnippetMatch;
- private final AppSearchDocument mDocument;
- /**
- * List of content with same property path in a document when there are multiple matches in
- * repeated sections.
- */
- private final String[] mValues;
-
- /** @hide */
- public MatchInfo(@NonNull String propertyPath, @NonNull SnippetMatchProto snippetMatch,
- @NonNull AppSearchDocument document) {
- mPropertyPath = propertyPath;
- mSnippetMatch = snippetMatch;
- mDocument = document;
- // In IcingLib snippeting is available for only 3 data types i.e String, double and long,
- // so we need to check which of these three are requested.
- // TODO (sidchhabra): getPropertyStringArray takes property name, handle for property path.
- String[] values = mDocument.getPropertyStringArray(propertyPath);
- if (values == null) {
- values = doubleToString(mDocument.getPropertyDoubleArray(propertyPath));
- }
- if (values == null) {
- values = longToString(mDocument.getPropertyLongArray(propertyPath));
- }
- if (values == null) {
- throw new IllegalStateException("No content found for requested property path!");
- }
- mValues = values;
- }
-
- /**
- * Gets the property path corresponding to the given entry.
- * <p>Property Path: '.' - delimited sequence of property names indicating which property in
- * the Document these snippets correspond to.
- * <p>Example properties: 'body', 'sender.name', 'sender.emailaddress', etc.
- * For class example 1 this returns "subject"
- */
- @NonNull
- public String getPropertyPath() {
- return mPropertyPath;
- }
-
- /**
- * Gets the full text corresponding to the given entry.
- * <p>For class example this returns "A commonly used fake word is foo. Another nonsense word
- * that’s used a lot is bar."
- */
- @NonNull
- public String getFullText() {
- return mValues[mSnippetMatch.getValuesIndex()];
- }
-
- /**
- * Gets the exact match range corresponding to the given entry.
- * <p>For class example 1 this returns [29, 32]
- */
- @NonNull
- public Range getExactMatchPosition() {
- return new Range(mSnippetMatch.getExactMatchPosition(),
- mSnippetMatch.getExactMatchPosition() + mSnippetMatch.getExactMatchBytes());
- }
-
- /**
- * Gets the exact match corresponding to the given entry.
- * <p>For class example 1 this returns "foo"
- */
- @NonNull
- public CharSequence getExactMatch() {
- return getSubstring(getExactMatchPosition());
- }
-
- /**
- * Gets the snippet range corresponding to the given entry.
- * <p>For class example 1 this returns [29, 41]
- */
- @NonNull
- public Range getSnippetPosition() {
- return new Range(mSnippetMatch.getWindowPosition(),
- mSnippetMatch.getWindowPosition() + mSnippetMatch.getWindowBytes());
- }
-
- /**
- * Gets the snippet corresponding to the given entry.
- * <p>Snippet - Provides a subset of the content to display. The
- * length of this content can be changed {@link SearchSpec.Builder#setMaxSnippetSize(int)}.
- * Windowing is centered around the middle of the matched token with content on either side
- * clipped to token boundaries.
- * <p>For class example 1 this returns "foo. Another"
- */
- @NonNull
- public CharSequence getSnippet() {
- return getSubstring(getSnippetPosition());
- }
-
- private CharSequence getSubstring(Range range) {
- return getFullText()
- .substring((int) range.getLower(), (int) range.getUpper());
- }
-
- /** Utility method to convert double[] to String[] */
- private String[] doubleToString(double[] values) {
- //TODO(sidchhabra): Implement the method.
- return null;
- }
-
- /** Utility method to convert long[] to String[] */
- private String[] longToString(long[] values) {
- //TODO(sidchhabra): Implement the method.
- return null;
- }
-}
diff --git a/apex/appsearch/framework/java/android/app/appsearch/SearchResults.java b/apex/appsearch/framework/java/android/app/appsearch/SearchResults.java
deleted file mode 100644
index 7287fe68f519..000000000000
--- a/apex/appsearch/framework/java/android/app/appsearch/SearchResults.java
+++ /dev/null
@@ -1,128 +0,0 @@
-/*
- * Copyright (C) 2020 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.app.appsearch;
-
-import android.annotation.NonNull;
-import android.annotation.Nullable;
-
-import com.google.android.icing.proto.SearchResultProto;
-import com.google.android.icing.proto.SnippetMatchProto;
-import com.google.android.icing.proto.SnippetProto;
-
-import java.util.ArrayList;
-import java.util.Iterator;
-import java.util.List;
-import java.util.NoSuchElementException;
-
-/**
- * SearchResults are a list of results that are returned from a query. Each result from this
- * list contains a document and may contain other fields like snippets based on request.
- * This iterator class is not thread safe.
- * @hide
- */
-public final class SearchResults implements Iterator<SearchResults.Result> {
-
- private final SearchResultProto mSearchResultProto;
- private int mNextIdx;
-
- /** @hide */
- public SearchResults(SearchResultProto searchResultProto) {
- mSearchResultProto = searchResultProto;
- }
-
- @Override
- public boolean hasNext() {
- return mNextIdx < mSearchResultProto.getResultsCount();
- }
-
- @NonNull
- @Override
- public Result next() {
- if (!hasNext()) {
- throw new NoSuchElementException();
- }
- Result result = new Result(mSearchResultProto.getResults(mNextIdx));
- mNextIdx++;
- return result;
- }
-
-
-
- /**
- * This class represents the result obtained from the query. It will contain the document which
- * which matched the specified query string and specifications.
- * @hide
- */
- public static final class Result {
- private final SearchResultProto.ResultProto mResultProto;
-
- @Nullable
- private AppSearchDocument mDocument;
-
- private Result(SearchResultProto.ResultProto resultProto) {
- mResultProto = resultProto;
- }
-
- /**
- * Contains the matching {@link AppSearchDocument}.
- * @return Document object which matched the query.
- * @hide
- */
- @NonNull
- public AppSearchDocument getDocument() {
- if (mDocument == null) {
- mDocument = new AppSearchDocument(mResultProto.getDocument());
- }
- return mDocument;
- }
-
- /**
- * Contains a list of Snippets that matched the request. Only populated when requested in
- * {@link SearchSpec.Builder#setMaxSnippetSize(int)}.
- * @return List of matches based on {@link SearchSpec}, if snippeting is disabled and this
- * method is called it will return {@code null}. Users can also restrict snippet population
- * using {@link SearchSpec.Builder#setNumToSnippet} and
- * {@link SearchSpec.Builder#setNumMatchesPerProperty}, for all results after that value
- * this method will return {@code null}.
- * @hide
- */
- // TODO(sidchhabra): Replace Document with proper constructor.
- @Nullable
- public List<MatchInfo> getMatchInfo() {
- if (!mResultProto.hasSnippet()) {
- return null;
- }
- AppSearchDocument document = getDocument();
- List<MatchInfo> matchList = new ArrayList<>();
- for (Iterator entryProtoIterator = mResultProto.getSnippet()
- .getEntriesList().iterator(); entryProtoIterator.hasNext(); ) {
- SnippetProto.EntryProto entry = (SnippetProto.EntryProto) entryProtoIterator.next();
- for (Iterator snippetMatchProtoIterator = entry.getSnippetMatchesList().iterator();
- snippetMatchProtoIterator.hasNext(); ) {
- matchList.add(new MatchInfo(entry.getPropertyName(),
- (SnippetMatchProto) snippetMatchProtoIterator.next(), document));
- }
- }
- return matchList;
- }
- }
-
- @Override
- public String toString() {
- return mSearchResultProto.toString();
- }
-}
diff --git a/apex/appsearch/framework/java/android/app/appsearch/SearchSpec.java b/apex/appsearch/framework/java/android/app/appsearch/SearchSpec.java
deleted file mode 100644
index c276ae1fe45e..000000000000
--- a/apex/appsearch/framework/java/android/app/appsearch/SearchSpec.java
+++ /dev/null
@@ -1,260 +0,0 @@
-/*
- * Copyright (C) 2020 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.app.appsearch;
-
-import android.annotation.IntDef;
-import android.annotation.NonNull;
-
-import com.google.android.icing.proto.ResultSpecProto;
-import com.google.android.icing.proto.ScoringSpecProto;
-import com.google.android.icing.proto.SearchSpecProto;
-import com.google.android.icing.proto.TermMatchType;
-
-import java.lang.annotation.Retention;
-import java.lang.annotation.RetentionPolicy;
-
-
-/**
- * This class represents the specification logic for AppSearch. It can be used to set the type of
- * search, like prefix or exact only or apply filters to search for a specific schema type only etc.
- * @hide
- */
-// TODO(sidchhabra) : AddResultSpec fields for Snippets etc.
-public final class SearchSpec {
-
- private final SearchSpecProto mSearchSpecProto;
- private final ResultSpecProto mResultSpecProto;
- private final ScoringSpecProto mScoringSpecProto;
-
- private SearchSpec(@NonNull SearchSpecProto searchSpecProto,
- @NonNull ResultSpecProto resultSpecProto, @NonNull ScoringSpecProto scoringSpecProto) {
- mSearchSpecProto = searchSpecProto;
- mResultSpecProto = resultSpecProto;
- mScoringSpecProto = scoringSpecProto;
- }
-
- /** Creates a new {@link SearchSpec.Builder}. */
- @NonNull
- public static SearchSpec.Builder newBuilder() {
- return new SearchSpec.Builder();
- }
-
- /** @hide */
- @NonNull
- SearchSpecProto getSearchSpecProto() {
- return mSearchSpecProto;
- }
-
- /** @hide */
- @NonNull
- ResultSpecProto getResultSpecProto() {
- return mResultSpecProto;
- }
-
- /** @hide */
- @NonNull
- ScoringSpecProto getScoringSpecProto() {
- return mScoringSpecProto;
- }
-
- /** Term Match Type for the query. */
- // NOTE: The integer values of these constants must match the proto enum constants in
- // {@link com.google.android.icing.proto.SearchSpecProto.termMatchType}
- @IntDef(prefix = {"TERM_MATCH_TYPE_"}, value = {
- TERM_MATCH_TYPE_EXACT_ONLY,
- TERM_MATCH_TYPE_PREFIX
- })
- @Retention(RetentionPolicy.SOURCE)
- public @interface TermMatchTypeCode {}
-
- /**
- * Query terms will only match exact tokens in the index.
- * <p>Ex. A query term "foo" will only match indexed token "foo", and not "foot" or "football".
- */
- public static final int TERM_MATCH_TYPE_EXACT_ONLY = 1;
- /**
- * Query terms will match indexed tokens when the query term is a prefix of the token.
- * <p>Ex. A query term "foo" will match indexed tokens like "foo", "foot", and "football".
- */
- public static final int TERM_MATCH_TYPE_PREFIX = 2;
-
- /** Ranking Strategy for query result.*/
- // NOTE: The integer values of these constants must match the proto enum constants in
- // {@link ScoringSpecProto.RankingStrategy.Code }
- @IntDef(prefix = {"RANKING_STRATEGY_"}, value = {
- RANKING_STRATEGY_NONE,
- RANKING_STRATEGY_DOCUMENT_SCORE,
- RANKING_STRATEGY_CREATION_TIMESTAMP
- })
- @Retention(RetentionPolicy.SOURCE)
- public @interface RankingStrategyCode {}
-
- /** No Ranking, results are returned in arbitrary order.*/
- public static final int RANKING_STRATEGY_NONE = 0;
- /** Ranked by app-provided document scores. */
- public static final int RANKING_STRATEGY_DOCUMENT_SCORE = 1;
- /** Ranked by document creation timestamps. */
- public static final int RANKING_STRATEGY_CREATION_TIMESTAMP = 2;
-
- /** Order for query result.*/
- // NOTE: The integer values of these constants must match the proto enum constants in
- // {@link ScoringSpecProto.Order.Code }
- @IntDef(prefix = {"ORDER_"}, value = {
- ORDER_DESCENDING,
- ORDER_ASCENDING
- })
- @Retention(RetentionPolicy.SOURCE)
- public @interface OrderCode {}
-
- /** Search results will be returned in a descending order. */
- public static final int ORDER_DESCENDING = 0;
- /** Search results will be returned in an ascending order. */
- public static final int ORDER_ASCENDING = 1;
-
- /** Builder for {@link SearchSpec objects}. */
- public static final class Builder {
-
- private final SearchSpecProto.Builder mSearchSpecBuilder = SearchSpecProto.newBuilder();
- private final ResultSpecProto.Builder mResultSpecBuilder = ResultSpecProto.newBuilder();
- private final ScoringSpecProto.Builder mScoringSpecBuilder = ScoringSpecProto.newBuilder();
- private final ResultSpecProto.SnippetSpecProto.Builder mSnippetSpecBuilder =
- ResultSpecProto.SnippetSpecProto.newBuilder();
-
- private Builder() {
- }
-
- /**
- * Indicates how the query terms should match {@link TermMatchTypeCode} in the index.
- */
- @NonNull
- public Builder setTermMatchType(@TermMatchTypeCode int termMatchTypeCode) {
- TermMatchType.Code termMatchTypeCodeProto =
- TermMatchType.Code.forNumber(termMatchTypeCode);
- if (termMatchTypeCodeProto == null) {
- throw new IllegalArgumentException("Invalid term match type: "
- + termMatchTypeCode);
- }
- mSearchSpecBuilder.setTermMatchType(termMatchTypeCodeProto);
- return this;
- }
-
- /**
- * Adds a Schema type filter to {@link SearchSpec} Entry. Only search for documents that
- * have the specified schema types.
- * <p>If unset, the query will search over all schema types.
- */
- @NonNull
- public Builder setSchemaTypes(@NonNull String... schemaTypes) {
- for (String schemaType : schemaTypes) {
- mSearchSpecBuilder.addSchemaTypeFilters(schemaType);
- }
- return this;
- }
-
- /** Sets the maximum number of results to retrieve from the query */
- @NonNull
- public SearchSpec.Builder setNumToRetrieve(int numToRetrieve) {
- mResultSpecBuilder.setNumToRetrieve(numToRetrieve);
- return this;
- }
-
- /** Sets ranking strategy for AppSearch results.*/
- @NonNull
- public Builder setRankingStrategy(@RankingStrategyCode int rankingStrategy) {
- ScoringSpecProto.RankingStrategy.Code rankingStrategyCodeProto =
- ScoringSpecProto.RankingStrategy.Code.forNumber(rankingStrategy);
- if (rankingStrategyCodeProto == null) {
- throw new IllegalArgumentException("Invalid result ranking strategy: "
- + rankingStrategyCodeProto);
- }
- mScoringSpecBuilder.setRankBy(rankingStrategyCodeProto);
- return this;
- }
-
- /**
- * Indicates the order of returned search results, the default is DESC, meaning that results
- * with higher scores come first.
- * <p>This order field will be ignored if RankingStrategy = {@code RANKING_STRATEGY_NONE}.
- */
- @NonNull
- public Builder setOrder(@OrderCode int order) {
- ScoringSpecProto.Order.Code orderCodeProto =
- ScoringSpecProto.Order.Code.forNumber(order);
- if (orderCodeProto == null) {
- throw new IllegalArgumentException("Invalid result ranking order: "
- + orderCodeProto);
- }
- mScoringSpecBuilder.setOrderBy(orderCodeProto);
- return this;
- }
-
- /**
- * Only the first {@code numToSnippet} documents based on the ranking strategy
- * will have snippet information provided.
- * <p>If set to 0 (default), snippeting is disabled and
- * {@link SearchResults.Result#getMatchInfo} will return {@code null} for that result.
- */
- @NonNull
- public SearchSpec.Builder setNumToSnippet(int numToSnippet) {
- mSnippetSpecBuilder.setNumToSnippet(numToSnippet);
- return this;
- }
-
- /**
- * Only the first {@code numMatchesPerProperty} matches for a every property of
- * {@link AppSearchDocument} will contain snippet information.
- * <p>If set to 0, snippeting is disabled and {@link SearchResults.Result#getMatchInfo}
- * will return {@code null} for that result.
- */
- @NonNull
- public SearchSpec.Builder setNumMatchesPerProperty(int numMatchesPerProperty) {
- mSnippetSpecBuilder.setNumMatchesPerProperty(numMatchesPerProperty);
- return this;
- }
-
- /**
- * Sets {@code maxSnippetSize}, the maximum snippet size. Snippet windows start at
- * {@code maxSnippetSize/2} bytes before the middle of the matching token and end at
- * {@code maxSnippetSize/2} bytes after the middle of the matching token. It respects
- * token boundaries, therefore the returned window may be smaller than requested.
- * <p> Setting {@code maxSnippetSize} to 0 will disable windowing and an empty string will
- * be returned. If matches enabled is also set to false, then snippeting is disabled.
- * <p>Ex. {@code maxSnippetSize} = 16. "foo bar baz bat rat" with a query of "baz" will
- * return a window of "bar baz bat" which is only 11 bytes long.
- */
- @NonNull
- public SearchSpec.Builder setMaxSnippetSize(int maxSnippetSize) {
- mSnippetSpecBuilder.setMaxWindowBytes(maxSnippetSize);
- return this;
- }
-
- /**
- * Constructs a new {@link SearchSpec} from the contents of this builder.
- *
- * <p>After calling this method, the builder must no longer be used.
- */
- @NonNull
- public SearchSpec build() {
- if (mSearchSpecBuilder.getTermMatchType() == TermMatchType.Code.UNKNOWN) {
- throw new IllegalSearchSpecException("Missing termMatchType field.");
- }
- mResultSpecBuilder.setSnippetSpec(mSnippetSpecBuilder);
- return new SearchSpec(mSearchSpecBuilder.build(), mResultSpecBuilder.build(),
- mScoringSpecBuilder.build());
- }
- }
-}
diff --git a/apex/appsearch/service/Android.bp b/apex/appsearch/service/Android.bp
deleted file mode 100644
index 04f385e8c6f6..000000000000
--- a/apex/appsearch/service/Android.bp
+++ /dev/null
@@ -1,24 +0,0 @@
-// Copyright (C) 2019 The Android Open Source Project
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-java_library {
- name: "service-appsearch",
- installable: true,
- srcs: ["java/**/*.java"],
- libs: [
- "framework",
- "framework-appsearch",
- "services.core",
- ],
- apex_available: ["com.android.appsearch"],
-}
diff --git a/apex/appsearch/service/java/com/android/server/appsearch/AppSearchManagerService.java b/apex/appsearch/service/java/com/android/server/appsearch/AppSearchManagerService.java
deleted file mode 100644
index 6293ee7059e5..000000000000
--- a/apex/appsearch/service/java/com/android/server/appsearch/AppSearchManagerService.java
+++ /dev/null
@@ -1,125 +0,0 @@
-/*
- * Copyright (C) 2020 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package com.android.server.appsearch;
-
-import android.annotation.NonNull;
-import android.app.appsearch.AppSearchBatchResult;
-import android.app.appsearch.IAppSearchManager;
-import android.content.Context;
-import android.os.Binder;
-import android.os.UserHandle;
-
-import com.android.internal.infra.AndroidFuture;
-import com.android.internal.util.Preconditions;
-import com.android.server.SystemService;
-import com.android.server.appsearch.impl.AppSearchImpl;
-import com.android.server.appsearch.impl.FakeIcing;
-import com.android.server.appsearch.impl.ImplInstanceManager;
-
-import com.google.android.icing.proto.DocumentProto;
-import com.google.android.icing.proto.SchemaProto;
-import com.google.android.icing.proto.SearchResultProto;
-import com.google.android.icing.proto.SearchSpecProto;
-import com.google.android.icing.protobuf.InvalidProtocolBufferException;
-
-import java.util.List;
-
-/**
- * TODO(b/142567528): add comments when implement this class
- */
-public class AppSearchManagerService extends SystemService {
-
- public AppSearchManagerService(Context context) {
- super(context);
- mFakeIcing = new FakeIcing();
- }
-
- private final FakeIcing mFakeIcing;
-
- @Override
- public void onStart() {
- publishBinderService(Context.APP_SEARCH_SERVICE, new Stub());
- }
-
- private class Stub extends IAppSearchManager.Stub {
- @Override
- public void setSchema(byte[] schemaBytes, boolean forceOverride, AndroidFuture callback) {
- Preconditions.checkNotNull(schemaBytes);
- Preconditions.checkNotNull(callback);
- int callingUid = Binder.getCallingUidOrThrow();
- int callingUserId = UserHandle.getUserId(callingUid);
- long callingIdentity = Binder.clearCallingIdentity();
- try {
- SchemaProto schema = SchemaProto.parseFrom(schemaBytes);
- AppSearchImpl impl = ImplInstanceManager.getInstance(getContext(), callingUserId);
- impl.setSchema(callingUid, schema, forceOverride);
- callback.complete(null);
- } catch (Throwable t) {
- callback.completeExceptionally(t);
- } finally {
- Binder.restoreCallingIdentity(callingIdentity);
- }
- }
-
- @Override
- public void putDocuments(
- List documentsBytes, AndroidFuture<AppSearchBatchResult> callback) {
- Preconditions.checkNotNull(documentsBytes);
- Preconditions.checkNotNull(callback);
- int callingUid = Binder.getCallingUidOrThrow();
- int callingUserId = UserHandle.getUserId(callingUid);
- long callingIdentity = Binder.clearCallingIdentity();
- try {
- AppSearchImpl impl = ImplInstanceManager.getInstance(getContext(), callingUserId);
- AppSearchBatchResult.Builder<String, Void> resultBuilder =
- AppSearchBatchResult.newBuilder();
- for (int i = 0; i < documentsBytes.size(); i++) {
- byte[] documentBytes = (byte[]) documentsBytes.get(i);
- DocumentProto document = DocumentProto.parseFrom(documentBytes);
- try {
- impl.putDocument(callingUid, document);
- resultBuilder.setSuccess(document.getUri(), /*value=*/ null);
- } catch (Throwable t) {
- resultBuilder.setFailure(document.getUri(), t);
- }
- }
- callback.complete(resultBuilder.build());
- } catch (Throwable t) {
- callback.completeExceptionally(t);
- } finally {
- Binder.restoreCallingIdentity(callingIdentity);
- }
- }
- // TODO(sidchhabra):Init FakeIcing properly.
- // TODO(sidchhabra): Do this in a threadpool.
- @Override
- public void query(@NonNull byte[] searchSpec, @NonNull byte[] resultSpec,
- @NonNull byte[] scoringSpec, AndroidFuture callback) {
- Preconditions.checkNotNull(searchSpec);
- Preconditions.checkNotNull(resultSpec);
- Preconditions.checkNotNull(scoringSpec);
- SearchSpecProto searchSpecProto = null;
- try {
- searchSpecProto = SearchSpecProto.parseFrom(searchSpec);
- } catch (InvalidProtocolBufferException e) {
- throw new RuntimeException(e);
- }
- SearchResultProto searchResults =
- mFakeIcing.query(searchSpecProto.getQuery());
- callback.complete(searchResults.toByteArray());
- }
- }
-}
diff --git a/apex/appsearch/service/java/com/android/server/appsearch/TEST_MAPPING b/apex/appsearch/service/java/com/android/server/appsearch/TEST_MAPPING
deleted file mode 100644
index ca5b8841ea49..000000000000
--- a/apex/appsearch/service/java/com/android/server/appsearch/TEST_MAPPING
+++ /dev/null
@@ -1,23 +0,0 @@
-{
- "presubmit": [
- {
- "name": "CtsAppSearchTestCases"
- },
- {
- "name": "FrameworksServicesTests",
- "options": [
- {
- "include-filter": "com.android.server.appsearch"
- }
- ]
- },
- {
- "name": "FrameworksCoreTests",
- "options": [
- {
- "include-filter": "android.app.appsearch"
- }
- ]
- }
- ]
-}
diff --git a/apex/appsearch/service/java/com/android/server/appsearch/impl/AppSearchImpl.java b/apex/appsearch/service/java/com/android/server/appsearch/impl/AppSearchImpl.java
deleted file mode 100644
index 04b4b1427328..000000000000
--- a/apex/appsearch/service/java/com/android/server/appsearch/impl/AppSearchImpl.java
+++ /dev/null
@@ -1,168 +0,0 @@
-/*
- * Copyright (C) 2019 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.server.appsearch.impl;
-
-import android.annotation.NonNull;
-import android.annotation.UserIdInt;
-import android.content.Context;
-
-import com.android.internal.annotations.VisibleForTesting;
-
-import com.google.android.icing.proto.DocumentProto;
-import com.google.android.icing.proto.PropertyConfigProto;
-import com.google.android.icing.proto.PropertyProto;
-import com.google.android.icing.proto.SchemaProto;
-import com.google.android.icing.proto.SchemaTypeConfigProto;
-
-/**
- * Manages interaction with {@link FakeIcing} and other components to implement AppSearch
- * functionality.
- */
-public final class AppSearchImpl {
- private final Context mContext;
- private final @UserIdInt int mUserId;
- private final FakeIcing mFakeIcing = new FakeIcing();
-
- AppSearchImpl(@NonNull Context context, @UserIdInt int userId) {
- mContext = context;
- mUserId = userId;
- }
-
- /**
- * Updates the AppSearch schema for this app.
- *
- * @param callingUid The uid of the app calling AppSearch.
- * @param origSchema The schema to set for this app.
- * @param forceOverride Whether to force-apply the schema even if it is incompatible. Documents
- * which do not comply with the new schema will be deleted.
- */
- public void setSchema(int callingUid, @NonNull SchemaProto origSchema, boolean forceOverride) {
- // Rewrite schema type names to include the calling app's package and uid.
- String typePrefix = getTypePrefix(callingUid);
- SchemaProto.Builder schemaBuilder = origSchema.toBuilder();
- rewriteSchemaTypes(typePrefix, schemaBuilder);
-
- // TODO(b/145635424): Save in schema type map
- // TODO(b/145635424): Apply the schema to Icing and report results
- }
-
- /**
- * Rewrites all types mentioned in the given {@code schemaBuilder} to prepend
- * {@code typePrefix}.
- *
- * @param typePrefix The prefix to add
- * @param schemaBuilder The schema to mutate
- */
- @VisibleForTesting
- void rewriteSchemaTypes(
- @NonNull String typePrefix, @NonNull SchemaProto.Builder schemaBuilder) {
- for (int typeIdx = 0; typeIdx < schemaBuilder.getTypesCount(); typeIdx++) {
- SchemaTypeConfigProto.Builder typeConfigBuilder =
- schemaBuilder.getTypes(typeIdx).toBuilder();
-
- // Rewrite SchemaProto.types.schema_type
- String newSchemaType = typePrefix + typeConfigBuilder.getSchemaType();
- typeConfigBuilder.setSchemaType(newSchemaType);
-
- // Rewrite SchemaProto.types.properties.schema_type
- for (int propertyIdx = 0;
- propertyIdx < typeConfigBuilder.getPropertiesCount();
- propertyIdx++) {
- PropertyConfigProto.Builder propertyConfigBuilder =
- typeConfigBuilder.getProperties(propertyIdx).toBuilder();
- if (!propertyConfigBuilder.getSchemaType().isEmpty()) {
- String newPropertySchemaType =
- typePrefix + propertyConfigBuilder.getSchemaType();
- propertyConfigBuilder.setSchemaType(newPropertySchemaType);
- typeConfigBuilder.setProperties(propertyIdx, propertyConfigBuilder);
- }
- }
-
- schemaBuilder.setTypes(typeIdx, typeConfigBuilder);
- }
- }
-
- /**
- * Adds a document to the AppSearch index.
- *
- * @param callingUid The uid of the app calling AppSearch.
- * @param origDocument The document to index.
- */
- public void putDocument(int callingUid, @NonNull DocumentProto origDocument) {
- // Rewrite the type names to include the app's prefix
- String typePrefix = getTypePrefix(callingUid);
- DocumentProto.Builder documentBuilder = origDocument.toBuilder();
- rewriteDocumentTypes(typePrefix, documentBuilder);
- mFakeIcing.put(documentBuilder.build());
- }
-
- /**
- * Rewrites all types mentioned anywhere in {@code documentBuilder} to prepend
- * {@code typePrefix}.
- *
- * @param typePrefix The prefix to add
- * @param documentBuilder The document to mutate
- */
- @VisibleForTesting
- void rewriteDocumentTypes(
- @NonNull String typePrefix,
- @NonNull DocumentProto.Builder documentBuilder) {
- // Rewrite the type name to include the app's prefix
- String newSchema = typePrefix + documentBuilder.getSchema();
- documentBuilder.setSchema(newSchema);
-
- // Add namespace. If we ever allow users to set their own namespaces, this will have
- // to change to prepend the prefix instead of setting the whole namespace. We will also have
- // to store the namespaces in a map similar to the type map so we can rewrite queries with
- // empty namespaces.
- documentBuilder.setNamespace(typePrefix);
-
- // Recurse into derived documents
- for (int propertyIdx = 0;
- propertyIdx < documentBuilder.getPropertiesCount();
- propertyIdx++) {
- int documentCount = documentBuilder.getProperties(propertyIdx).getDocumentValuesCount();
- if (documentCount > 0) {
- PropertyProto.Builder propertyBuilder =
- documentBuilder.getProperties(propertyIdx).toBuilder();
- for (int documentIdx = 0; documentIdx < documentCount; documentIdx++) {
- DocumentProto.Builder derivedDocumentBuilder =
- propertyBuilder.getDocumentValues(documentIdx).toBuilder();
- rewriteDocumentTypes(typePrefix, derivedDocumentBuilder);
- propertyBuilder.setDocumentValues(documentIdx, derivedDocumentBuilder);
- }
- documentBuilder.setProperties(propertyIdx, propertyBuilder);
- }
- }
- }
-
- /**
- * Returns a type prefix in a format like {@code com.example.package@1000/} or
- * {@code com.example.sharedname:5678@1000/}.
- */
- @NonNull
- private String getTypePrefix(int callingUid) {
- // For regular apps, this call will return the package name. If callingUid is an
- // android:sharedUserId, this value may be another type of name and have a :uid suffix.
- String callingUidName = mContext.getPackageManager().getNameForUid(callingUid);
- if (callingUidName == null) {
- // Not sure how this is possible --- maybe app was uninstalled?
- throw new IllegalStateException("Failed to look up package name for uid " + callingUid);
- }
- return callingUidName + "@" + mUserId + "/";
- }
-}
diff --git a/apex/appsearch/service/java/com/android/server/appsearch/impl/FakeIcing.java b/apex/appsearch/service/java/com/android/server/appsearch/impl/FakeIcing.java
deleted file mode 100644
index d07ef4bc3bf5..000000000000
--- a/apex/appsearch/service/java/com/android/server/appsearch/impl/FakeIcing.java
+++ /dev/null
@@ -1,169 +0,0 @@
-/*
- * Copyright (C) 2019 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.server.appsearch.impl;
-
-import android.annotation.NonNull;
-import android.annotation.Nullable;
-import android.util.ArrayMap;
-import android.util.ArraySet;
-import android.util.SparseArray;
-
-import com.google.android.icing.proto.DocumentProto;
-import com.google.android.icing.proto.PropertyProto;
-import com.google.android.icing.proto.SearchResultProto;
-import com.google.android.icing.proto.StatusProto;
-
-import java.util.Locale;
-import java.util.Map;
-import java.util.Set;
-import java.util.concurrent.atomic.AtomicInteger;
-
-/**
- * Fake in-memory implementation of the Icing key-value store and reverse index.
- * <p>
- * Currently, only queries by single exact term are supported. There is no support for persistence,
- * namespaces, i18n tokenization, or schema.
- */
-public class FakeIcing {
- private final AtomicInteger mNextDocId = new AtomicInteger();
- private final Map<String, Integer> mUriToDocIdMap = new ArrayMap<>();
- /** Array of Documents where index into the array is the docId. */
- private final SparseArray<DocumentProto> mDocStore = new SparseArray<>();
- /** Map of term to posting-list (the set of DocIds containing that term). */
- private final Map<String, Set<Integer>> mIndex = new ArrayMap<>();
-
- /**
- * Inserts a document into the index.
- *
- * @param document The document to insert.
- */
- public void put(@NonNull DocumentProto document) {
- String uri = document.getUri();
-
- // Update mDocIdMap
- Integer docId = mUriToDocIdMap.get(uri);
- if (docId != null) {
- // Delete the old doc
- mDocStore.remove(docId);
- }
-
- // Allocate a new docId
- docId = mNextDocId.getAndIncrement();
- mUriToDocIdMap.put(uri, docId);
-
- // Update mDocStore
- mDocStore.put(docId, document);
-
- // Update mIndex
- indexDocument(docId, document);
- }
-
- /**
- * Retrieves a document from the index.
- *
- * @param uri The URI of the document to retrieve.
- * @return The body of the document, or {@code null} if no such document exists.
- */
- @Nullable
- public DocumentProto get(@NonNull String uri) {
- Integer docId = mUriToDocIdMap.get(uri);
- if (docId == null) {
- return null;
- }
- return mDocStore.get(docId);
- }
-
- /**
- * Returns documents containing the given term.
- *
- * @param term A single exact term to look up in the index.
- * @return A {@link SearchResultProto} containing the matching documents, which may have no
- * results if no documents match.
- */
- @NonNull
- public SearchResultProto query(@NonNull String term) {
- String normTerm = normalizeString(term);
- Set<Integer> docIds = mIndex.get(normTerm);
- SearchResultProto.Builder results = SearchResultProto.newBuilder()
- .setStatus(StatusProto.newBuilder().setCode(StatusProto.Code.OK));
- if (docIds == null || docIds.isEmpty()) {
- return results.build();
- }
-
- for (int docId : docIds) {
- DocumentProto document = mDocStore.get(docId);
- if (document != null) {
- results.addResults(
- SearchResultProto.ResultProto.newBuilder().setDocument(document));
- }
- }
- return results.build();
- }
-
- /**
- * Deletes a document by its URI.
- *
- * @param uri The URI of the document to be deleted.
- */
- public void delete(@NonNull String uri) {
- // Update mDocIdMap
- Integer docId = mUriToDocIdMap.get(uri);
- if (docId != null) {
- // Delete the old doc
- mDocStore.remove(docId);
- mUriToDocIdMap.remove(uri);
- }
- }
-
- private void indexDocument(int docId, DocumentProto document) {
- for (PropertyProto property : document.getPropertiesList()) {
- for (String stringValue : property.getStringValuesList()) {
- String[] words = normalizeString(stringValue).split("\\s+");
- for (String word : words) {
- indexTerm(docId, word);
- }
- }
- for (Long longValue : property.getInt64ValuesList()) {
- indexTerm(docId, longValue.toString());
- }
- for (Double doubleValue : property.getDoubleValuesList()) {
- indexTerm(docId, doubleValue.toString());
- }
- for (Boolean booleanValue : property.getBooleanValuesList()) {
- indexTerm(docId, booleanValue.toString());
- }
- // Intentionally skipping bytes values
- for (DocumentProto documentValue : property.getDocumentValuesList()) {
- indexDocument(docId, documentValue);
- }
- }
- }
-
- private void indexTerm(int docId, String term) {
- Set<Integer> postingList = mIndex.get(term);
- if (postingList == null) {
- postingList = new ArraySet<>();
- mIndex.put(term, postingList);
- }
- postingList.add(docId);
- }
-
- /** Strips out punctuation and converts to lowercase. */
- private static String normalizeString(String input) {
- return input.replaceAll("\\p{P}", "").toLowerCase(Locale.getDefault());
- }
-}
diff --git a/apex/appsearch/service/java/com/android/server/appsearch/impl/ImplInstanceManager.java b/apex/appsearch/service/java/com/android/server/appsearch/impl/ImplInstanceManager.java
deleted file mode 100644
index 395e30e89dc0..000000000000
--- a/apex/appsearch/service/java/com/android/server/appsearch/impl/ImplInstanceManager.java
+++ /dev/null
@@ -1,56 +0,0 @@
-/*
- * Copyright (C) 2019 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.server.appsearch.impl;
-
-import android.annotation.NonNull;
-import android.annotation.UserIdInt;
-import android.content.Context;
-import android.util.SparseArray;
-
-/**
- * Manages the lifecycle of instances of {@link AppSearchImpl}.
- *
- * <p>These instances are managed per unique device-user.
- */
-public final class ImplInstanceManager {
- private static final SparseArray<AppSearchImpl> sInstances = new SparseArray<>();
-
- /**
- * Gets an instance of AppSearchImpl for the given user.
- *
- * <p>If no AppSearchImpl instance exists for this user, Icing will be initialized and one will
- * be created.
- *
- * @param context The Android context
- * @param userId The multi-user userId of the device user calling AppSearch
- * @return An initialized {@link AppSearchImpl} for this user
- */
- @NonNull
- public static AppSearchImpl getInstance(@NonNull Context context, @UserIdInt int userId) {
- AppSearchImpl instance = sInstances.get(userId);
- if (instance == null) {
- synchronized (ImplInstanceManager.class) {
- instance = sInstances.get(userId);
- if (instance == null) {
- instance = new AppSearchImpl(context, userId);
- sInstances.put(userId, instance);
- }
- }
- }
- return instance;
- }
-}
diff --git a/apex/blobstore/framework/java/android/app/blob/AccessorInfo.java b/apex/blobstore/framework/java/android/app/blob/AccessorInfo.java
new file mode 100644
index 000000000000..3725ad4a6c09
--- /dev/null
+++ b/apex/blobstore/framework/java/android/app/blob/AccessorInfo.java
@@ -0,0 +1,119 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.app.blob;
+
+import android.annotation.NonNull;
+import android.os.Parcel;
+import android.os.Parcelable;
+
+import java.util.List;
+
+/**
+ * Class to provide information about an accessor of a shared blob.
+ *
+ * @hide
+ */
+public final class AccessorInfo implements Parcelable {
+ private final String mPackageName;
+ private final long mExpiryTimeMs;
+ private final int mDescriptionResId;
+ private final CharSequence mDescription;
+
+ public AccessorInfo(String packageName, long expiryTimeMs,
+ int descriptionResId, CharSequence description) {
+ mPackageName = packageName;
+ mExpiryTimeMs = expiryTimeMs;
+ mDescriptionResId = descriptionResId;
+ mDescription = description;
+ }
+
+ private AccessorInfo(Parcel in) {
+ mPackageName = in.readString();
+ mExpiryTimeMs = in.readLong();
+ mDescriptionResId = in.readInt();
+ mDescription = in.readCharSequence();
+ }
+
+ public String getPackageName() {
+ return mPackageName;
+ }
+
+ public long getExpiryTimeMs() {
+ return mExpiryTimeMs;
+ }
+
+ public int getDescriptionResId() {
+ return mDescriptionResId;
+ }
+
+ public CharSequence getDescription() {
+ return mDescription;
+ }
+
+ @Override
+ public void writeToParcel(@NonNull Parcel dest, int flags) {
+ dest.writeString(mPackageName);
+ dest.writeLong(mExpiryTimeMs);
+ dest.writeInt(mDescriptionResId);
+ dest.writeCharSequence(mDescription);
+ }
+
+ @Override
+ public String toString() {
+ return "AccessorInfo {"
+ + "package: " + mPackageName + ","
+ + "expiryMs: " + mExpiryTimeMs + ","
+ + "descriptionResId: " + mDescriptionResId + ","
+ + "description: " + mDescription + ","
+ + "}";
+ }
+
+ private String toShortString() {
+ return mPackageName;
+ }
+
+ public static String toShortString(List<AccessorInfo> accessors) {
+ final StringBuilder sb = new StringBuilder();
+ sb.append("[");
+ for (int i = 0, size = accessors.size(); i < size; ++i) {
+ sb.append(accessors.get(i).toShortString());
+ sb.append(",");
+ }
+ sb.append("]");
+ return sb.toString();
+ }
+
+ @Override
+ public int describeContents() {
+ return 0;
+ }
+
+ @NonNull
+ public static final Creator<AccessorInfo> CREATOR = new Creator<AccessorInfo>() {
+ @Override
+ @NonNull
+ public AccessorInfo createFromParcel(Parcel source) {
+ return new AccessorInfo(source);
+ }
+
+ @Override
+ @NonNull
+ public AccessorInfo[] newArray(int size) {
+ return new AccessorInfo[size];
+ }
+ };
+}
diff --git a/apex/blobstore/framework/java/android/app/blob/BlobInfo.aidl b/apex/blobstore/framework/java/android/app/blob/BlobInfo.aidl
new file mode 100644
index 000000000000..25497738f685
--- /dev/null
+++ b/apex/blobstore/framework/java/android/app/blob/BlobInfo.aidl
@@ -0,0 +1,19 @@
+/*
+ * Copyright 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package android.app.blob;
+
+/** {@hide} */
+parcelable BlobInfo; \ No newline at end of file
diff --git a/apex/blobstore/framework/java/android/app/blob/BlobInfo.java b/apex/blobstore/framework/java/android/app/blob/BlobInfo.java
new file mode 100644
index 000000000000..9746dd023002
--- /dev/null
+++ b/apex/blobstore/framework/java/android/app/blob/BlobInfo.java
@@ -0,0 +1,109 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.app.blob;
+
+import android.annotation.NonNull;
+import android.os.Parcel;
+import android.os.Parcelable;
+
+import java.util.Collections;
+import java.util.List;
+
+/**
+ * Class to provide information about a shared blob.
+ *
+ * @hide
+ */
+public final class BlobInfo implements Parcelable {
+ private final long mId;
+ private final long mExpiryTimeMs;
+ private final CharSequence mLabel;
+ private final List<AccessorInfo> mAccessors;
+
+ public BlobInfo(long id, long expiryTimeMs, CharSequence label,
+ List<AccessorInfo> accessors) {
+ mId = id;
+ mExpiryTimeMs = expiryTimeMs;
+ mLabel = label;
+ mAccessors = accessors;
+ }
+
+ private BlobInfo(Parcel in) {
+ mId = in.readLong();
+ mExpiryTimeMs = in.readLong();
+ mLabel = in.readCharSequence();
+ mAccessors = in.readArrayList(null /* classloader */);
+ }
+
+ public long getId() {
+ return mId;
+ }
+
+ public long getExpiryTimeMs() {
+ return mExpiryTimeMs;
+ }
+
+ public CharSequence getLabel() {
+ return mLabel;
+ }
+
+ public List<AccessorInfo> getAccessors() {
+ return Collections.unmodifiableList(mAccessors);
+ }
+
+ @Override
+ public void writeToParcel(@NonNull Parcel dest, int flags) {
+ dest.writeLong(mId);
+ dest.writeLong(mExpiryTimeMs);
+ dest.writeCharSequence(mLabel);
+ dest.writeList(mAccessors);
+ }
+
+ @Override
+ public String toString() {
+ return toShortString();
+ }
+
+ private String toShortString() {
+ return "BlobInfo {"
+ + "id: " + mId + ","
+ + "expiryMs: " + mExpiryTimeMs + ","
+ + "label: " + mLabel + ","
+ + "accessors: " + AccessorInfo.toShortString(mAccessors) + ","
+ + "}";
+ }
+
+ @Override
+ public int describeContents() {
+ return 0;
+ }
+
+ @NonNull
+ public static final Creator<BlobInfo> CREATOR = new Creator<BlobInfo>() {
+ @Override
+ @NonNull
+ public BlobInfo createFromParcel(Parcel source) {
+ return new BlobInfo(source);
+ }
+
+ @Override
+ @NonNull
+ public BlobInfo[] newArray(int size) {
+ return new BlobInfo[size];
+ }
+ };
+}
diff --git a/apex/blobstore/framework/java/android/app/blob/BlobStoreManager.java b/apex/blobstore/framework/java/android/app/blob/BlobStoreManager.java
index f53f1f19aea7..814ab6dbd7fd 100644
--- a/apex/blobstore/framework/java/android/app/blob/BlobStoreManager.java
+++ b/apex/blobstore/framework/java/android/app/blob/BlobStoreManager.java
@@ -22,16 +22,19 @@ import android.annotation.IdRes;
import android.annotation.IntRange;
import android.annotation.NonNull;
import android.annotation.SystemService;
+import android.annotation.TestApi;
import android.content.Context;
import android.os.ParcelFileDescriptor;
import android.os.ParcelableException;
import android.os.RemoteCallback;
import android.os.RemoteException;
+import android.os.UserHandle;
import com.android.internal.util.function.pooled.PooledLambda;
import java.io.Closeable;
import java.io.IOException;
+import java.util.List;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.Executor;
import java.util.concurrent.TimeUnit;
@@ -212,7 +215,7 @@ public class BlobStoreManager {
}
/**
- * Delete an existing session and any data that was written to that session so far.
+ * Abandons an existing session and deletes any data that was written to that session so far.
*
* @param sessionId a unique id obtained via {@link #createSession(BlobHandle)} that
* represents a particular session.
@@ -221,9 +224,9 @@ public class BlobStoreManager {
* @throws SecurityException when the caller does not own the session, or
* the session does not exist or is invalid.
*/
- public void deleteSession(@IntRange(from = 1) long sessionId) throws IOException {
+ public void abandonSession(@IntRange(from = 1) long sessionId) throws IOException {
try {
- mService.deleteSession(sessionId, mContext.getOpPackageName());
+ mService.abandonSession(sessionId, mContext.getOpPackageName());
} catch (ParcelableException e) {
e.maybeRethrow(IOException.class);
throw new RuntimeException(e);
@@ -269,6 +272,9 @@ public class BlobStoreManager {
* <p> When an app acquires a lease on a blob, the System will try to keep this
* blob around but note that it can still be deleted if it was requested by the user.
*
+ * <p> In case the resource name for the {@code descriptionResId} is modified as part of
+ * an app update, apps should re-acquire the lease with the new resource id.
+ *
* @param blobHandle the {@link BlobHandle} representing the blob that the caller wants to
* acquire a lease for.
* @param descriptionResId the resource id for a short description string that can be surfaced
@@ -380,6 +386,9 @@ public class BlobStoreManager {
* <p> When an app acquires a lease on a blob, the System will try to keep this
* blob around but note that it can still be deleted if it was requested by the user.
*
+ * <p> In case the resource name for the {@code descriptionResId} is modified as part of
+ * an app update, apps should re-acquire the lease with the new resource id.
+ *
* @param blobHandle the {@link BlobHandle} representing the blob that the caller wants to
* acquire a lease for.
* @param descriptionResId the resource id for a short description string that can be surfaced
@@ -445,13 +454,13 @@ public class BlobStoreManager {
}
/**
- * Release all active leases to the blob represented by {@code blobHandle} which are
+ * Release any active lease to the blob represented by {@code blobHandle} which is
* currently held by the caller.
*
* @param blobHandle the {@link BlobHandle} representing the blob that the caller wants to
- * release the leases for.
+ * release the lease for.
*
- * @throws IOException when there is an I/O error while releasing the releases to the blob.
+ * @throws IOException when there is an I/O error while releasing the release to the blob.
* @throws SecurityException when the blob represented by the {@code blobHandle} does not
* exist or the caller does not have access to it.
* @throws IllegalArgumentException when {@code blobHandle} is invalid.
@@ -472,6 +481,7 @@ public class BlobStoreManager {
*
* @hide
*/
+ @TestApi
public void waitForIdle(long timeoutMillis) throws InterruptedException, TimeoutException {
try {
final CountDownLatch countDownLatch = new CountDownLatch(1);
@@ -486,6 +496,31 @@ public class BlobStoreManager {
}
}
+ /** @hide */
+ @NonNull
+ public List<BlobInfo> queryBlobsForUser(@NonNull UserHandle user) throws IOException {
+ try {
+ return mService.queryBlobsForUser(user.getIdentifier());
+ } catch (ParcelableException e) {
+ e.maybeRethrow(IOException.class);
+ throw new RuntimeException(e);
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
+
+ /** @hide */
+ public void deleteBlob(@NonNull BlobInfo blobInfo) throws IOException {
+ try {
+ mService.deleteBlob(blobInfo.getId());
+ } catch (ParcelableException e) {
+ e.maybeRethrow(IOException.class);
+ throw new RuntimeException(e);
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
+
/**
* Represents an ongoing session of a blob's contribution to the blob store managed by the
* system.
@@ -590,7 +625,7 @@ public class BlobStoreManager {
/**
* Close this session. It can be re-opened for writing/reading if it has not been
- * abandoned (using {@link #abandon}) or closed (using {@link #commit}).
+ * abandoned (using {@link #abandon}) or committed (using {@link #commit}).
*
* @throws IOException when there is an I/O error while closing the session.
* @throws SecurityException when the caller is not the owner of the session.
diff --git a/apex/blobstore/framework/java/android/app/blob/IBlobStoreManager.aidl b/apex/blobstore/framework/java/android/app/blob/IBlobStoreManager.aidl
index a85a25c9c4ad..e78381359b41 100644
--- a/apex/blobstore/framework/java/android/app/blob/IBlobStoreManager.aidl
+++ b/apex/blobstore/framework/java/android/app/blob/IBlobStoreManager.aidl
@@ -16,6 +16,7 @@
package android.app.blob;
import android.app.blob.BlobHandle;
+import android.app.blob.BlobInfo;
import android.app.blob.IBlobStoreSession;
import android.os.RemoteCallback;
@@ -24,11 +25,14 @@ interface IBlobStoreManager {
long createSession(in BlobHandle handle, in String packageName);
IBlobStoreSession openSession(long sessionId, in String packageName);
ParcelFileDescriptor openBlob(in BlobHandle handle, in String packageName);
- void deleteSession(long sessionId, in String packageName);
+ void abandonSession(long sessionId, in String packageName);
void acquireLease(in BlobHandle handle, int descriptionResId, in CharSequence description,
long leaseTimeoutMillis, in String packageName);
void releaseLease(in BlobHandle handle, in String packageName);
void waitForIdle(in RemoteCallback callback);
+
+ List<BlobInfo> queryBlobsForUser(int userId);
+ void deleteBlob(long blobId);
} \ No newline at end of file
diff --git a/apex/blobstore/framework/java/android/app/blob/XmlTags.java b/apex/blobstore/framework/java/android/app/blob/XmlTags.java
index 9834d7477838..e64edc393769 100644
--- a/apex/blobstore/framework/java/android/app/blob/XmlTags.java
+++ b/apex/blobstore/framework/java/android/app/blob/XmlTags.java
@@ -51,6 +51,6 @@ public final class XmlTags {
// For leasee
public static final String TAG_LEASEE = "l";
- public static final String ATTR_DESCRIPTION_RES_ID = "rid";
+ public static final String ATTR_DESCRIPTION_RES_NAME = "rn";
public static final String ATTR_DESCRIPTION = "d";
}
diff --git a/apex/blobstore/service/java/com/android/server/blob/BlobMetadata.java b/apex/blobstore/service/java/com/android/server/blob/BlobMetadata.java
index 4a85a69b82d3..970766d2c8a6 100644
--- a/apex/blobstore/service/java/com/android/server/blob/BlobMetadata.java
+++ b/apex/blobstore/service/java/com/android/server/blob/BlobMetadata.java
@@ -16,7 +16,7 @@
package com.android.server.blob;
import static android.app.blob.XmlTags.ATTR_DESCRIPTION;
-import static android.app.blob.XmlTags.ATTR_DESCRIPTION_RES_ID;
+import static android.app.blob.XmlTags.ATTR_DESCRIPTION_RES_NAME;
import static android.app.blob.XmlTags.ATTR_EXPIRY_TIME;
import static android.app.blob.XmlTags.ATTR_ID;
import static android.app.blob.XmlTags.ATTR_PACKAGE;
@@ -30,13 +30,15 @@ import static android.os.Process.INVALID_UID;
import static android.system.OsConstants.O_RDONLY;
import static com.android.server.blob.BlobStoreConfig.TAG;
+import static com.android.server.blob.BlobStoreConfig.XML_VERSION_ADD_DESC_RES_NAME;
import static com.android.server.blob.BlobStoreConfig.XML_VERSION_ADD_STRING_DESC;
+import static com.android.server.blob.BlobStoreUtils.getDescriptionResourceId;
+import static com.android.server.blob.BlobStoreUtils.getPackageResources;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.app.blob.BlobHandle;
import android.content.Context;
-import android.content.pm.PackageManager;
import android.content.res.ResourceId;
import android.content.res.Resources;
import android.os.ParcelFileDescriptor;
@@ -62,6 +64,7 @@ import java.io.File;
import java.io.FileDescriptor;
import java.io.IOException;
import java.util.Objects;
+import java.util.function.Consumer;
class BlobMetadata {
private final Object mMetadataLock = new Object();
@@ -154,7 +157,7 @@ class BlobMetadata {
synchronized (mMetadataLock) {
// We need to override the leasee data, so first remove any existing
// leasee before adding the new one.
- final Leasee leasee = new Leasee(callingPackage, callingUid,
+ final Leasee leasee = new Leasee(mContext, callingPackage, callingUid,
descriptionResId, description, leaseExpiryTimeMillis);
mLeasees.remove(leasee);
mLeasees.add(leasee);
@@ -239,7 +242,7 @@ class BlobMetadata {
return hasOtherLeasees(null, uid);
}
- private boolean isALeasee(@Nullable String packageName, int uid) {
+ boolean isALeasee(@Nullable String packageName, int uid) {
synchronized (mMetadataLock) {
// Check if the package is a leasee of the data blob.
for (int i = 0, size = mLeasees.size(); i < size; ++i) {
@@ -278,6 +281,10 @@ class BlobMetadata {
return false;
}
+ void forEachLeasee(Consumer<Leasee> consumer) {
+ mLeasees.forEach(consumer);
+ }
+
File getBlobFile() {
if (mBlobFile == null) {
mBlobFile = BlobStoreConfig.getBlobFile(mBlobId);
@@ -459,59 +466,103 @@ class BlobMetadata {
}
static final class Leasee extends Accessor {
- public final int descriptionResId;
+ public final String descriptionResEntryName;
public final CharSequence description;
public final long expiryTimeMillis;
- Leasee(String packageName, int uid, int descriptionResId, CharSequence description,
- long expiryTimeMillis) {
+ Leasee(@NonNull Context context, @NonNull String packageName,
+ int uid, int descriptionResId,
+ @Nullable CharSequence description, long expiryTimeMillis) {
super(packageName, uid);
- this.descriptionResId = descriptionResId;
+ final Resources packageResources = getPackageResources(context, packageName,
+ UserHandle.getUserId(uid));
+ this.descriptionResEntryName = getResourceEntryName(packageResources, descriptionResId);
+ this.expiryTimeMillis = expiryTimeMillis;
+ this.description = description == null
+ ? getDescription(packageResources, descriptionResId)
+ : description;
+ }
+
+ Leasee(String packageName, int uid, @Nullable String descriptionResEntryName,
+ @Nullable CharSequence description, long expiryTimeMillis) {
+ super(packageName, uid);
+ this.descriptionResEntryName = descriptionResEntryName;
this.expiryTimeMillis = expiryTimeMillis;
this.description = description;
}
+ @Nullable
+ private static String getResourceEntryName(@Nullable Resources packageResources,
+ int resId) {
+ if (!ResourceId.isValid(resId) || packageResources == null) {
+ return null;
+ }
+ return packageResources.getResourceEntryName(resId);
+ }
+
+ @Nullable
+ private static String getDescription(@NonNull Context context,
+ @NonNull String descriptionResEntryName, @NonNull String packageName, int userId) {
+ if (descriptionResEntryName == null || descriptionResEntryName.isEmpty()) {
+ return null;
+ }
+ final Resources resources = getPackageResources(context, packageName, userId);
+ if (resources == null) {
+ return null;
+ }
+ final int resId = getDescriptionResourceId(resources, descriptionResEntryName,
+ packageName);
+ return resId == Resources.ID_NULL ? null : resources.getString(resId);
+ }
+
+ @Nullable
+ private static String getDescription(@Nullable Resources packageResources,
+ int descriptionResId) {
+ if (!ResourceId.isValid(descriptionResId) || packageResources == null) {
+ return null;
+ }
+ return packageResources.getString(descriptionResId);
+ }
+
boolean isStillValid() {
return expiryTimeMillis == 0 || expiryTimeMillis <= System.currentTimeMillis();
}
- void dump(Context context, IndentingPrintWriter fout) {
+ void dump(@NonNull Context context, @NonNull IndentingPrintWriter fout) {
fout.println("desc: " + getDescriptionToDump(context));
fout.println("expiryMs: " + expiryTimeMillis);
}
- private String getDescriptionToDump(Context context) {
- String desc = null;
- if (ResourceId.isValid(descriptionResId)) {
- try {
- final Resources leaseeRes = context.getPackageManager()
- .getResourcesForApplicationAsUser(
- packageName, UserHandle.getUserId(uid));
- desc = leaseeRes.getString(descriptionResId);
- } catch (PackageManager.NameNotFoundException e) {
- Slog.d(TAG, "Unknown package in user " + UserHandle.getUserId(uid) + ": "
- + packageName, e);
- desc = "<none>";
- }
- } else {
+ @NonNull
+ private String getDescriptionToDump(@NonNull Context context) {
+ String desc = getDescription(context, descriptionResEntryName, packageName,
+ UserHandle.getUserId(uid));
+ if (desc == null) {
desc = description.toString();
}
- return desc;
+ return desc == null ? "<none>" : desc;
}
void writeToXml(@NonNull XmlSerializer out) throws IOException {
XmlUtils.writeStringAttribute(out, ATTR_PACKAGE, packageName);
XmlUtils.writeIntAttribute(out, ATTR_UID, uid);
- XmlUtils.writeIntAttribute(out, ATTR_DESCRIPTION_RES_ID, descriptionResId);
+ XmlUtils.writeStringAttribute(out, ATTR_DESCRIPTION_RES_NAME, descriptionResEntryName);
XmlUtils.writeLongAttribute(out, ATTR_EXPIRY_TIME, expiryTimeMillis);
XmlUtils.writeStringAttribute(out, ATTR_DESCRIPTION, description);
}
@NonNull
- static Leasee createFromXml(@NonNull XmlPullParser in, int version) throws IOException {
+ static Leasee createFromXml(@NonNull XmlPullParser in, int version)
+ throws IOException {
final String packageName = XmlUtils.readStringAttribute(in, ATTR_PACKAGE);
final int uid = XmlUtils.readIntAttribute(in, ATTR_UID);
- final int descriptionResId = XmlUtils.readIntAttribute(in, ATTR_DESCRIPTION_RES_ID);
+ final String descriptionResEntryName;
+ if (version >= XML_VERSION_ADD_DESC_RES_NAME) {
+ descriptionResEntryName = XmlUtils.readStringAttribute(
+ in, ATTR_DESCRIPTION_RES_NAME);
+ } else {
+ descriptionResEntryName = null;
+ }
final long expiryTimeMillis = XmlUtils.readLongAttribute(in, ATTR_EXPIRY_TIME);
final CharSequence description;
if (version >= XML_VERSION_ADD_STRING_DESC) {
@@ -520,7 +571,8 @@ class BlobMetadata {
description = null;
}
- return new Leasee(packageName, uid, descriptionResId, description, expiryTimeMillis);
+ return new Leasee(packageName, uid, descriptionResEntryName,
+ description, expiryTimeMillis);
}
}
diff --git a/apex/blobstore/service/java/com/android/server/blob/BlobStoreConfig.java b/apex/blobstore/service/java/com/android/server/blob/BlobStoreConfig.java
index bcc1610435d9..5e8ea7afaec7 100644
--- a/apex/blobstore/service/java/com/android/server/blob/BlobStoreConfig.java
+++ b/apex/blobstore/service/java/com/android/server/blob/BlobStoreConfig.java
@@ -15,12 +15,23 @@
*/
package com.android.server.blob;
+import static android.provider.DeviceConfig.NAMESPACE_BLOBSTORE;
+import static android.text.format.Formatter.FLAG_IEC_UNITS;
+import static android.text.format.Formatter.formatFileSize;
+import static android.util.TimeUtils.formatDuration;
+
import android.annotation.NonNull;
import android.annotation.Nullable;
+import android.content.Context;
import android.os.Environment;
+import android.provider.DeviceConfig;
+import android.provider.DeviceConfig.Properties;
+import android.util.DataUnit;
import android.util.Log;
import android.util.Slog;
+import com.android.internal.util.IndentingPrintWriter;
+
import java.io.File;
import java.util.concurrent.TimeUnit;
@@ -32,8 +43,9 @@ class BlobStoreConfig {
public static final int XML_VERSION_INIT = 1;
// Added a string variant of lease description.
public static final int XML_VERSION_ADD_STRING_DESC = 2;
+ public static final int XML_VERSION_ADD_DESC_RES_NAME = 3;
- public static final int XML_VERSION_CURRENT = XML_VERSION_ADD_STRING_DESC;
+ public static final int XML_VERSION_CURRENT = XML_VERSION_ADD_DESC_RES_NAME;
private static final String ROOT_DIR_NAME = "blobstore";
private static final String BLOBS_DIR_NAME = "blobs";
@@ -54,6 +66,76 @@ class BlobStoreConfig {
*/
public static final long SESSION_EXPIRY_TIMEOUT_MILLIS = TimeUnit.DAYS.toMillis(7);
+ public static class DeviceConfigProperties {
+ /**
+ * Denotes how low the limit for the amount of data, that an app will be allowed to acquire
+ * a lease on, can be.
+ */
+ public static final String KEY_TOTAL_BYTES_PER_APP_LIMIT_FLOOR =
+ "total_bytes_per_app_limit_floor";
+ public static final long DEFAULT_TOTAL_BYTES_PER_APP_LIMIT_FLOOR =
+ DataUnit.MEBIBYTES.toBytes(300); // 300 MiB
+ public static long TOTAL_BYTES_PER_APP_LIMIT_FLOOR =
+ DEFAULT_TOTAL_BYTES_PER_APP_LIMIT_FLOOR;
+
+ /**
+ * Denotes the maximum amount of data an app can acquire a lease on, in terms of fraction
+ * of total disk space.
+ */
+ public static final String KEY_TOTAL_BYTES_PER_APP_LIMIT_FRACTION =
+ "total_bytes_per_app_limit_fraction";
+ public static final float DEFAULT_TOTAL_BYTES_PER_APP_LIMIT_FRACTION = 0.01f;
+ public static float TOTAL_BYTES_PER_APP_LIMIT_FRACTION =
+ DEFAULT_TOTAL_BYTES_PER_APP_LIMIT_FRACTION;
+
+ static void refresh(Properties properties) {
+ if (!NAMESPACE_BLOBSTORE.equals(properties.getNamespace())) {
+ return;
+ }
+ properties.getKeyset().forEach(key -> {
+ switch (key) {
+ case KEY_TOTAL_BYTES_PER_APP_LIMIT_FLOOR:
+ TOTAL_BYTES_PER_APP_LIMIT_FLOOR = properties.getLong(key,
+ DEFAULT_TOTAL_BYTES_PER_APP_LIMIT_FLOOR);
+ break;
+ case KEY_TOTAL_BYTES_PER_APP_LIMIT_FRACTION:
+ TOTAL_BYTES_PER_APP_LIMIT_FRACTION = properties.getFloat(key,
+ DEFAULT_TOTAL_BYTES_PER_APP_LIMIT_FRACTION);
+ break;
+ default:
+ Slog.wtf(TAG, "Unknown key in device config properties: " + key);
+ }
+ });
+ }
+
+ static void dump(IndentingPrintWriter fout, Context context) {
+ final String dumpFormat = "%s: [cur: %s, def: %s]";
+ fout.println(String.format(dumpFormat, KEY_TOTAL_BYTES_PER_APP_LIMIT_FLOOR,
+ formatFileSize(context, TOTAL_BYTES_PER_APP_LIMIT_FLOOR, FLAG_IEC_UNITS),
+ formatFileSize(context, DEFAULT_TOTAL_BYTES_PER_APP_LIMIT_FLOOR,
+ FLAG_IEC_UNITS)));
+ fout.println(String.format(dumpFormat, KEY_TOTAL_BYTES_PER_APP_LIMIT_FRACTION,
+ TOTAL_BYTES_PER_APP_LIMIT_FRACTION,
+ DEFAULT_TOTAL_BYTES_PER_APP_LIMIT_FRACTION));
+ }
+ }
+
+ public static void initialize(Context context) {
+ DeviceConfig.addOnPropertiesChangedListener(NAMESPACE_BLOBSTORE,
+ context.getMainExecutor(),
+ properties -> DeviceConfigProperties.refresh(properties));
+ DeviceConfigProperties.refresh(DeviceConfig.getProperties(NAMESPACE_BLOBSTORE));
+ }
+
+ /**
+ * Returns the maximum amount of data that an app can acquire a lease on.
+ */
+ public static long getAppDataBytesLimit() {
+ final long totalBytesLimit = (long) (Environment.getDataSystemDirectory().getTotalSpace()
+ * DeviceConfigProperties.TOTAL_BYTES_PER_APP_LIMIT_FRACTION);
+ return Math.max(DeviceConfigProperties.TOTAL_BYTES_PER_APP_LIMIT_FLOOR, totalBytesLimit);
+ }
+
@Nullable
public static File prepareBlobFile(long sessionId) {
final File blobsDir = prepareBlobsDir();
@@ -122,4 +204,21 @@ class BlobStoreConfig {
public static File getBlobStoreRootDir() {
return new File(Environment.getDataSystemDirectory(), ROOT_DIR_NAME);
}
+
+ public static void dump(IndentingPrintWriter fout, Context context) {
+ fout.println("XML current version: " + XML_VERSION_CURRENT);
+
+ fout.println("Idle job ID: " + IDLE_JOB_ID);
+ fout.println("Idle job period: " + formatDuration(IDLE_JOB_PERIOD_MILLIS));
+
+ fout.println("Session expiry timeout: " + formatDuration(SESSION_EXPIRY_TIMEOUT_MILLIS));
+
+ fout.println("Total bytes per app limit: " + formatFileSize(context,
+ getAppDataBytesLimit(), FLAG_IEC_UNITS));
+
+ fout.println("Device config properties:");
+ fout.increaseIndent();
+ DeviceConfigProperties.dump(fout, context);
+ fout.decreaseIndent();
+ }
}
diff --git a/apex/blobstore/service/java/com/android/server/blob/BlobStoreManagerService.java b/apex/blobstore/service/java/com/android/server/blob/BlobStoreManagerService.java
index 05c661127eab..53a97cefa59b 100644
--- a/apex/blobstore/service/java/com/android/server/blob/BlobStoreManagerService.java
+++ b/apex/blobstore/service/java/com/android/server/blob/BlobStoreManagerService.java
@@ -36,6 +36,8 @@ import static com.android.server.blob.BlobStoreSession.STATE_COMMITTED;
import static com.android.server.blob.BlobStoreSession.STATE_VERIFIED_INVALID;
import static com.android.server.blob.BlobStoreSession.STATE_VERIFIED_VALID;
import static com.android.server.blob.BlobStoreSession.stateToString;
+import static com.android.server.blob.BlobStoreUtils.getDescriptionResourceId;
+import static com.android.server.blob.BlobStoreUtils.getPackageResources;
import android.annotation.CurrentTimeSecondsLong;
import android.annotation.IdRes;
@@ -43,7 +45,9 @@ import android.annotation.IntRange;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.annotation.UserIdInt;
+import android.app.blob.AccessorInfo;
import android.app.blob.BlobHandle;
+import android.app.blob.BlobInfo;
import android.app.blob.IBlobStoreManager;
import android.app.blob.IBlobStoreSession;
import android.content.BroadcastReceiver;
@@ -54,6 +58,7 @@ import android.content.pm.ApplicationInfo;
import android.content.pm.PackageManagerInternal;
import android.content.pm.PackageStats;
import android.content.res.ResourceId;
+import android.content.res.Resources;
import android.os.Binder;
import android.os.Handler;
import android.os.HandlerThread;
@@ -99,6 +104,7 @@ import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.PrintWriter;
+import java.lang.ref.WeakReference;
import java.nio.charset.StandardCharsets;
import java.security.SecureRandom;
import java.util.ArrayList;
@@ -109,6 +115,7 @@ import java.util.Random;
import java.util.Set;
import java.util.concurrent.atomic.AtomicLong;
import java.util.function.Consumer;
+import java.util.function.Function;
/**
* Service responsible for maintaining and facilitating access to data blobs published by apps.
@@ -187,7 +194,9 @@ public class BlobStoreManagerService extends SystemService {
@Override
public void onBootPhase(int phase) {
- if (phase == PHASE_THIRD_PARTY_APPS_CAN_START) {
+ if (phase == PHASE_ACTIVITY_MANAGER_READY) {
+ BlobStoreConfig.initialize(mContext);
+ } else if (phase == PHASE_THIRD_PARTY_APPS_CAN_START) {
synchronized (mBlobsLock) {
final SparseArray<SparseArray<String>> allPackages = getAllPackages();
readBlobSessionsLocked(allPackages);
@@ -213,12 +222,17 @@ public class BlobStoreManagerService extends SystemService {
}
private void registerReceivers() {
- final IntentFilter intentFilter = new IntentFilter();
- intentFilter.addAction(Intent.ACTION_PACKAGE_FULLY_REMOVED);
- intentFilter.addAction(Intent.ACTION_PACKAGE_DATA_CLEARED);
- intentFilter.addAction(Intent.ACTION_USER_REMOVED);
+ final IntentFilter packageChangedFilter = new IntentFilter();
+ packageChangedFilter.addAction(Intent.ACTION_PACKAGE_FULLY_REMOVED);
+ packageChangedFilter.addAction(Intent.ACTION_PACKAGE_DATA_CLEARED);
+ packageChangedFilter.addDataScheme("package");
mContext.registerReceiverAsUser(new PackageChangedReceiver(), UserHandle.ALL,
- intentFilter, null, mHandler);
+ packageChangedFilter, null, mHandler);
+
+ final IntentFilter userActionFilter = new IntentFilter();
+ userActionFilter.addAction(Intent.ACTION_USER_REMOVED);
+ mContext.registerReceiverAsUser(new UserActionReceiver(), UserHandle.ALL,
+ userActionFilter, null, mHandler);
}
@GuardedBy("mBlobsLock")
@@ -335,7 +349,7 @@ public class BlobStoreManagerService extends SystemService {
return session;
}
- private void deleteSessionInternal(long sessionId,
+ private void abandonSessionInternal(long sessionId,
int callingUid, String callingPackage) {
synchronized (mBlobsLock) {
final BlobStoreSession session = openSessionInternal(sessionId,
@@ -343,7 +357,7 @@ public class BlobStoreManagerService extends SystemService {
session.open();
session.abandon();
if (LOGV) {
- Slog.v(TAG, "Deleted session with id " + sessionId
+ Slog.v(TAG, "Abandoned session with id " + sessionId
+ "; callingUid=" + callingUid + ", callingPackage=" + callingPackage);
}
writeBlobSessionsAsync();
@@ -380,6 +394,11 @@ public class BlobStoreManagerService extends SystemService {
throw new IllegalArgumentException(
"Lease expiry cannot be later than blobs expiry time");
}
+ if (getTotalUsageBytesLocked(callingUid, callingPackage)
+ + blobMetadata.getSize() > BlobStoreConfig.getAppDataBytesLimit()) {
+ throw new IllegalStateException("Total amount of data with an active lease"
+ + " is exceeding the max limit");
+ }
blobMetadata.addLeasee(callingPackage, callingUid,
descriptionResId, description, leaseExpiryTimeMillis);
if (LOGV) {
@@ -390,6 +409,18 @@ public class BlobStoreManagerService extends SystemService {
}
}
+ @VisibleForTesting
+ @GuardedBy("mBlobsLock")
+ long getTotalUsageBytesLocked(int callingUid, String callingPackage) {
+ final AtomicLong totalBytes = new AtomicLong(0);
+ forEachBlobInUser((blobMetadata) -> {
+ if (blobMetadata.isALeasee(callingPackage, callingUid)) {
+ totalBytes.getAndAdd(blobMetadata.getSize());
+ }
+ }, UserHandle.getUserId(callingUid));
+ return totalBytes.get();
+ }
+
private void releaseLeaseInternal(BlobHandle blobHandle, int callingUid,
String callingPackage) {
synchronized (mBlobsLock) {
@@ -409,6 +440,48 @@ public class BlobStoreManagerService extends SystemService {
}
}
+ private List<BlobInfo> queryBlobsForUserInternal(int userId) {
+ final ArrayList<BlobInfo> blobInfos = new ArrayList<>();
+ synchronized (mBlobsLock) {
+ final ArrayMap<String, WeakReference<Resources>> resources = new ArrayMap<>();
+ final Function<String, Resources> resourcesGetter = (packageName) -> {
+ final WeakReference<Resources> resourcesRef = resources.get(packageName);
+ Resources packageResources = resourcesRef == null ? null : resourcesRef.get();
+ if (packageResources == null) {
+ packageResources = getPackageResources(mContext, packageName, userId);
+ resources.put(packageName, new WeakReference<>(packageResources));
+ }
+ return packageResources;
+ };
+ getUserBlobsLocked(userId).forEach((blobHandle, blobMetadata) -> {
+ final ArrayList<AccessorInfo> accessorInfos = new ArrayList<>();
+ blobMetadata.forEachLeasee(leasee -> {
+ final int descriptionResId = leasee.descriptionResEntryName == null
+ ? Resources.ID_NULL
+ : getDescriptionResourceId(resourcesGetter.apply(leasee.packageName),
+ leasee.descriptionResEntryName, leasee.packageName);
+ accessorInfos.add(new AccessorInfo(leasee.packageName, leasee.expiryTimeMillis,
+ descriptionResId, leasee.description));
+ });
+ blobInfos.add(new BlobInfo(blobMetadata.getBlobId(),
+ blobHandle.getExpiryTimeMillis(), blobHandle.getLabel(), accessorInfos));
+ });
+ }
+ return blobInfos;
+ }
+
+ private void deleteBlobInternal(long blobId, int callingUid) {
+ synchronized (mBlobsLock) {
+ final ArrayMap<BlobHandle, BlobMetadata> userBlobs = getUserBlobsLocked(
+ UserHandle.getUserId(callingUid));
+ userBlobs.entrySet().removeIf(entry -> {
+ final BlobMetadata blobMetadata = entry.getValue();
+ return blobMetadata.getBlobId() == blobId;
+ });
+ writeBlobsInfoAsync();
+ }
+ }
+
private void verifyCallingPackage(int callingUid, String callingPackage) {
if (mPackageManagerInternal.getPackageUid(
callingPackage, 0, UserHandle.getUserId(callingUid)) != callingUid) {
@@ -749,40 +822,34 @@ public class BlobStoreManagerService extends SystemService {
// Clean up any pending sessions
final LongSparseArray<BlobStoreSession> userSessions =
getUserSessionsLocked(UserHandle.getUserId(uid));
- final ArrayList<Integer> indicesToRemove = new ArrayList<>();
- for (int i = 0, count = userSessions.size(); i < count; ++i) {
- final BlobStoreSession session = userSessions.valueAt(i);
- if (session.getOwnerUid() == uid
- && session.getOwnerPackageName().equals(packageName)) {
- session.getSessionFile().delete();
- mActiveBlobIds.remove(session.getSessionId());
- indicesToRemove.add(i);
+ userSessions.removeIf((sessionId, blobStoreSession) -> {
+ if (blobStoreSession.getOwnerUid() == uid
+ && blobStoreSession.getOwnerPackageName().equals(packageName)) {
+ blobStoreSession.getSessionFile().delete();
+ mActiveBlobIds.remove(blobStoreSession.getSessionId());
+ return true;
}
- }
- for (int i = 0, count = indicesToRemove.size(); i < count; ++i) {
- userSessions.removeAt(indicesToRemove.get(i));
- }
+ return false;
+ });
writeBlobSessionsAsync();
// Remove the package from the committer and leasee list
final ArrayMap<BlobHandle, BlobMetadata> userBlobs =
getUserBlobsLocked(UserHandle.getUserId(uid));
- indicesToRemove.clear();
- for (int i = 0, count = userBlobs.size(); i < count; ++i) {
- final BlobMetadata blobMetadata = userBlobs.valueAt(i);
+ userBlobs.entrySet().removeIf(entry -> {
+ final BlobMetadata blobMetadata = entry.getValue();
blobMetadata.removeCommitter(packageName, uid);
blobMetadata.removeLeasee(packageName, uid);
// Delete the blob if it doesn't have any active leases.
if (!blobMetadata.hasLeases()) {
blobMetadata.getBlobFile().delete();
mActiveBlobIds.remove(blobMetadata.getBlobId());
- indicesToRemove.add(i);
+ return true;
}
- }
- for (int i = 0, count = indicesToRemove.size(); i < count; ++i) {
- userBlobs.removeAt(indicesToRemove.get(i));
- }
+ return false;
+ });
writeBlobsInfoAsync();
+
if (LOGV) {
Slog.v(TAG, "Removed blobs data associated with pkg="
+ packageName + ", uid=" + uid);
@@ -939,6 +1006,12 @@ public class BlobStoreManagerService extends SystemService {
}
}
+ void runIdleMaintenance() {
+ synchronized (mBlobsLock) {
+ handleIdleMaintenanceLocked();
+ }
+ }
+
@GuardedBy("mBlobsLock")
private void dumpSessionsLocked(IndentingPrintWriter fout, DumpArgs dumpArgs) {
for (int i = 0, userCount = mSessions.size(); i < userCount; ++i) {
@@ -1077,6 +1150,19 @@ public class BlobStoreManagerService extends SystemService {
}
handlePackageRemoved(packageName, uid);
break;
+ default:
+ Slog.wtf(TAG, "Received unknown intent: " + intent);
+ }
+ }
+ }
+
+ private class UserActionReceiver extends BroadcastReceiver {
+ @Override
+ public void onReceive(Context context, Intent intent) {
+ if (LOGV) {
+ Slog.v(TAG, "Received: " + intent);
+ }
+ switch (intent.getAction()) {
case Intent.ACTION_USER_REMOVED:
final int userId = intent.getIntExtra(Intent.EXTRA_USER_HANDLE,
USER_NULL);
@@ -1129,7 +1215,7 @@ public class BlobStoreManagerService extends SystemService {
}
@Override
- public void deleteSession(@IntRange(from = 1) long sessionId,
+ public void abandonSession(@IntRange(from = 1) long sessionId,
@NonNull String packageName) {
Preconditions.checkArgumentPositive(sessionId,
"sessionId must be positive: " + sessionId);
@@ -1138,7 +1224,7 @@ public class BlobStoreManagerService extends SystemService {
final int callingUid = Binder.getCallingUid();
verifyCallingPackage(callingUid, packageName);
- deleteSessionInternal(sessionId, callingUid, packageName);
+ abandonSessionInternal(sessionId, callingUid, packageName);
}
@Override
@@ -1181,8 +1267,12 @@ public class BlobStoreManagerService extends SystemService {
final int callingUid = Binder.getCallingUid();
verifyCallingPackage(callingUid, packageName);
- acquireLeaseInternal(blobHandle, descriptionResId, description, leaseExpiryTimeMillis,
- callingUid, packageName);
+ try {
+ acquireLeaseInternal(blobHandle, descriptionResId, description,
+ leaseExpiryTimeMillis, callingUid, packageName);
+ } catch (Resources.NotFoundException e) {
+ throw new IllegalArgumentException(e);
+ }
}
@Override
@@ -1208,6 +1298,28 @@ public class BlobStoreManagerService extends SystemService {
}
@Override
+ @NonNull
+ public List<BlobInfo> queryBlobsForUser(@UserIdInt int userId) {
+ if (Binder.getCallingUid() != Process.SYSTEM_UID) {
+ throw new SecurityException("Only system uid is allowed to call "
+ + "queryBlobsForUser()");
+ }
+
+ return queryBlobsForUserInternal(userId);
+ }
+
+ @Override
+ public void deleteBlob(long blobId) {
+ final int callingUid = Binder.getCallingUid();
+ if (callingUid != Process.SYSTEM_UID) {
+ throw new SecurityException("Only system uid is allowed to call "
+ + "deleteBlob()");
+ }
+
+ deleteBlobInternal(blobId, callingUid);
+ }
+
+ @Override
public void dump(@NonNull FileDescriptor fd, @NonNull PrintWriter writer,
@Nullable String[] args) {
// TODO: add proto-based version of this.
@@ -1225,8 +1337,10 @@ public class BlobStoreManagerService extends SystemService {
}
synchronized (mBlobsLock) {
- fout.println("mCurrentMaxSessionId: " + mCurrentMaxSessionId);
- fout.println();
+ if (dumpArgs.shouldDumpAllSections()) {
+ fout.println("mCurrentMaxSessionId: " + mCurrentMaxSessionId);
+ fout.println();
+ }
if (dumpArgs.shouldDumpSessions()) {
dumpSessionsLocked(fout, dumpArgs);
@@ -1237,6 +1351,14 @@ public class BlobStoreManagerService extends SystemService {
fout.println();
}
}
+
+ if (dumpArgs.shouldDumpConfig()) {
+ fout.println("BlobStore config:");
+ fout.increaseIndent();
+ BlobStoreConfig.dump(fout, mContext);
+ fout.decreaseIndent();
+ fout.println();
+ }
}
@Override
@@ -1249,14 +1371,16 @@ public class BlobStoreManagerService extends SystemService {
}
static final class DumpArgs {
+ private static final int FLAG_DUMP_SESSIONS = 1 << 0;
+ private static final int FLAG_DUMP_BLOBS = 1 << 1;
+ private static final int FLAG_DUMP_CONFIG = 1 << 2;
+
+ private int mSelectedSectionFlags;
private boolean mDumpFull;
private final ArrayList<String> mDumpPackages = new ArrayList<>();
private final ArrayList<Integer> mDumpUids = new ArrayList<>();
private final ArrayList<Integer> mDumpUserIds = new ArrayList<>();
private final ArrayList<Long> mDumpBlobIds = new ArrayList<>();
- private boolean mDumpOnlySelectedSections;
- private boolean mDumpSessions;
- private boolean mDumpBlobs;
private boolean mDumpHelp;
public boolean shouldDumpSession(String packageName, int uid, long blobId) {
@@ -1275,18 +1399,41 @@ public class BlobStoreManagerService extends SystemService {
return true;
}
+ public boolean shouldDumpAllSections() {
+ return mSelectedSectionFlags == 0;
+ }
+
+ public void allowDumpSessions() {
+ mSelectedSectionFlags |= FLAG_DUMP_SESSIONS;
+ }
+
public boolean shouldDumpSessions() {
- if (!mDumpOnlySelectedSections) {
+ if (shouldDumpAllSections()) {
return true;
}
- return mDumpSessions;
+ return (mSelectedSectionFlags & FLAG_DUMP_SESSIONS) != 0;
+ }
+
+ public void allowDumpBlobs() {
+ mSelectedSectionFlags |= FLAG_DUMP_BLOBS;
}
public boolean shouldDumpBlobs() {
- if (!mDumpOnlySelectedSections) {
+ if (shouldDumpAllSections()) {
return true;
}
- return mDumpBlobs;
+ return (mSelectedSectionFlags & FLAG_DUMP_BLOBS) != 0;
+ }
+
+ public void allowDumpConfig() {
+ mSelectedSectionFlags |= FLAG_DUMP_CONFIG;
+ }
+
+ public boolean shouldDumpConfig() {
+ if (shouldDumpAllSections()) {
+ return true;
+ }
+ return (mSelectedSectionFlags & FLAG_DUMP_CONFIG) != 0;
}
public boolean shouldDumpBlob(long blobId) {
@@ -1323,11 +1470,11 @@ public class BlobStoreManagerService extends SystemService {
dumpArgs.mDumpFull = true;
}
} else if ("--sessions".equals(opt)) {
- dumpArgs.mDumpOnlySelectedSections = true;
- dumpArgs.mDumpSessions = true;
+ dumpArgs.allowDumpSessions();
} else if ("--blobs".equals(opt)) {
- dumpArgs.mDumpOnlySelectedSections = true;
- dumpArgs.mDumpBlobs = true;
+ dumpArgs.allowDumpBlobs();
+ } else if ("--config".equals(opt)) {
+ dumpArgs.allowDumpConfig();
} else if ("--package".equals(opt) || "-p".equals(opt)) {
dumpArgs.mDumpPackages.add(getStringArgRequired(args, ++i, "packageName"));
} else if ("--uid".equals(opt) || "-u".equals(opt)) {
@@ -1386,6 +1533,8 @@ public class BlobStoreManagerService extends SystemService {
printWithIndent(pw, "Dump only the sessions info");
pw.println("--blobs");
printWithIndent(pw, "Dump only the committed blobs info");
+ pw.println("--config");
+ printWithIndent(pw, "Dump only the config values");
pw.println("--package | -p [package-name]");
printWithIndent(pw, "Dump blobs info associated with the given package");
pw.println("--uid | -u [uid]");
@@ -1408,9 +1557,7 @@ public class BlobStoreManagerService extends SystemService {
private class LocalService extends BlobStoreManagerInternal {
@Override
public void onIdleMaintenance() {
- synchronized (mBlobsLock) {
- handleIdleMaintenanceLocked();
- }
+ runIdleMaintenance();
}
}
diff --git a/apex/blobstore/service/java/com/android/server/blob/BlobStoreManagerShellCommand.java b/apex/blobstore/service/java/com/android/server/blob/BlobStoreManagerShellCommand.java
index d58294b8b941..72af323e9d5f 100644
--- a/apex/blobstore/service/java/com/android/server/blob/BlobStoreManagerShellCommand.java
+++ b/apex/blobstore/service/java/com/android/server/blob/BlobStoreManagerShellCommand.java
@@ -44,6 +44,8 @@ class BlobStoreManagerShellCommand extends ShellCommand {
return runClearAllBlobs(pw);
case "delete-blob":
return runDeleteBlob(pw);
+ case "idle-maintenance":
+ return runIdleMaintenance(pw);
default:
return handleDefaultCommands(cmd);
}
@@ -84,6 +86,11 @@ class BlobStoreManagerShellCommand extends ShellCommand {
return 0;
}
+ private int runIdleMaintenance(PrintWriter pw) {
+ mService.runIdleMaintenance();
+ return 0;
+ }
+
@Override
public void onHelp() {
final PrintWriter pw = getOutPrintWriter();
@@ -112,6 +119,8 @@ class BlobStoreManagerShellCommand extends ShellCommand {
pw.println(" --expiry: Expiry time of the blob to delete, in milliseconds.");
pw.println(" --label: Label of the blob to delete.");
pw.println(" --tag: Tag of the blob to delete.");
+ pw.println("idle-maintenance");
+ pw.println(" Run idle maintenance which takes care of removing stale data.");
pw.println();
}
diff --git a/apex/blobstore/service/java/com/android/server/blob/BlobStoreSession.java b/apex/blobstore/service/java/com/android/server/blob/BlobStoreSession.java
index cc4044ed46b9..62701e52781d 100644
--- a/apex/blobstore/service/java/com/android/server/blob/BlobStoreSession.java
+++ b/apex/blobstore/service/java/com/android/server/blob/BlobStoreSession.java
@@ -347,12 +347,12 @@ class BlobStoreSession extends IBlobStoreSession.Stub {
@Override
public void close() {
- closeSession(STATE_CLOSED);
+ closeSession(STATE_CLOSED, false /* sendCallback */);
}
@Override
public void abandon() {
- closeSession(STATE_ABANDONED);
+ closeSession(STATE_ABANDONED, true /* sendCallback */);
}
@Override
@@ -360,11 +360,11 @@ class BlobStoreSession extends IBlobStoreSession.Stub {
synchronized (mSessionLock) {
mBlobCommitCallback = callback;
- closeSession(STATE_COMMITTED);
+ closeSession(STATE_COMMITTED, true /* sendCallback */);
}
}
- private void closeSession(int state) {
+ private void closeSession(int state, boolean sendCallback) {
assertCallerIsOwner();
synchronized (mSessionLock) {
if (mState != STATE_OPENED) {
@@ -381,7 +381,9 @@ class BlobStoreSession extends IBlobStoreSession.Stub {
mState = state;
revokeAllFdsLocked();
- mListener.onStateChanged(this);
+ if (sendCallback) {
+ mListener.onStateChanged(this);
+ }
}
}
@@ -457,6 +459,10 @@ class BlobStoreSession extends IBlobStoreSession.Stub {
return "<abandoned>";
case STATE_COMMITTED:
return "<committed>";
+ case STATE_VERIFIED_VALID:
+ return "<verified_valid>";
+ case STATE_VERIFIED_INVALID:
+ return "<verified_invalid>";
default:
Slog.wtf(TAG, "Unknown state: " + state);
return "<unknown>";
diff --git a/apex/blobstore/service/java/com/android/server/blob/BlobStoreUtils.java b/apex/blobstore/service/java/com/android/server/blob/BlobStoreUtils.java
new file mode 100644
index 000000000000..6af540acd6a4
--- /dev/null
+++ b/apex/blobstore/service/java/com/android/server/blob/BlobStoreUtils.java
@@ -0,0 +1,50 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.blob;
+
+import static com.android.server.blob.BlobStoreConfig.TAG;
+
+import android.annotation.IdRes;
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.content.Context;
+import android.content.pm.PackageManager;
+import android.content.res.Resources;
+import android.util.Slog;
+
+class BlobStoreUtils {
+ private static final String DESC_RES_TYPE_STRING = "string";
+
+ @Nullable
+ static Resources getPackageResources(@NonNull Context context,
+ @NonNull String packageName, int userId) {
+ try {
+ return context.getPackageManager()
+ .getResourcesForApplicationAsUser(packageName, userId);
+ } catch (PackageManager.NameNotFoundException e) {
+ Slog.d(TAG, "Unknown package in user " + userId + ": "
+ + packageName, e);
+ return null;
+ }
+ }
+
+ @IdRes
+ static int getDescriptionResourceId(@NonNull Resources resources,
+ @NonNull String resourceEntryName, @NonNull String packageName) {
+ return resources.getIdentifier(resourceEntryName, DESC_RES_TYPE_STRING, packageName);
+ }
+}
diff --git a/apex/jobscheduler/service/java/com/android/server/job/TEST_MAPPING b/apex/jobscheduler/service/java/com/android/server/job/TEST_MAPPING
index cdcd65985ec0..e2e118074aac 100644
--- a/apex/jobscheduler/service/java/com/android/server/job/TEST_MAPPING
+++ b/apex/jobscheduler/service/java/com/android/server/job/TEST_MAPPING
@@ -1,6 +1,13 @@
{
"presubmit": [
{
+ "name": "CtsJobSchedulerTestCases",
+ "options": [
+ {"exclude-annotation": "androidx.test.filters.FlakyTest"},
+ {"exclude-annotation": "androidx.test.filters.LargeTest"}
+ ]
+ },
+ {
"name": "FrameworksMockingServicesTests",
"options": [
{"include-filter": "com.android.server.job"},
diff --git a/apex/media/framework/java/android/media/MediaParser.java b/apex/media/framework/java/android/media/MediaParser.java
index a4f7b5bf5e24..b219fd41afec 100644
--- a/apex/media/framework/java/android/media/MediaParser.java
+++ b/apex/media/framework/java/android/media/MediaParser.java
@@ -54,6 +54,7 @@ import com.google.android.exoplayer2.video.ColorInfo;
import java.io.EOFException;
import java.io.IOException;
+import java.io.InterruptedIOException;
import java.nio.ByteBuffer;
import java.util.Collections;
import java.util.HashMap;
@@ -119,7 +120,7 @@ import java.util.Map;
*
* &#64;Override
* public void onSampleData(int trackIndex, &#64;NonNull InputReader inputReader)
- * throws IOException, InterruptedException {
+ * throws IOException {
* int numberOfBytesToRead = (int) inputReader.getLength();
* if (videoTrackIndex != trackIndex) {
* // Discard contents.
@@ -310,8 +311,7 @@ public final class MediaParser {
* of the input has been reached.
* @throws java.io.IOException If an error occurs reading from the source.
*/
- int read(@NonNull byte[] buffer, int offset, int readLength)
- throws IOException, InterruptedException;
+ int read(@NonNull byte[] buffer, int offset, int readLength) throws IOException;
/** Returns the current read position (byte offset) in the stream. */
long getPosition();
@@ -373,11 +373,8 @@ public final class MediaParser {
* @param trackIndex The index of the track to which the sample data corresponds.
* @param inputReader The {@link InputReader} from which to read the data.
* @throws IOException If an exception occurs while reading from {@code inputReader}.
- * @throws InterruptedException If an interruption occurs while reading from {@code
- * inputReader}.
*/
- void onSampleData(int trackIndex, @NonNull InputReader inputReader)
- throws IOException, InterruptedException;
+ void onSampleData(int trackIndex, @NonNull InputReader inputReader) throws IOException;
/**
* Called once all the data of a sample has been passed to {@link #onSampleData}.
@@ -717,8 +714,7 @@ public final class MediaParser {
* @throws UnrecognizedInputFormatException If the format cannot be recognized by any of the
* underlying parser implementations.
*/
- public boolean advance(@NonNull SeekableInputReader seekableInputReader)
- throws IOException, InterruptedException {
+ public boolean advance(@NonNull SeekableInputReader seekableInputReader) throws IOException {
if (mExtractorInput == null) {
// TODO: For efficiency, the same implementation should be used, by providing a
// clearBuffers() method, or similar.
@@ -748,8 +744,10 @@ public final class MediaParser {
}
} catch (EOFException e) {
// Do nothing.
- } catch (IOException | InterruptedException e) {
- throw new IllegalStateException(e);
+ } catch (InterruptedException e) {
+ // TODO: Remove this exception replacement once we update the ExoPlayer
+ // version.
+ throw new InterruptedIOException();
} finally {
mExtractorInput.resetPeekPosition();
}
@@ -767,7 +765,13 @@ public final class MediaParser {
}
mPositionHolder.position = seekableInputReader.getPosition();
- int result = mExtractor.read(mExtractorInput, mPositionHolder);
+ int result = 0;
+ try {
+ result = mExtractor.read(mExtractorInput, mPositionHolder);
+ } catch (InterruptedException e) {
+ // TODO: Remove this exception replacement once we update the ExoPlayer version.
+ throw new InterruptedIOException();
+ }
if (result == Extractor.RESULT_END_OF_INPUT) {
return false;
}
@@ -853,13 +857,7 @@ public final class MediaParser {
@Override
public int read(byte[] buffer, int offset, int readLength) throws IOException {
- // TODO: Reevaluate interruption in Input.
- try {
- return mInputReader.read(buffer, offset, readLength);
- } catch (InterruptedException e) {
- // TODO: Remove.
- throw new RuntimeException();
- }
+ return mInputReader.read(buffer, offset, readLength);
}
@Override
@@ -926,7 +924,7 @@ public final class MediaParser {
@Override
public int sampleData(ExtractorInput input, int length, boolean allowEndOfInput)
- throws IOException, InterruptedException {
+ throws IOException {
mScratchExtractorInputAdapter.setExtractorInput(input, length);
long positionBeforeReading = mScratchExtractorInputAdapter.getPosition();
mOutputConsumer.onSampleData(mTrackIndex, mScratchExtractorInputAdapter);
@@ -938,7 +936,7 @@ public final class MediaParser {
mScratchParsableByteArrayAdapter.resetWithByteArray(data, length);
try {
mOutputConsumer.onSampleData(mTrackIndex, mScratchParsableByteArrayAdapter);
- } catch (IOException | InterruptedException e) {
+ } catch (IOException e) {
// Unexpected.
throw new RuntimeException(e);
}
@@ -967,9 +965,14 @@ public final class MediaParser {
// Input implementation.
@Override
- public int read(byte[] buffer, int offset, int readLength)
- throws IOException, InterruptedException {
- int readBytes = mExtractorInput.read(buffer, offset, readLength);
+ public int read(byte[] buffer, int offset, int readLength) throws IOException {
+ int readBytes = 0;
+ try {
+ readBytes = mExtractorInput.read(buffer, offset, readLength);
+ } catch (InterruptedException e) {
+ // TODO: Remove this exception replacement once we update the ExoPlayer version.
+ throw new InterruptedIOException();
+ }
mCurrentPosition += readBytes;
return readBytes;
}
diff --git a/apex/permission/service/java/com/android/permission/persistence/RuntimePermissionsPersistenceImpl.java b/apex/permission/service/java/com/android/permission/persistence/RuntimePermissionsPersistenceImpl.java
index 30a8b458cce5..0ac0c730998b 100644
--- a/apex/permission/service/java/com/android/permission/persistence/RuntimePermissionsPersistenceImpl.java
+++ b/apex/permission/service/java/com/android/permission/persistence/RuntimePermissionsPersistenceImpl.java
@@ -18,7 +18,7 @@ package com.android.permission.persistence;
import android.annotation.NonNull;
import android.annotation.Nullable;
-import android.content.ApexContext;
+import android.content.ApexEnvironment;
import android.content.pm.PackageManager;
import android.os.UserHandle;
import android.util.ArrayMap;
@@ -258,8 +258,8 @@ public class RuntimePermissionsPersistenceImpl implements RuntimePermissionsPers
@NonNull
private static File getFile(@NonNull UserHandle user) {
- ApexContext apexContext = ApexContext.getApexContext(APEX_MODULE_NAME);
- File dataDirectory = apexContext.getDeviceProtectedDataDirForUser(user);
+ ApexEnvironment apexEnvironment = ApexEnvironment.getApexEnvironment(APEX_MODULE_NAME);
+ File dataDirectory = apexEnvironment.getDeviceProtectedDataDirForUser(user);
return new File(dataDirectory, RUNTIME_PERMISSIONS_FILE_NAME);
}
}
diff --git a/apex/permission/service/java/com/android/role/persistence/RolesPersistenceImpl.java b/apex/permission/service/java/com/android/role/persistence/RolesPersistenceImpl.java
index 3031c8213982..2346c11e5242 100644
--- a/apex/permission/service/java/com/android/role/persistence/RolesPersistenceImpl.java
+++ b/apex/permission/service/java/com/android/role/persistence/RolesPersistenceImpl.java
@@ -18,7 +18,7 @@ package com.android.role.persistence;
import android.annotation.NonNull;
import android.annotation.Nullable;
-import android.content.ApexContext;
+import android.content.ApexEnvironment;
import android.os.UserHandle;
import android.util.ArrayMap;
import android.util.ArraySet;
@@ -211,8 +211,8 @@ public class RolesPersistenceImpl implements RolesPersistence {
@NonNull
private static File getFile(@NonNull UserHandle user) {
- ApexContext apexContext = ApexContext.getApexContext(APEX_MODULE_NAME);
- File dataDirectory = apexContext.getDeviceProtectedDataDirForUser(user);
+ ApexEnvironment apexEnvironment = ApexEnvironment.getApexEnvironment(APEX_MODULE_NAME);
+ File dataDirectory = apexEnvironment.getDeviceProtectedDataDirForUser(user);
return new File(dataDirectory, ROLES_FILE_NAME);
}
}
diff --git a/apex/statsd/aidl/android/os/IStatsManagerService.aidl b/apex/statsd/aidl/android/os/IStatsManagerService.aidl
index 4a259f50d2f6..b59a97e25bd0 100644
--- a/apex/statsd/aidl/android/os/IStatsManagerService.aidl
+++ b/apex/statsd/aidl/android/os/IStatsManagerService.aidl
@@ -128,7 +128,7 @@ interface IStatsManagerService {
void removeConfiguration(in long configId, in String packageName);
/** Tell StatsManagerService to register a puller for the given atom tag with statsd. */
- oneway void registerPullAtomCallback(int atomTag, long coolDownNs, long timeoutNs,
+ oneway void registerPullAtomCallback(int atomTag, long coolDownMillis, long timeoutMillis,
in int[] additiveFields, IPullAtomCallback pullerCallback);
/** Tell StatsManagerService to unregister the pulller for the given atom tag from statsd. */
diff --git a/apex/statsd/aidl/android/os/IStatsd.aidl b/apex/statsd/aidl/android/os/IStatsd.aidl
index 10b1e5b26d12..c8aec5337f6e 100644
--- a/apex/statsd/aidl/android/os/IStatsd.aidl
+++ b/apex/statsd/aidl/android/os/IStatsd.aidl
@@ -186,8 +186,9 @@ interface IStatsd {
* Registers a puller callback function that, when invoked, pulls the data
* for the specified atom tag.
*/
- oneway void registerPullAtomCallback(int uid, int atomTag, long coolDownNs, long timeoutNs,
- in int[] additiveFields, IPullAtomCallback pullerCallback);
+ oneway void registerPullAtomCallback(int uid, int atomTag, long coolDownMillis,
+ long timeoutMillis,in int[] additiveFields,
+ IPullAtomCallback pullerCallback);
/**
* Registers a puller callback function that, when invoked, pulls the data
diff --git a/apex/statsd/framework/Android.bp b/apex/statsd/framework/Android.bp
index 1bd770a1ab99..8185bb036b22 100644
--- a/apex/statsd/framework/Android.bp
+++ b/apex/statsd/framework/Android.bp
@@ -43,6 +43,7 @@ filegroup {
],
visibility: [
"//frameworks/base", // For the "global" stubs.
+ "//frameworks/base/apex/statsd:__subpackages__",
],
}
@@ -74,8 +75,6 @@ java_library {
hostdex: true, // for hiddenapi check
visibility: [
"//frameworks/base/apex/statsd:__subpackages__",
- // TODO(b/149928788): Remove when tests are moved.
- "//frameworks/base/core/tests/coretests:__pkg__",
],
apex_available: [
"com.android.os.statsd",
@@ -164,3 +163,26 @@ java_library {
"//frameworks/opt/net/wifi/service" // wifi service
]
}
+
+android_test {
+ name: "FrameworkStatsdTest",
+ platform_apis: true,
+ srcs: [
+ // TODO(b/147705194): Use framework-statsd as a lib dependency instead.
+ ":framework-statsd-sources",
+ "test/**/*.java",
+ ],
+ manifest: "test/AndroidManifest.xml",
+ static_libs: [
+ "androidx.test.rules",
+ "truth-prebuilt",
+ ],
+ libs: [
+ "android.test.runner.stubs",
+ "android.test.base.stubs",
+ ],
+ test_suites: [
+ "device-tests",
+ ],
+}
+
diff --git a/apex/statsd/framework/java/android/app/StatsManager.java b/apex/statsd/framework/java/android/app/StatsManager.java
index e637187f23be..f021dcf3cd2f 100644
--- a/apex/statsd/framework/java/android/app/StatsManager.java
+++ b/apex/statsd/framework/java/android/app/StatsManager.java
@@ -119,14 +119,12 @@ public final class StatsManager {
/**
* @hide
**/
- @VisibleForTesting
- public static final long DEFAULT_COOL_DOWN_NS = 1_000_000_000L; // 1 second.
+ @VisibleForTesting public static final long DEFAULT_COOL_DOWN_MILLIS = 1_000L; // 1 second.
/**
* @hide
**/
- @VisibleForTesting
- public static final long DEFAULT_TIMEOUT_NS = 10_000_000_000L; // 10 seconds.
+ @VisibleForTesting public static final long DEFAULT_TIMEOUT_MILLIS = 10_000L; // 10 seconds.
/**
* Constructor for StatsManagerClient.
@@ -489,23 +487,24 @@ public final class StatsManager {
}
/**
- * Registers a callback for an atom when that atom is to be pulled. The stats service will
+ * Sets a callback for an atom when that atom is to be pulled. The stats service will
* invoke pullData in the callback when the stats service determines that this atom needs to be
* pulled. This method should not be called by third-party apps.
*
* @param atomTag The tag of the atom for this puller callback.
* @param metadata Optional metadata specifying the timeout, cool down time, and
* additive fields for mapping isolated to host uids.
- * @param callback The callback to be invoked when the stats service pulls the atom.
* @param executor The executor in which to run the callback.
+ * @param callback The callback to be invoked when the stats service pulls the atom.
*
*/
@RequiresPermission(android.Manifest.permission.REGISTER_STATS_PULL_ATOM)
- public void registerPullAtomCallback(int atomTag, @Nullable PullAtomMetadata metadata,
+ public void setPullAtomCallback(int atomTag, @Nullable PullAtomMetadata metadata,
@NonNull @CallbackExecutor Executor executor,
@NonNull StatsPullAtomCallback callback) {
- long coolDownNs = metadata == null ? DEFAULT_COOL_DOWN_NS : metadata.mCoolDownNs;
- long timeoutNs = metadata == null ? DEFAULT_TIMEOUT_NS : metadata.mTimeoutNs;
+ long coolDownMillis =
+ metadata == null ? DEFAULT_COOL_DOWN_MILLIS : metadata.mCoolDownMillis;
+ long timeoutMillis = metadata == null ? DEFAULT_TIMEOUT_MILLIS : metadata.mTimeoutMillis;
int[] additiveFields = metadata == null ? new int[0] : metadata.mAdditiveFields;
if (additiveFields == null) {
additiveFields = new int[0];
@@ -516,8 +515,8 @@ public final class StatsManager {
IStatsManagerService service = getIStatsManagerServiceLocked();
PullAtomCallbackInternal rec =
new PullAtomCallbackInternal(atomTag, callback, executor);
- service.registerPullAtomCallback(atomTag, coolDownNs, timeoutNs, additiveFields,
- rec);
+ service.registerPullAtomCallback(
+ atomTag, coolDownMillis, timeoutMillis, additiveFields, rec);
} catch (RemoteException e) {
throw new RuntimeException("Unable to register pull callback", e);
}
@@ -525,14 +524,14 @@ public final class StatsManager {
}
/**
- * Unregisters a callback for an atom when that atom is to be pulled. Note that any ongoing
+ * Clears a callback for an atom when that atom is to be pulled. Note that any ongoing
* pulls will still occur. This method should not be called by third-party apps.
*
* @param atomTag The tag of the atom of which to unregister
*
*/
@RequiresPermission(android.Manifest.permission.REGISTER_STATS_PULL_ATOM)
- public void unregisterPullAtomCallback(int atomTag) {
+ public void clearPullAtomCallback(int atomTag) {
synchronized (sLock) {
try {
IStatsManagerService service = getIStatsManagerServiceLocked();
@@ -585,14 +584,14 @@ public final class StatsManager {
*
*/
public static class PullAtomMetadata {
- private final long mCoolDownNs;
- private final long mTimeoutNs;
+ private final long mCoolDownMillis;
+ private final long mTimeoutMillis;
private final int[] mAdditiveFields;
// Private Constructor for builder
- private PullAtomMetadata(long coolDownNs, long timeoutNs, int[] additiveFields) {
- mCoolDownNs = coolDownNs;
- mTimeoutNs = timeoutNs;
+ private PullAtomMetadata(long coolDownMillis, long timeoutMillis, int[] additiveFields) {
+ mCoolDownMillis = coolDownMillis;
+ mTimeoutMillis = timeoutMillis;
mAdditiveFields = additiveFields;
}
@@ -600,8 +599,8 @@ public final class StatsManager {
* Builder for PullAtomMetadata.
*/
public static class Builder {
- private long mCoolDownNs;
- private long mTimeoutNs;
+ private long mCoolDownMillis;
+ private long mTimeoutMillis;
private int[] mAdditiveFields;
/**
@@ -609,27 +608,28 @@ public final class StatsManager {
* StatsManager#registerPullAtomCallback
*/
public Builder() {
- mCoolDownNs = DEFAULT_COOL_DOWN_NS;
- mTimeoutNs = DEFAULT_TIMEOUT_NS;
+ mCoolDownMillis = DEFAULT_COOL_DOWN_MILLIS;
+ mTimeoutMillis = DEFAULT_TIMEOUT_MILLIS;
mAdditiveFields = null;
}
/**
- * Set the cool down time of the pull in nanoseconds. If two successive pulls are issued
- * within the cool down, a cached version of the first will be used for the second.
+ * Set the cool down time of the pull in milliseconds. If two successive pulls are
+ * issued within the cool down, a cached version of the first pull will be used for the
+ * second pull.
*/
@NonNull
- public Builder setCoolDownNs(long coolDownNs) {
- mCoolDownNs = coolDownNs;
+ public Builder setCoolDownMillis(long coolDownMillis) {
+ mCoolDownMillis = coolDownMillis;
return this;
}
/**
- * Set the maximum time the pull can take in nanoseconds.
+ * Set the maximum time the pull can take in milliseconds.
*/
@NonNull
- public Builder setTimeoutNs(long timeoutNs) {
- mTimeoutNs = timeoutNs;
+ public Builder setTimeoutMillis(long timeoutMillis) {
+ mTimeoutMillis = timeoutMillis;
return this;
}
@@ -652,30 +652,32 @@ public final class StatsManager {
*/
@NonNull
public PullAtomMetadata build() {
- return new PullAtomMetadata(mCoolDownNs, mTimeoutNs, mAdditiveFields);
+ return new PullAtomMetadata(mCoolDownMillis, mTimeoutMillis, mAdditiveFields);
}
}
/**
- * @hide
+ * Return the cool down time of this pull in milliseconds.
*/
- @VisibleForTesting
- public long getCoolDownNs() {
- return mCoolDownNs;
+ public long getCoolDownMillis() {
+ return mCoolDownMillis;
}
/**
- * @hide
+ * Return the maximum amount of time this pull can take in milliseconds.
*/
- @VisibleForTesting
- public long getTimeoutNs() {
- return mTimeoutNs;
+ public long getTimeoutMillis() {
+ return mTimeoutMillis;
}
/**
- * @hide
+ * Return the additive fields of this pulled atom.
+ *
+ * This is only applicable for atoms that have a uid field. When tasks are run in
+ * isolated processes, the data will be attributed to the host uid. Additive fields
+ * will be combined when the non-additive fields are the same.
*/
- @VisibleForTesting
+ @Nullable
public int[] getAdditiveFields() {
return mAdditiveFields;
}
diff --git a/apex/statsd/framework/test/AndroidManifest.xml b/apex/statsd/framework/test/AndroidManifest.xml
new file mode 100644
index 000000000000..8f89d2332b12
--- /dev/null
+++ b/apex/statsd/framework/test/AndroidManifest.xml
@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2020 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+ package="com.android.os.statsd.framework.test"
+ >
+
+ <instrumentation
+ android:name="androidx.test.runner.AndroidJUnitRunner"
+ android:targetPackage="com.android.os.statsd.framework.test"
+ android:label="Framework Statsd Tests" />
+
+</manifest>
diff --git a/apex/statsd/framework/test/TEST_MAPPING b/apex/statsd/framework/test/TEST_MAPPING
new file mode 100644
index 000000000000..f38795819189
--- /dev/null
+++ b/apex/statsd/framework/test/TEST_MAPPING
@@ -0,0 +1,7 @@
+{
+ "presubmit" : [
+ {
+ "name" : "FrameworkStatsdTest"
+ }
+ ]
+}
diff --git a/core/tests/coretests/src/android/app/PullAtomMetadataTest.java b/apex/statsd/framework/test/src/android/app/PullAtomMetadataTest.java
index 0ae613400b18..fd386bd8e32e 100644
--- a/core/tests/coretests/src/android/app/PullAtomMetadataTest.java
+++ b/apex/statsd/framework/test/src/android/app/PullAtomMetadataTest.java
@@ -33,28 +33,28 @@ public final class PullAtomMetadataTest {
@Test
public void testEmpty() {
PullAtomMetadata metadata = new PullAtomMetadata.Builder().build();
- assertThat(metadata.getTimeoutNs()).isEqualTo(StatsManager.DEFAULT_TIMEOUT_NS);
- assertThat(metadata.getCoolDownNs()).isEqualTo(StatsManager.DEFAULT_COOL_DOWN_NS);
+ assertThat(metadata.getTimeoutMillis()).isEqualTo(StatsManager.DEFAULT_TIMEOUT_MILLIS);
+ assertThat(metadata.getCoolDownMillis()).isEqualTo(StatsManager.DEFAULT_COOL_DOWN_MILLIS);
assertThat(metadata.getAdditiveFields()).isNull();
}
@Test
- public void testSetTimeoutNs() {
- long timeoutNs = 500_000_000L;
+ public void testSetTimeoutMillis() {
+ long timeoutMillis = 500L;
PullAtomMetadata metadata =
- new PullAtomMetadata.Builder().setTimeoutNs(timeoutNs).build();
- assertThat(metadata.getTimeoutNs()).isEqualTo(timeoutNs);
- assertThat(metadata.getCoolDownNs()).isEqualTo(StatsManager.DEFAULT_COOL_DOWN_NS);
+ new PullAtomMetadata.Builder().setTimeoutMillis(timeoutMillis).build();
+ assertThat(metadata.getTimeoutMillis()).isEqualTo(timeoutMillis);
+ assertThat(metadata.getCoolDownMillis()).isEqualTo(StatsManager.DEFAULT_COOL_DOWN_MILLIS);
assertThat(metadata.getAdditiveFields()).isNull();
}
@Test
- public void testSetCoolDownNs() {
- long coolDownNs = 10_000_000_000L;
+ public void testSetCoolDownMillis() {
+ long coolDownMillis = 10_000L;
PullAtomMetadata metadata =
- new PullAtomMetadata.Builder().setCoolDownNs(coolDownNs).build();
- assertThat(metadata.getTimeoutNs()).isEqualTo(StatsManager.DEFAULT_TIMEOUT_NS);
- assertThat(metadata.getCoolDownNs()).isEqualTo(coolDownNs);
+ new PullAtomMetadata.Builder().setCoolDownMillis(coolDownMillis).build();
+ assertThat(metadata.getTimeoutMillis()).isEqualTo(StatsManager.DEFAULT_TIMEOUT_MILLIS);
+ assertThat(metadata.getCoolDownMillis()).isEqualTo(coolDownMillis);
assertThat(metadata.getAdditiveFields()).isNull();
}
@@ -63,23 +63,23 @@ public final class PullAtomMetadataTest {
int[] fields = {2, 4, 6};
PullAtomMetadata metadata =
new PullAtomMetadata.Builder().setAdditiveFields(fields).build();
- assertThat(metadata.getTimeoutNs()).isEqualTo(StatsManager.DEFAULT_TIMEOUT_NS);
- assertThat(metadata.getCoolDownNs()).isEqualTo(StatsManager.DEFAULT_COOL_DOWN_NS);
+ assertThat(metadata.getTimeoutMillis()).isEqualTo(StatsManager.DEFAULT_TIMEOUT_MILLIS);
+ assertThat(metadata.getCoolDownMillis()).isEqualTo(StatsManager.DEFAULT_COOL_DOWN_MILLIS);
assertThat(metadata.getAdditiveFields()).isEqualTo(fields);
}
@Test
public void testSetAllElements() {
- long timeoutNs = 300L;
- long coolDownNs = 9572L;
+ long timeoutMillis = 300L;
+ long coolDownMillis = 9572L;
int[] fields = {3, 2};
PullAtomMetadata metadata = new PullAtomMetadata.Builder()
- .setTimeoutNs(timeoutNs)
- .setCoolDownNs(coolDownNs)
+ .setTimeoutMillis(timeoutMillis)
+ .setCoolDownMillis(coolDownMillis)
.setAdditiveFields(fields)
.build();
- assertThat(metadata.getTimeoutNs()).isEqualTo(timeoutNs);
- assertThat(metadata.getCoolDownNs()).isEqualTo(coolDownNs);
+ assertThat(metadata.getTimeoutMillis()).isEqualTo(timeoutMillis);
+ assertThat(metadata.getCoolDownMillis()).isEqualTo(coolDownMillis);
assertThat(metadata.getAdditiveFields()).isEqualTo(fields);
}
}
diff --git a/core/tests/coretests/src/android/util/StatsEventTest.java b/apex/statsd/framework/test/src/android/util/StatsEventTest.java
index ac25e2734ac9..ac25e2734ac9 100644
--- a/core/tests/coretests/src/android/util/StatsEventTest.java
+++ b/apex/statsd/framework/test/src/android/util/StatsEventTest.java
diff --git a/apex/statsd/service/java/com/android/server/stats/StatsCompanionService.java b/apex/statsd/service/java/com/android/server/stats/StatsCompanionService.java
index dc61f2aedf99..c84627de3e36 100644
--- a/apex/statsd/service/java/com/android/server/stats/StatsCompanionService.java
+++ b/apex/statsd/service/java/com/android/server/stats/StatsCompanionService.java
@@ -54,6 +54,7 @@ import java.io.FileDescriptor;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.PrintWriter;
+import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
@@ -102,9 +103,6 @@ public class StatsCompanionService extends IStatsCompanionService.Stub {
private final OnAlarmListener mAnomalyAlarmListener = new AnomalyAlarmListener();
private final OnAlarmListener mPullingAlarmListener = new PullingAlarmListener();
private final OnAlarmListener mPeriodicAlarmListener = new PeriodicAlarmListener();
- private final BroadcastReceiver mAppUpdateReceiver;
- private final BroadcastReceiver mUserUpdateReceiver;
- private final ShutdownEventReceiver mShutdownEventReceiver;
private StatsManagerService mStatsManagerService;
@@ -118,27 +116,6 @@ public class StatsCompanionService extends IStatsCompanionService.Stub {
super();
mContext = context;
mAlarmManager = (AlarmManager) mContext.getSystemService(Context.ALARM_SERVICE);
- mAppUpdateReceiver = new AppUpdateReceiver();
- mUserUpdateReceiver = new BroadcastReceiver() {
- @Override
- public void onReceive(Context context, Intent intent) {
- synchronized (sStatsdLock) {
- if (sStatsd == null) {
- Log.w(TAG, "Could not access statsd for UserUpdateReceiver");
- return;
- }
- try {
- // Pull the latest state of UID->app name, version mapping.
- // Needed since the new user basically has a version of every app.
- informAllUidsLocked(context);
- } catch (RemoteException e) {
- Log.e(TAG, "Failed to inform statsd latest update of all apps", e);
- forgetEverythingLocked();
- }
- }
- }
- };
- mShutdownEventReceiver = new ShutdownEventReceiver();
if (DEBUG) Log.d(TAG, "Registered receiver for ACTION_PACKAGE_REPLACED and ADDED.");
HandlerThread handlerThread = new HandlerThread(TAG);
handlerThread.start();
@@ -162,9 +139,18 @@ public class StatsCompanionService extends IStatsCompanionService.Stub {
return ret;
}
- // Assumes that sStatsdLock is held.
- @GuardedBy("sStatsdLock")
- private void informAllUidsLocked(Context context) throws RemoteException {
+ /**
+ * Non-blocking call to retrieve a reference to statsd
+ *
+ * @return IStatsd object if statsd is ready, null otherwise.
+ */
+ private static IStatsd getStatsdNonblocking() {
+ synchronized (sStatsdLock) {
+ return sStatsd;
+ }
+ }
+
+ private static void informAllUidsLocked(Context context) throws RemoteException {
UserManager um = (UserManager) context.getSystemService(Context.USER_SERVICE);
PackageManager pm = context.getPackageManager();
final List<UserHandle> users = um.getUserHandles(true);
@@ -273,7 +259,6 @@ public class StatsCompanionService extends IStatsCompanionService.Stub {
if (!replacing) {
// Don't bother sending an update if we're right about to get another
// intent for the new version that's added.
- PackageManager pm = context.getPackageManager();
String app = intent.getData().getSchemeSpecificPart();
sStatsd.informOnePackageRemoved(app, uid);
}
@@ -303,23 +288,43 @@ public class StatsCompanionService extends IStatsCompanionService.Stub {
}
}
- public final static class AnomalyAlarmListener implements OnAlarmListener {
+ private static final class UserUpdateReceiver extends BroadcastReceiver {
@Override
- public void onAlarm() {
- Log.i(TAG, "StatsCompanionService believes an anomaly has occurred at time "
- + System.currentTimeMillis() + "ms.");
+ public void onReceive(Context context, Intent intent) {
synchronized (sStatsdLock) {
if (sStatsd == null) {
- Log.w(TAG, "Could not access statsd to inform it of anomaly alarm firing");
+ Log.w(TAG, "Could not access statsd for UserUpdateReceiver");
return;
}
try {
- // Two-way call to statsd to retain AlarmManager wakelock
- sStatsd.informAnomalyAlarmFired();
+ // Pull the latest state of UID->app name, version mapping.
+ // Needed since the new user basically has a version of every app.
+ informAllUidsLocked(context);
} catch (RemoteException e) {
- Log.w(TAG, "Failed to inform statsd of anomaly alarm firing", e);
+ Log.e(TAG, "Failed to inform statsd latest update of all apps", e);
}
}
+ }
+ }
+
+ public static final class AnomalyAlarmListener implements OnAlarmListener {
+ @Override
+ public void onAlarm() {
+ if (DEBUG) {
+ Log.i(TAG, "StatsCompanionService believes an anomaly has occurred at time "
+ + System.currentTimeMillis() + "ms.");
+ }
+ IStatsd statsd = getStatsdNonblocking();
+ if (statsd == null) {
+ Log.w(TAG, "Could not access statsd to inform it of anomaly alarm firing");
+ return;
+ }
+ try {
+ // Two-way call to statsd to retain AlarmManager wakelock
+ statsd.informAnomalyAlarmFired();
+ } catch (RemoteException e) {
+ Log.w(TAG, "Failed to inform statsd of anomaly alarm firing", e);
+ }
// AlarmManager releases its own wakelock here.
}
}
@@ -330,17 +335,16 @@ public class StatsCompanionService extends IStatsCompanionService.Stub {
if (DEBUG) {
Log.d(TAG, "Time to poll something.");
}
- synchronized (sStatsdLock) {
- if (sStatsd == null) {
- Log.w(TAG, "Could not access statsd to inform it of pulling alarm firing.");
- return;
- }
- try {
- // Two-way call to statsd to retain AlarmManager wakelock
- sStatsd.informPollAlarmFired();
- } catch (RemoteException e) {
- Log.w(TAG, "Failed to inform statsd of pulling alarm firing.", e);
- }
+ IStatsd statsd = getStatsdNonblocking();
+ if (statsd == null) {
+ Log.w(TAG, "Could not access statsd to inform it of pulling alarm firing.");
+ return;
+ }
+ try {
+ // Two-way call to statsd to retain AlarmManager wakelock
+ statsd.informPollAlarmFired();
+ } catch (RemoteException e) {
+ Log.w(TAG, "Failed to inform statsd of pulling alarm firing.", e);
}
}
}
@@ -351,17 +355,16 @@ public class StatsCompanionService extends IStatsCompanionService.Stub {
if (DEBUG) {
Log.d(TAG, "Time to trigger periodic alarm.");
}
- synchronized (sStatsdLock) {
- if (sStatsd == null) {
- Log.w(TAG, "Could not access statsd to inform it of periodic alarm firing.");
- return;
- }
- try {
- // Two-way call to statsd to retain AlarmManager wakelock
- sStatsd.informAlarmForSubscriberTriggeringFired();
- } catch (RemoteException e) {
- Log.w(TAG, "Failed to inform statsd of periodic alarm firing.", e);
- }
+ IStatsd statsd = getStatsdNonblocking();
+ if (statsd == null) {
+ Log.w(TAG, "Could not access statsd to inform it of periodic alarm firing.");
+ return;
+ }
+ try {
+ // Two-way call to statsd to retain AlarmManager wakelock
+ statsd.informAlarmForSubscriberTriggeringFired();
+ } catch (RemoteException e) {
+ Log.w(TAG, "Failed to inform statsd of periodic alarm firing.", e);
}
// AlarmManager releases its own wakelock here.
}
@@ -379,17 +382,19 @@ public class StatsCompanionService extends IStatsCompanionService.Stub {
return;
}
- Log.i(TAG, "StatsCompanionService noticed a shutdown.");
- synchronized (sStatsdLock) {
- if (sStatsd == null) {
- Log.w(TAG, "Could not access statsd to inform it of a shutdown event.");
- return;
- }
- try {
- sStatsd.informDeviceShutdown();
- } catch (Exception e) {
- Log.w(TAG, "Failed to inform statsd of a shutdown event.", e);
- }
+ if (DEBUG) {
+ Log.i(TAG, "StatsCompanionService noticed a shutdown.");
+ }
+ IStatsd statsd = getStatsdNonblocking();
+ if (statsd == null) {
+ Log.w(TAG, "Could not access statsd to inform it of a shutdown event.");
+ return;
+ }
+ try {
+ // two way binder call
+ statsd.informDeviceShutdown();
+ } catch (Exception e) {
+ Log.w(TAG, "Failed to inform statsd of a shutdown event.", e);
}
}
}
@@ -515,7 +520,7 @@ public class StatsCompanionService extends IStatsCompanionService.Stub {
}
}
- @Override
+ @Override // Binder call
public void triggerUidSnapshot() {
StatsCompanion.enforceStatsdCallingUid();
synchronized (sStatsdLock) {
@@ -525,7 +530,7 @@ public class StatsCompanionService extends IStatsCompanionService.Stub {
} catch (RemoteException e) {
Log.e(TAG, "Failed to trigger uid snapshot.", e);
} finally {
- restoreCallingIdentity(token);
+ Binder.restoreCallingIdentity(token);
}
}
}
@@ -539,15 +544,28 @@ public class StatsCompanionService extends IStatsCompanionService.Stub {
// Statsd related code
/**
- * Fetches the statsd IBinder service.
- * Note: This should only be called from sayHiToStatsd. All other clients should use the cached
- * sStatsd with a null check.
+ * Fetches the statsd IBinder service. This is a blocking call.
+ * Note: This should only be called from {@link #sayHiToStatsd()}. All other clients should use
+ * the cached sStatsd via {@link #getStatsdNonblocking()}.
*/
- private static IStatsd fetchStatsdService() {
- return IStatsd.Stub.asInterface(StatsFrameworkInitializer
- .getStatsServiceManager()
- .getStatsdServiceRegisterer()
- .get());
+ private IStatsd fetchStatsdService(StatsdDeathRecipient deathRecipient) {
+ synchronized (sStatsdLock) {
+ if (sStatsd == null) {
+ sStatsd = IStatsd.Stub.asInterface(StatsFrameworkInitializer
+ .getStatsServiceManager()
+ .getStatsdServiceRegisterer()
+ .get());
+ if (sStatsd != null) {
+ try {
+ sStatsd.asBinder().linkToDeath(deathRecipient, /* flags */ 0);
+ } catch (RemoteException e) {
+ Log.e(TAG, "linkToDeath(StatsdDeathRecipient) failed");
+ statsdNotReadyLocked();
+ }
+ }
+ }
+ return sStatsd;
+ }
}
/**
@@ -567,67 +585,84 @@ public class StatsCompanionService extends IStatsCompanionService.Stub {
* statsd.
*/
private void sayHiToStatsd() {
- synchronized (sStatsdLock) {
- if (sStatsd != null) {
- Log.e(TAG, "Trying to fetch statsd, but it was already fetched",
- new IllegalStateException(
- "sStatsd is not null when being fetched"));
- return;
- }
- sStatsd = fetchStatsdService();
- if (sStatsd == null) {
- Log.i(TAG,
- "Could not yet find statsd to tell it that StatsCompanion is "
- + "alive.");
- return;
- }
- mStatsManagerService.statsdReady(sStatsd);
- if (DEBUG) Log.d(TAG, "Saying hi to statsd");
+ if (getStatsdNonblocking() != null) {
+ Log.e(TAG, "Trying to fetch statsd, but it was already fetched",
+ new IllegalStateException(
+ "sStatsd is not null when being fetched"));
+ return;
+ }
+ StatsdDeathRecipient deathRecipient = new StatsdDeathRecipient();
+ IStatsd statsd = fetchStatsdService(deathRecipient);
+ if (statsd == null) {
+ Log.i(TAG,
+ "Could not yet find statsd to tell it that StatsCompanion is "
+ + "alive.");
+ return;
+ }
+ mStatsManagerService.statsdReady(statsd);
+ if (DEBUG) Log.d(TAG, "Saying hi to statsd");
+ try {
+ statsd.statsCompanionReady();
+
+ cancelAnomalyAlarm();
+ cancelPullingAlarm();
+
+ BroadcastReceiver appUpdateReceiver = new AppUpdateReceiver();
+ BroadcastReceiver userUpdateReceiver = new UserUpdateReceiver();
+ BroadcastReceiver shutdownEventReceiver = new ShutdownEventReceiver();
+
+ // Setup broadcast receiver for updates.
+ IntentFilter filter = new IntentFilter(Intent.ACTION_PACKAGE_REPLACED);
+ filter.addAction(Intent.ACTION_PACKAGE_ADDED);
+ filter.addAction(Intent.ACTION_PACKAGE_REMOVED);
+ filter.addDataScheme("package");
+ mContext.registerReceiverForAllUsers(appUpdateReceiver, filter, null, null);
+
+ // Setup receiver for user initialize (which happens once for a new user)
+ // and
+ // if a user is removed.
+ filter = new IntentFilter(Intent.ACTION_USER_INITIALIZE);
+ filter.addAction(Intent.ACTION_USER_REMOVED);
+ mContext.registerReceiverForAllUsers(userUpdateReceiver, filter, null, null);
+
+ // Setup receiver for device reboots or shutdowns.
+ filter = new IntentFilter(Intent.ACTION_REBOOT);
+ filter.addAction(Intent.ACTION_SHUTDOWN);
+ mContext.registerReceiverForAllUsers(
+ shutdownEventReceiver, filter, null, null);
+
+ // Only add the receivers if the registration is successful.
+ deathRecipient.addRegisteredBroadcastReceivers(
+ List.of(appUpdateReceiver, userUpdateReceiver, shutdownEventReceiver));
+
+ final long token = Binder.clearCallingIdentity();
try {
- sStatsd.statsCompanionReady();
- // If the statsCompanionReady two-way binder call returns, link to statsd.
- try {
- sStatsd.asBinder().linkToDeath(new StatsdDeathRecipient(), 0);
- } catch (RemoteException e) {
- Log.e(TAG, "linkToDeath(StatsdDeathRecipient) failed", e);
- forgetEverythingLocked();
- }
- // Setup broadcast receiver for updates.
- IntentFilter filter = new IntentFilter(Intent.ACTION_PACKAGE_REPLACED);
- filter.addAction(Intent.ACTION_PACKAGE_ADDED);
- filter.addAction(Intent.ACTION_PACKAGE_REMOVED);
- filter.addDataScheme("package");
- mContext.registerReceiverForAllUsers(mAppUpdateReceiver, filter, null, null);
-
- // Setup receiver for user initialize (which happens once for a new user)
- // and
- // if a user is removed.
- filter = new IntentFilter(Intent.ACTION_USER_INITIALIZE);
- filter.addAction(Intent.ACTION_USER_REMOVED);
- mContext.registerReceiverForAllUsers(mUserUpdateReceiver, filter, null, null);
-
- // Setup receiver for device reboots or shutdowns.
- filter = new IntentFilter(Intent.ACTION_REBOOT);
- filter.addAction(Intent.ACTION_SHUTDOWN);
- mContext.registerReceiverForAllUsers(
- mShutdownEventReceiver, filter, null, null);
- final long token = Binder.clearCallingIdentity();
- try {
- // Pull the latest state of UID->app name, version mapping when
- // statsd starts.
- informAllUidsLocked(mContext);
- } finally {
- restoreCallingIdentity(token);
- }
- Log.i(TAG, "Told statsd that StatsCompanionService is alive.");
- } catch (RemoteException e) {
- Log.e(TAG, "Failed to inform statsd that statscompanion is ready", e);
- forgetEverythingLocked();
+ // Pull the latest state of UID->app name, version mapping when
+ // statsd starts.
+ informAllUidsLocked(mContext);
+ } finally {
+ Binder.restoreCallingIdentity(token);
}
+ Log.i(TAG, "Told statsd that StatsCompanionService is alive.");
+ } catch (RemoteException e) {
+ Log.e(TAG, "Failed to inform statsd that statscompanion is ready", e);
}
}
private class StatsdDeathRecipient implements IBinder.DeathRecipient {
+
+ private List<BroadcastReceiver> mReceiversToUnregister;
+
+ StatsdDeathRecipient() {
+ mReceiversToUnregister = new ArrayList<>();
+ }
+
+ public void addRegisteredBroadcastReceivers(List<BroadcastReceiver> receivers) {
+ synchronized (sStatsdLock) {
+ mReceiversToUnregister.addAll(receivers);
+ }
+ }
+
@Override
public void binderDied() {
Log.i(TAG, "Statsd is dead - erase all my knowledge, except pullers");
@@ -656,20 +691,18 @@ public class StatsCompanionService extends IStatsCompanionService.Stub {
}
}
}
- forgetEverythingLocked();
+ // We only unregister in binder death becaseu receivers can only be unregistered
+ // once, or an IllegalArgumentException is thrown.
+ for (BroadcastReceiver receiver: mReceiversToUnregister) {
+ mContext.unregisterReceiver(receiver);
+ }
+ statsdNotReadyLocked();
}
}
}
- @GuardedBy("StatsCompanionService.sStatsdLock")
- private void forgetEverythingLocked() {
+ private void statsdNotReadyLocked() {
sStatsd = null;
- mContext.unregisterReceiver(mAppUpdateReceiver);
- mContext.unregisterReceiver(mUserUpdateReceiver);
- mContext.unregisterReceiver(mShutdownEventReceiver);
- cancelAnomalyAlarm();
- cancelPullingAlarm();
-
mStatsManagerService.statsdNotReady();
}
diff --git a/apex/statsd/service/java/com/android/server/stats/StatsManagerService.java b/apex/statsd/service/java/com/android/server/stats/StatsManagerService.java
index 4e4bc40b727f..58c78da5cea7 100644
--- a/apex/statsd/service/java/com/android/server/stats/StatsManagerService.java
+++ b/apex/statsd/service/java/com/android/server/stats/StatsManagerService.java
@@ -136,25 +136,25 @@ public class StatsManagerService extends IStatsManagerService.Stub {
}
private static class PullerValue {
- private final long mCoolDownNs;
- private final long mTimeoutNs;
+ private final long mCoolDownMillis;
+ private final long mTimeoutMillis;
private final int[] mAdditiveFields;
private final IPullAtomCallback mCallback;
- PullerValue(long coolDownNs, long timeoutNs, int[] additiveFields,
+ PullerValue(long coolDownMillis, long timeoutMillis, int[] additiveFields,
IPullAtomCallback callback) {
- mCoolDownNs = coolDownNs;
- mTimeoutNs = timeoutNs;
+ mCoolDownMillis = coolDownMillis;
+ mTimeoutMillis = timeoutMillis;
mAdditiveFields = additiveFields;
mCallback = callback;
}
- public long getCoolDownNs() {
- return mCoolDownNs;
+ public long getCoolDownMillis() {
+ return mCoolDownMillis;
}
- public long getTimeoutNs() {
- return mTimeoutNs;
+ public long getTimeoutMillis() {
+ return mTimeoutMillis;
}
public int[] getAdditiveFields() {
@@ -169,12 +169,13 @@ public class StatsManagerService extends IStatsManagerService.Stub {
private final ArrayMap<PullerKey, PullerValue> mPullers = new ArrayMap<>();
@Override
- public void registerPullAtomCallback(int atomTag, long coolDownNs, long timeoutNs,
+ public void registerPullAtomCallback(int atomTag, long coolDownMillis, long timeoutMillis,
int[] additiveFields, IPullAtomCallback pullerCallback) {
enforceRegisterStatsPullAtomPermission();
int callingUid = Binder.getCallingUid();
PullerKey key = new PullerKey(callingUid, atomTag);
- PullerValue val = new PullerValue(coolDownNs, timeoutNs, additiveFields, pullerCallback);
+ PullerValue val =
+ new PullerValue(coolDownMillis, timeoutMillis, additiveFields, pullerCallback);
// Always cache the puller in StatsManagerService. If statsd is down, we will register the
// puller when statsd comes back up.
@@ -189,8 +190,8 @@ public class StatsManagerService extends IStatsManagerService.Stub {
final long token = Binder.clearCallingIdentity();
try {
- statsd.registerPullAtomCallback(
- callingUid, atomTag, coolDownNs, timeoutNs, additiveFields, pullerCallback);
+ statsd.registerPullAtomCallback(callingUid, atomTag, coolDownMillis, timeoutMillis,
+ additiveFields, pullerCallback);
} catch (RemoteException e) {
Log.e(TAG, "Failed to access statsd to register puller for atom " + atomTag);
} finally {
@@ -596,8 +597,8 @@ public class StatsManagerService extends IStatsManagerService.Stub {
for (Map.Entry<PullerKey, PullerValue> entry : pullersCopy.entrySet()) {
PullerKey key = entry.getKey();
PullerValue value = entry.getValue();
- statsd.registerPullAtomCallback(key.getUid(), key.getAtom(), value.getCoolDownNs(),
- value.getTimeoutNs(), value.getAdditiveFields(), value.getCallback());
+ statsd.registerPullAtomCallback(key.getUid(), key.getAtom(), value.getCoolDownMillis(),
+ value.getTimeoutMillis(), value.getAdditiveFields(), value.getCallback());
}
}
diff --git a/apex/statsd/tests/libstatspull/jni/stats_pull_helper.cpp b/apex/statsd/tests/libstatspull/jni/stats_pull_helper.cpp
index eb97f6559b6d..9e5aa952d9bc 100644
--- a/apex/statsd/tests/libstatspull/jni/stats_pull_helper.cpp
+++ b/apex/statsd/tests/libstatspull/jni/stats_pull_helper.cpp
@@ -14,7 +14,6 @@
* limitations under the License.
*/
-#include <android/binder_process.h>
#include <jni.h>
#include <log/log.h>
#include <stats_event.h>
@@ -32,17 +31,6 @@ static int64_t sLatencyMillis;
static int32_t sAtomsPerPull;
static int32_t sNumPulls = 0;
-static bool initialized = false;
-
-static void init() {
- if (!initialized) {
- initialized = true;
- // Set up the binder
- ABinderProcess_setThreadPoolMaxThreadCount(9);
- ABinderProcess_startThreadPool();
- }
-}
-
static AStatsManager_PullAtomCallbackReturn pullAtomCallback(int32_t atomTag, AStatsEventList* data,
void* /*cookie*/) {
sNumPulls++;
@@ -62,7 +50,6 @@ Java_com_android_internal_os_statsd_libstats_LibStatsPullTests_registerStatsPull
JNIEnv* /*env*/, jobject /* this */, jint atomTag, jlong timeoutNs, jlong coolDownNs,
jint pullRetVal, jlong latencyMillis, int atomsPerPull)
{
- init();
sAtomTag = atomTag;
sPullReturnVal = pullRetVal;
sLatencyMillis = latencyMillis;
diff --git a/apex/statsd/tests/libstatspull/src/com/android/internal/os/statsd/libstats/LibStatsPullTests.java b/apex/statsd/tests/libstatspull/src/com/android/internal/os/statsd/libstats/LibStatsPullTests.java
index e119b4c47604..d4e51e040d1c 100644
--- a/apex/statsd/tests/libstatspull/src/com/android/internal/os/statsd/libstats/LibStatsPullTests.java
+++ b/apex/statsd/tests/libstatspull/src/com/android/internal/os/statsd/libstats/LibStatsPullTests.java
@@ -229,7 +229,7 @@ public class LibStatsPullTests {
// Let the current bucket finish.
Thread.sleep(LONG_SLEEP_MILLIS);
List<Atom> data = StatsConfigUtils.getGaugeMetricDataList(statsManager, sConfigId);
- statsManager.unregisterPullAtomCallback(PULL_ATOM_TAG);
+ unregisterStatsPuller(PULL_ATOM_TAG);
assertThat(data.size()).isEqualTo(sAtomsPerPull);
for (int i = 0; i < data.size(); i++) {
diff --git a/api/current.txt b/api/current.txt
index 7acbdb4929f8..542a714be8e1 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -315,7 +315,7 @@ package android {
field public static final int animationOrder = 16843214; // 0x10101ce
field @Deprecated public static final int animationResolution = 16843546; // 0x101031a
field public static final int antialias = 16843034; // 0x101011a
- field public static final int anyDensity = 16843372; // 0x101026c
+ field @Deprecated public static final int anyDensity = 16843372; // 0x101026c
field public static final int apduServiceBanner = 16843757; // 0x10103ed
field public static final int apiKey = 16843281; // 0x1010211
field public static final int appCategory = 16844101; // 0x1010545
@@ -4368,7 +4368,7 @@ package android.app {
method @Deprecated public int noteProxyOpNoThrow(@NonNull String, @Nullable String, int);
method public int noteProxyOpNoThrow(@NonNull String, @Nullable String, int, @Nullable String, @Nullable String);
method @Nullable public static String permissionToOp(@NonNull String);
- method public void setNotedAppOpsCollector(@Nullable android.app.AppOpsManager.AppOpsCollector);
+ method public void setOnOpNotedCallback(@Nullable java.util.concurrent.Executor, @Nullable android.app.AppOpsManager.OnOpNotedCallback);
method @Deprecated public int startOp(@NonNull String, int, @NonNull String);
method public int startOp(@NonNull String, int, @Nullable String, @Nullable String, @Nullable String);
method @Deprecated public int startOpNoThrow(@NonNull String, int, @NonNull String);
@@ -4424,14 +4424,6 @@ package android.app {
field public static final int WATCH_FOREGROUND_CHANGES = 1; // 0x1
}
- public abstract static class AppOpsManager.AppOpsCollector {
- ctor public AppOpsManager.AppOpsCollector();
- method @NonNull public java.util.concurrent.Executor getAsyncNotedExecutor();
- method public abstract void onAsyncNoted(@NonNull android.app.AsyncNotedAppOp);
- method public abstract void onNoted(@NonNull android.app.SyncNotedAppOp);
- method public abstract void onSelfNoted(@NonNull android.app.SyncNotedAppOp);
- }
-
public static interface AppOpsManager.OnOpActiveChangedListener {
method public void onOpActiveChanged(@NonNull String, int, @NonNull String, boolean);
}
@@ -4440,6 +4432,13 @@ package android.app {
method public void onOpChanged(String, String);
}
+ public abstract static class AppOpsManager.OnOpNotedCallback {
+ ctor public AppOpsManager.OnOpNotedCallback();
+ method public abstract void onAsyncNoted(@NonNull android.app.AsyncNotedAppOp);
+ method public abstract void onNoted(@NonNull android.app.SyncNotedAppOp);
+ method public abstract void onSelfNoted(@NonNull android.app.SyncNotedAppOp);
+ }
+
public class Application extends android.content.ContextWrapper implements android.content.ComponentCallbacks2 {
ctor public Application();
method public static String getProcessName();
@@ -4572,14 +4571,17 @@ package android.app {
field public static final int REASON_ANR = 6; // 0x6
field public static final int REASON_CRASH = 4; // 0x4
field public static final int REASON_CRASH_NATIVE = 5; // 0x5
+ field public static final int REASON_DEPENDENCY_DIED = 12; // 0xc
field public static final int REASON_EXCESSIVE_RESOURCE_USAGE = 9; // 0x9
field public static final int REASON_EXIT_SELF = 1; // 0x1
field public static final int REASON_INITIALIZATION_FAILURE = 7; // 0x7
field public static final int REASON_LOW_MEMORY = 3; // 0x3
- field public static final int REASON_OTHER = 10; // 0xa
+ field public static final int REASON_OTHER = 13; // 0xd
field public static final int REASON_PERMISSION_CHANGE = 8; // 0x8
field public static final int REASON_SIGNALED = 2; // 0x2
field public static final int REASON_UNKNOWN = 0; // 0x0
+ field public static final int REASON_USER_REQUESTED = 10; // 0xa
+ field public static final int REASON_USER_STOPPED = 11; // 0xb
}
public final class AsyncNotedAppOp implements android.os.Parcelable {
@@ -4588,7 +4590,7 @@ package android.app {
method @NonNull public String getMessage();
method @IntRange(from=0) public int getNotingUid();
method @NonNull public String getOp();
- method @IntRange(from=0) public long getTime();
+ method public long getTime();
method public void writeToParcel(@NonNull android.os.Parcel, int);
field @NonNull public static final android.os.Parcelable.Creator<android.app.AsyncNotedAppOp> CREATOR;
}
@@ -7580,12 +7582,12 @@ package android.app.blob {
}
public class BlobStoreManager {
+ method public void abandonSession(@IntRange(from=1) long) throws java.io.IOException;
method public void acquireLease(@NonNull android.app.blob.BlobHandle, @IdRes int, long) throws java.io.IOException;
method public void acquireLease(@NonNull android.app.blob.BlobHandle, @NonNull CharSequence, long) throws java.io.IOException;
method public void acquireLease(@NonNull android.app.blob.BlobHandle, @IdRes int) throws java.io.IOException;
method public void acquireLease(@NonNull android.app.blob.BlobHandle, @NonNull CharSequence) throws java.io.IOException;
method @IntRange(from=1) public long createSession(@NonNull android.app.blob.BlobHandle) throws java.io.IOException;
- method public void deleteSession(@IntRange(from=1) long) throws java.io.IOException;
method @NonNull public android.os.ParcelFileDescriptor openBlob(@NonNull android.app.blob.BlobHandle) throws java.io.IOException;
method @NonNull public android.app.blob.BlobStoreManager.Session openSession(@IntRange(from=1) long) throws java.io.IOException;
method public void releaseLease(@NonNull android.app.blob.BlobHandle) throws java.io.IOException;
@@ -9921,8 +9923,11 @@ package android.content {
field public static final String EXTRA_REFRESH_SUPPORTED = "android.content.extra.REFRESH_SUPPORTED";
field public static final String EXTRA_SIZE = "android.content.extra.SIZE";
field public static final String EXTRA_TOTAL_COUNT = "android.content.extra.TOTAL_COUNT";
+ field public static final int NOTIFY_DELETE = 16; // 0x10
+ field public static final int NOTIFY_INSERT = 4; // 0x4
field public static final int NOTIFY_SKIP_NOTIFY_FOR_DESCENDANTS = 2; // 0x2
field public static final int NOTIFY_SYNC_TO_NETWORK = 1; // 0x1
+ field public static final int NOTIFY_UPDATE = 8; // 0x8
field public static final String QUERY_ARG_GROUP_COLUMNS = "android:query-arg-group-columns";
field public static final String QUERY_ARG_LIMIT = "android:query-arg-limit";
field public static final String QUERY_ARG_OFFSET = "android:query-arg-offset";
@@ -10560,6 +10565,7 @@ package android.content {
field public static final String ACTION_APP_ERROR = "android.intent.action.APP_ERROR";
field public static final String ACTION_ASSIST = "android.intent.action.ASSIST";
field public static final String ACTION_ATTACH_DATA = "android.intent.action.ATTACH_DATA";
+ field public static final String ACTION_AUTO_REVOKE_PERMISSIONS = "android.intent.action.AUTO_REVOKE_PERMISSIONS";
field public static final String ACTION_BATTERY_CHANGED = "android.intent.action.BATTERY_CHANGED";
field public static final String ACTION_BATTERY_LOW = "android.intent.action.BATTERY_LOW";
field public static final String ACTION_BATTERY_OKAY = "android.intent.action.BATTERY_OKAY";
@@ -11368,6 +11374,7 @@ package android.content.pm {
field public static final int FLAG_IMMERSIVE = 2048; // 0x800
field public static final int FLAG_MULTIPROCESS = 1; // 0x1
field public static final int FLAG_NO_HISTORY = 128; // 0x80
+ field public static final int FLAG_PREFER_MINIMAL_POST_PROCESSING = 33554432; // 0x2000000
field public static final int FLAG_RELINQUISH_TASK_IDENTITY = 4096; // 0x1000
field public static final int FLAG_RESUME_WHILE_PAUSING = 16384; // 0x4000
field public static final int FLAG_SINGLE_USER = 1073741824; // 0x40000000
@@ -11405,7 +11412,6 @@ package android.content.pm {
field public String parentActivityName;
field public String permission;
field public int persistableMode;
- field public boolean preferMinimalPostProcessing;
field public int screenOrientation;
field public int softInputMode;
field public String targetActivity;
@@ -11469,7 +11475,7 @@ package android.content.pm {
field public static final int FLAG_SUPPORTS_LARGE_SCREENS = 2048; // 0x800
field public static final int FLAG_SUPPORTS_NORMAL_SCREENS = 1024; // 0x400
field public static final int FLAG_SUPPORTS_RTL = 4194304; // 0x400000
- field public static final int FLAG_SUPPORTS_SCREEN_DENSITIES = 8192; // 0x2000
+ field @Deprecated public static final int FLAG_SUPPORTS_SCREEN_DENSITIES = 8192; // 0x2000
field public static final int FLAG_SUPPORTS_SMALL_SCREENS = 512; // 0x200
field public static final int FLAG_SUPPORTS_XLARGE_SCREENS = 524288; // 0x80000
field public static final int FLAG_SUSPENDED = 1073741824; // 0x40000000
@@ -12964,9 +12970,13 @@ package android.database {
ctor public ContentObserver(android.os.Handler);
method public boolean deliverSelfNotifications();
method @Deprecated public final void dispatchChange(boolean);
- method public final void dispatchChange(boolean, android.net.Uri);
+ method public final void dispatchChange(boolean, @Nullable android.net.Uri);
+ method public final void dispatchChange(boolean, @Nullable android.net.Uri, int);
+ method public final void dispatchChange(boolean, @NonNull Iterable<android.net.Uri>, int);
method public void onChange(boolean);
- method public void onChange(boolean, android.net.Uri);
+ method public void onChange(boolean, @Nullable android.net.Uri);
+ method public void onChange(boolean, @Nullable android.net.Uri, int);
+ method public void onChange(boolean, @NonNull Iterable<android.net.Uri>, int);
}
public interface CrossProcessCursor extends android.database.Cursor {
@@ -18108,9 +18118,7 @@ package android.hardware.fingerprint {
ctor @Deprecated public FingerprintManager.CryptoObject(@NonNull java.security.Signature);
ctor @Deprecated public FingerprintManager.CryptoObject(@NonNull javax.crypto.Cipher);
ctor @Deprecated public FingerprintManager.CryptoObject(@NonNull javax.crypto.Mac);
- ctor @Deprecated public FingerprintManager.CryptoObject(@NonNull android.security.identity.IdentityCredential);
method @Deprecated public javax.crypto.Cipher getCipher();
- method @Deprecated @Nullable public android.security.identity.IdentityCredential getIdentityCredential();
method @Deprecated public javax.crypto.Mac getMac();
method @Deprecated public java.security.Signature getSignature();
}
@@ -26403,7 +26411,7 @@ package android.media {
}
public final class MediaParser {
- method public boolean advance(@NonNull android.media.MediaParser.SeekableInputReader) throws java.io.IOException, java.lang.InterruptedException;
+ method public boolean advance(@NonNull android.media.MediaParser.SeekableInputReader) throws java.io.IOException;
method @NonNull public static android.media.MediaParser create(@NonNull android.media.MediaParser.OutputConsumer, @NonNull java.lang.String...);
method @NonNull public static android.media.MediaParser createByName(@NonNull String, @NonNull android.media.MediaParser.OutputConsumer);
method @Nullable public String getParserName();
@@ -26435,12 +26443,12 @@ package android.media {
public static interface MediaParser.InputReader {
method public long getLength();
method public long getPosition();
- method public int read(@NonNull byte[], int, int) throws java.io.IOException, java.lang.InterruptedException;
+ method public int read(@NonNull byte[], int, int) throws java.io.IOException;
}
public static interface MediaParser.OutputConsumer {
method public void onSampleCompleted(int, long, int, int, int, @Nullable android.media.MediaCodec.CryptoInfo);
- method public void onSampleData(int, @NonNull android.media.MediaParser.InputReader) throws java.io.IOException, java.lang.InterruptedException;
+ method public void onSampleData(int, @NonNull android.media.MediaParser.InputReader) throws java.io.IOException;
method public void onSeekMap(@NonNull android.media.MediaParser.SeekMap);
method public void onTrackData(int, @NonNull android.media.MediaParser.TrackData);
method public void onTracksFound(int);
@@ -26848,7 +26856,6 @@ package android.media {
method @Nullable public String getClientPackageName();
method public int getConnectionState();
method @Nullable public CharSequence getDescription();
- method public int getDeviceType();
method @Nullable public android.os.Bundle getExtras();
method @NonNull public java.util.List<java.lang.String> getFeatures();
method @Nullable public android.net.Uri getIconUri();
@@ -26863,10 +26870,6 @@ package android.media {
field public static final int CONNECTION_STATE_CONNECTING = 1; // 0x1
field public static final int CONNECTION_STATE_DISCONNECTED = 0; // 0x0
field @NonNull public static final android.os.Parcelable.Creator<android.media.MediaRoute2Info> CREATOR;
- field public static final int DEVICE_TYPE_BLUETOOTH = 3; // 0x3
- field public static final int DEVICE_TYPE_REMOTE_SPEAKER = 2; // 0x2
- field public static final int DEVICE_TYPE_REMOTE_TV = 1; // 0x1
- field public static final int DEVICE_TYPE_UNKNOWN = 0; // 0x0
field public static final String FEATURE_LIVE_AUDIO = "android.media.intent.category.LIVE_AUDIO";
field public static final String FEATURE_LIVE_VIDEO = "android.media.intent.category.LIVE_VIDEO";
field public static final String FEATURE_REMOTE_PLAYBACK = "android.media.intent.category.REMOTE_PLAYBACK";
@@ -26884,7 +26887,6 @@ package android.media {
method @NonNull public android.media.MediaRoute2Info.Builder setClientPackageName(@Nullable String);
method @NonNull public android.media.MediaRoute2Info.Builder setConnectionState(int);
method @NonNull public android.media.MediaRoute2Info.Builder setDescription(@Nullable CharSequence);
- method @NonNull public android.media.MediaRoute2Info.Builder setDeviceType(int);
method @NonNull public android.media.MediaRoute2Info.Builder setExtras(@Nullable android.os.Bundle);
method @NonNull public android.media.MediaRoute2Info.Builder setIconUri(@Nullable android.net.Uri);
method @NonNull public android.media.MediaRoute2Info.Builder setVolume(int);
@@ -26898,8 +26900,7 @@ package android.media {
method @Nullable public final android.media.RoutingSessionInfo getSessionInfo(@NonNull String);
method public final void notifyRequestFailed(long, int);
method public final void notifyRoutes(@NonNull java.util.Collection<android.media.MediaRoute2Info>);
- method public final void notifySessionCreated(@NonNull android.media.RoutingSessionInfo, long);
- method public final void notifySessionCreationFailed(long);
+ method public final void notifySessionCreated(long, @NonNull android.media.RoutingSessionInfo);
method public final void notifySessionReleased(@NonNull String);
method public final void notifySessionUpdated(@NonNull android.media.RoutingSessionInfo);
method @CallSuper @Nullable public android.os.IBinder onBind(@NonNull android.content.Intent);
@@ -27052,7 +27053,8 @@ package android.media {
method public void registerRouteCallback(@NonNull java.util.concurrent.Executor, @NonNull android.media.MediaRouter2.RouteCallback, @NonNull android.media.RouteDiscoveryPreference);
method public void registerTransferCallback(@NonNull java.util.concurrent.Executor, @NonNull android.media.MediaRouter2.TransferCallback);
method public void setOnGetControllerHintsListener(@Nullable android.media.MediaRouter2.OnGetControllerHintsListener);
- method public void transferTo(@Nullable android.media.MediaRoute2Info);
+ method public void stop();
+ method public void transferTo(@NonNull android.media.MediaRoute2Info);
method public void unregisterControllerCallback(@NonNull android.media.MediaRouter2.ControllerCallback);
method public void unregisterRouteCallback(@NonNull android.media.MediaRouter2.RouteCallback);
method public void unregisterTransferCallback(@NonNull android.media.MediaRouter2.TransferCallback);
@@ -27092,8 +27094,9 @@ package android.media {
public abstract static class MediaRouter2.TransferCallback {
ctor public MediaRouter2.TransferCallback();
+ method public void onStopped(@NonNull android.media.MediaRouter2.RoutingController);
method public void onTransferFailed(@NonNull android.media.MediaRoute2Info);
- method public void onTransferred(@NonNull android.media.MediaRouter2.RoutingController, @Nullable android.media.MediaRouter2.RoutingController);
+ method public void onTransferred(@NonNull android.media.MediaRouter2.RoutingController, @NonNull android.media.MediaRouter2.RoutingController);
}
public class MediaScannerConnection implements android.content.ServiceConnection {
@@ -36151,6 +36154,8 @@ package android.os {
method public static boolean isExternalStorageEmulated(@NonNull java.io.File);
method public static boolean isExternalStorageLegacy();
method public static boolean isExternalStorageLegacy(@NonNull java.io.File);
+ method public static boolean isExternalStorageManager();
+ method public static boolean isExternalStorageManager(@NonNull java.io.File);
method public static boolean isExternalStorageRemovable();
method public static boolean isExternalStorageRemovable(@NonNull java.io.File);
field public static String DIRECTORY_ALARMS;
@@ -36585,6 +36590,7 @@ package android.os {
method public static android.os.ParcelFileDescriptor open(java.io.File, int) throws java.io.FileNotFoundException;
method public static android.os.ParcelFileDescriptor open(java.io.File, int, android.os.Handler, android.os.ParcelFileDescriptor.OnCloseListener) throws java.io.IOException;
method public static int parseMode(String);
+ method @NonNull public static android.os.ParcelFileDescriptor wrap(@NonNull android.os.ParcelFileDescriptor, @NonNull android.os.Handler, @NonNull android.os.ParcelFileDescriptor.OnCloseListener) throws java.io.IOException;
method public void writeToParcel(android.os.Parcel, int);
field @NonNull public static final android.os.Parcelable.Creator<android.os.ParcelFileDescriptor> CREATOR;
field public static final int MODE_APPEND = 33554432; // 0x2000000
@@ -40565,7 +40571,7 @@ package android.provider {
field public static final String EXTRA_APP_PACKAGE = "android.provider.extra.APP_PACKAGE";
field public static final String EXTRA_AUTHORITIES = "authorities";
field public static final String EXTRA_BATTERY_SAVER_MODE_ENABLED = "android.settings.extra.battery_saver_mode_enabled";
- field public static final String EXTRA_BIOMETRIC_MINIMUM_STRENGTH_REQUIRED = "android.provider.extra.BIOMETRIC_MINIMUM_STRENGTH_REQUIRED";
+ field public static final String EXTRA_BIOMETRIC_AUTHENTICATORS_ALLOWED = "android.provider.extra.BIOMETRIC_AUTHENTICATORS_ALLOWED";
field public static final String EXTRA_CHANNEL_ID = "android.provider.extra.CHANNEL_ID";
field public static final String EXTRA_CONVERSATION_ID = "android.provider.extra.CONVERSATION_ID";
field public static final String EXTRA_DO_NOT_DISTURB_MODE_ENABLED = "android.settings.extra.do_not_disturb_mode_enabled";
@@ -42686,7 +42692,7 @@ package android.security.identity {
ctor public PersonalizationData.Builder();
method @NonNull public android.security.identity.PersonalizationData.Builder addAccessControlProfile(@NonNull android.security.identity.AccessControlProfile);
method @NonNull public android.security.identity.PersonalizationData build();
- method @NonNull public android.security.identity.PersonalizationData.Builder setEntry(@NonNull String, @NonNull String, @NonNull java.util.Collection<android.security.identity.AccessControlProfileId>, @NonNull byte[]);
+ method @NonNull public android.security.identity.PersonalizationData.Builder putEntry(@NonNull String, @NonNull String, @NonNull java.util.Collection<android.security.identity.AccessControlProfileId>, @NonNull byte[]);
}
public abstract class ResultData {
@@ -42694,7 +42700,7 @@ package android.security.identity {
method @Nullable public abstract byte[] getEntry(@NonNull String, @NonNull String);
method @Nullable public abstract java.util.Collection<java.lang.String> getEntryNames(@NonNull String);
method @Nullable public abstract byte[] getMessageAuthenticationCode();
- method @NonNull public abstract java.util.Collection<java.lang.String> getNamespaceNames();
+ method @NonNull public abstract java.util.Collection<java.lang.String> getNamespaces();
method @Nullable public abstract java.util.Collection<java.lang.String> getRetrievedEntryNames(@NonNull String);
method @NonNull public abstract byte[] getStaticAuthenticationData();
method public abstract int getStatus(@NonNull String, @NonNull String);
@@ -42784,7 +42790,7 @@ package android.security.keystore {
method @NonNull public android.security.keystore.KeyGenParameterSpec.Builder setRandomizedEncryptionRequired(boolean);
method @NonNull public android.security.keystore.KeyGenParameterSpec.Builder setSignaturePaddings(java.lang.String...);
method @NonNull public android.security.keystore.KeyGenParameterSpec.Builder setUnlockedDeviceRequired(boolean);
- method @NonNull public android.security.keystore.KeyGenParameterSpec.Builder setUserAuthenticationParameters(@IntRange(from=0xffffffff) int, int);
+ method @NonNull public android.security.keystore.KeyGenParameterSpec.Builder setUserAuthenticationParameters(@IntRange(from=0) int, int);
method @NonNull public android.security.keystore.KeyGenParameterSpec.Builder setUserAuthenticationRequired(boolean);
method @NonNull public android.security.keystore.KeyGenParameterSpec.Builder setUserAuthenticationValidWhileOnBody(boolean);
method @Deprecated @NonNull public android.security.keystore.KeyGenParameterSpec.Builder setUserAuthenticationValidityDurationSeconds(@IntRange(from=0xffffffff) int);
@@ -42902,7 +42908,7 @@ package android.security.keystore {
method @NonNull public android.security.keystore.KeyProtection.Builder setRandomizedEncryptionRequired(boolean);
method @NonNull public android.security.keystore.KeyProtection.Builder setSignaturePaddings(java.lang.String...);
method @NonNull public android.security.keystore.KeyProtection.Builder setUnlockedDeviceRequired(boolean);
- method @NonNull public android.security.keystore.KeyProtection.Builder setUserAuthenticationParameters(@IntRange(from=0xffffffff) int, int);
+ method @NonNull public android.security.keystore.KeyProtection.Builder setUserAuthenticationParameters(@IntRange(from=0) int, int);
method @NonNull public android.security.keystore.KeyProtection.Builder setUserAuthenticationRequired(boolean);
method @NonNull public android.security.keystore.KeyProtection.Builder setUserAuthenticationValidWhileOnBody(boolean);
method @Deprecated @NonNull public android.security.keystore.KeyProtection.Builder setUserAuthenticationValidityDurationSeconds(@IntRange(from=0xffffffff) int);
@@ -43106,7 +43112,7 @@ package android.service.autofill {
public static final class FillResponse.Builder {
ctor public FillResponse.Builder();
method @NonNull public android.service.autofill.FillResponse.Builder addDataset(@Nullable android.service.autofill.Dataset);
- method @NonNull public android.service.autofill.FillResponse.Builder addInlineAction(@NonNull android.service.autofill.InlinePresentation);
+ method @NonNull public android.service.autofill.FillResponse.Builder addInlineAction(@NonNull android.service.autofill.InlineAction);
method @NonNull public android.service.autofill.FillResponse build();
method @NonNull public android.service.autofill.FillResponse.Builder disableAutofill(long);
method @NonNull public android.service.autofill.FillResponse.Builder setAuthentication(@NonNull android.view.autofill.AutofillId[], @Nullable android.content.IntentSender, @Nullable android.widget.RemoteViews);
@@ -43136,6 +43142,15 @@ package android.service.autofill {
method public android.service.autofill.ImageTransformation build();
}
+ public final class InlineAction implements android.os.Parcelable {
+ ctor public InlineAction(@NonNull android.service.autofill.InlinePresentation, @NonNull android.content.IntentSender);
+ method public int describeContents();
+ method @NonNull public android.content.IntentSender getAction();
+ method @NonNull public android.service.autofill.InlinePresentation getInlinePresentation();
+ method public void writeToParcel(@NonNull android.os.Parcel, int);
+ field @NonNull public static final android.os.Parcelable.Creator<android.service.autofill.InlineAction> CREATOR;
+ }
+
public final class InlinePresentation implements android.os.Parcelable {
ctor public InlinePresentation(@NonNull android.app.slice.Slice, @NonNull android.view.inline.InlinePresentationSpec, boolean);
method public int describeContents();
@@ -43504,6 +43519,7 @@ package android.service.controls {
field public static final int TYPE_RADIATOR = 16; // 0x10
field public static final int TYPE_REFRIGERATOR = 48; // 0x30
field public static final int TYPE_REMOTE_CONTROL = 17; // 0x11
+ field public static final int TYPE_ROUTINE = 52; // 0x34
field public static final int TYPE_SECURITY_SYSTEM = 46; // 0x2e
field public static final int TYPE_SET_TOP = 18; // 0x12
field public static final int TYPE_SHOWER = 29; // 0x1d
@@ -43542,9 +43558,9 @@ package android.service.controls.actions {
public abstract class ControlAction {
method public abstract int getActionType();
method @Nullable public String getChallengeValue();
+ method @NonNull public static android.service.controls.actions.ControlAction getErrorAction();
method @NonNull public String getTemplateId();
method public static final boolean isValidResponse(int);
- field @NonNull public static final android.service.controls.actions.ControlAction ERROR_ACTION;
field public static final int RESPONSE_CHALLENGE_ACK = 3; // 0x3
field public static final int RESPONSE_CHALLENGE_PASSPHRASE = 5; // 0x5
field public static final int RESPONSE_CHALLENGE_PIN = 4; // 0x4
@@ -43556,7 +43572,6 @@ package android.service.controls.actions {
field public static final int TYPE_ERROR = -1; // 0xffffffff
field public static final int TYPE_FLOAT = 2; // 0x2
field public static final int TYPE_MODE = 4; // 0x4
- field public static final int TYPE_MULTI_FLOAT = 3; // 0x3
}
public final class FloatAction extends android.service.controls.actions.ControlAction {
@@ -43573,13 +43588,6 @@ package android.service.controls.actions {
method public int getNewMode();
}
- public final class MultiFloatAction extends android.service.controls.actions.ControlAction {
- ctor public MultiFloatAction(@NonNull String, @NonNull float[], @Nullable String);
- ctor public MultiFloatAction(@NonNull String, @NonNull float[]);
- method public int getActionType();
- method @NonNull public float[] getNewValues();
- }
-
}
package android.service.controls.templates {
@@ -43594,16 +43602,15 @@ package android.service.controls.templates {
}
public abstract class ControlTemplate {
+ method @NonNull public static android.service.controls.templates.ControlTemplate getErrorTemplate();
+ method @NonNull public static android.service.controls.templates.ControlTemplate getNoTemplateObject();
method @NonNull public String getTemplateId();
method public abstract int getTemplateType();
- field @NonNull public static final android.service.controls.templates.ControlTemplate ERROR_TEMPLATE;
- field @NonNull public static final android.service.controls.templates.ControlTemplate NO_TEMPLATE;
field public static final int TYPE_ERROR = -1; // 0xffffffff
- field public static final int TYPE_NONE = 0; // 0x0
+ field public static final int TYPE_NO_TEMPLATE = 0; // 0x0
field public static final int TYPE_RANGE = 2; // 0x2
field public static final int TYPE_STATELESS = 8; // 0x8
field public static final int TYPE_TEMPERATURE = 7; // 0x7
- field public static final int TYPE_THUMBNAIL = 3; // 0x3
field public static final int TYPE_TOGGLE = 1; // 0x1
field public static final int TYPE_TOGGLE_RANGE = 6; // 0x6
}
@@ -43643,13 +43650,6 @@ package android.service.controls.templates {
field public static final int MODE_UNKNOWN = 0; // 0x0
}
- public final class ThumbnailTemplate extends android.service.controls.templates.ControlTemplate {
- ctor public ThumbnailTemplate(@NonNull String, @NonNull android.graphics.drawable.Icon, @NonNull CharSequence);
- method @NonNull public CharSequence getContentDescription();
- method public int getTemplateType();
- method @NonNull public android.graphics.drawable.Icon getThumbnail();
- }
-
public final class ToggleRangeTemplate extends android.service.controls.templates.ControlTemplate {
ctor public ToggleRangeTemplate(@NonNull String, @NonNull android.service.controls.templates.ControlButton, @NonNull android.service.controls.templates.RangeTemplate);
ctor public ToggleRangeTemplate(@NonNull String, boolean, @NonNull CharSequence, @NonNull android.service.controls.templates.RangeTemplate);
@@ -48305,10 +48305,6 @@ package android.telephony {
field public static final String EXTRA_SUBSCRIPTION_ID = "android.telephony.extra.SUBSCRIPTION_ID";
field public static final String EXTRA_VOICEMAIL_NUMBER = "android.telephony.extra.VOICEMAIL_NUMBER";
field public static final String METADATA_HIDE_VOICEMAIL_SETTINGS_MENU = "android.telephony.HIDE_VOICEMAIL_SETTINGS_MENU";
- field public static final int MODEM_COUNT_DUAL_MODEM = 2; // 0x2
- field public static final int MODEM_COUNT_NO_MODEM = 0; // 0x0
- field public static final int MODEM_COUNT_SINGLE_MODEM = 1; // 0x1
- field public static final int MODEM_COUNT_TRI_MODEM = 3; // 0x3
field public static final int MULTISIM_ALLOWED = 0; // 0x0
field public static final int MULTISIM_NOT_SUPPORTED_BY_CARRIER = 2; // 0x2
field public static final int MULTISIM_NOT_SUPPORTED_BY_HARDWARE = 1; // 0x1
@@ -56172,7 +56168,7 @@ package android.view.accessibility {
}
public static final class AccessibilityNodeInfo.ExtraRenderingInfo {
- method @Nullable public android.util.Size getLayoutParams();
+ method @Nullable public android.util.Size getLayoutSize();
method public float getTextSizeInPx();
method public int getTextSizeUnit();
}
@@ -82238,4 +82234,3 @@ package org.xmlpull.v1.sax2 {
}
}
-
diff --git a/api/module-lib-current.txt b/api/module-lib-current.txt
index 6863221f7fda..69b52693aa46 100644
--- a/api/module-lib-current.txt
+++ b/api/module-lib-current.txt
@@ -47,6 +47,7 @@ package android.net {
method @NonNull public String[] getTetheredIfaces();
method @NonNull public String[] getTetheringErroredIfaces();
method public boolean isTetheringSupported();
+ method public boolean isTetheringSupported(@NonNull String);
method @RequiresPermission(android.Manifest.permission.ACCESS_NETWORK_STATE) public void registerTetheringEventCallback(@NonNull java.util.concurrent.Executor, @NonNull android.net.TetheringManager.TetheringEventCallback);
method @RequiresPermission(anyOf={"android.permission.TETHER_PRIVILEGED", android.Manifest.permission.WRITE_SETTINGS}) public void requestLatestTetheringEntitlementResult(int, boolean, @NonNull java.util.concurrent.Executor, @NonNull android.net.TetheringManager.OnTetheringEntitlementResultListener);
method public void requestLatestTetheringEntitlementResult(int, @NonNull android.os.ResultReceiver, boolean);
@@ -86,6 +87,9 @@ package android.net {
field public static final int TETHER_ERROR_UNKNOWN_IFACE = 1; // 0x1
field public static final int TETHER_ERROR_UNSUPPORTED = 3; // 0x3
field public static final int TETHER_ERROR_UNTETHER_IFACE_ERROR = 7; // 0x7
+ field public static final int TETHER_HARDWARE_OFFLOAD_FAILED = 2; // 0x2
+ field public static final int TETHER_HARDWARE_OFFLOAD_STARTED = 1; // 0x1
+ field public static final int TETHER_HARDWARE_OFFLOAD_STOPPED = 0; // 0x0
}
public static interface TetheringManager.OnTetheringEntitlementResultListener {
@@ -102,6 +106,7 @@ package android.net {
ctor public TetheringManager.TetheringEventCallback();
method public void onClientsChanged(@NonNull java.util.Collection<android.net.TetheredClient>);
method public void onError(@NonNull String, int);
+ method public void onOffloadStatusChanged(int);
method @Deprecated public void onTetherableInterfaceRegexpsChanged(@NonNull android.net.TetheringManager.TetheringInterfaceRegexps);
method public void onTetherableInterfacesChanged(@NonNull java.util.List<java.lang.String>);
method public void onTetheredInterfacesChanged(@NonNull java.util.List<java.lang.String>);
diff --git a/api/system-current.txt b/api/system-current.txt
index 379ae579e8b7..74bd2197af85 100755
--- a/api/system-current.txt
+++ b/api/system-current.txt
@@ -388,6 +388,7 @@ package android.app {
field public static final String OPSTR_AUDIO_NOTIFICATION_VOLUME = "android:audio_notification_volume";
field public static final String OPSTR_AUDIO_RING_VOLUME = "android:audio_ring_volume";
field public static final String OPSTR_AUDIO_VOICE_VOLUME = "android:audio_voice_volume";
+ field public static final String OPSTR_AUTO_REVOKE_PERMISSIONS_IF_UNUSED = "android:auto_revoke_permissions_if_unused";
field public static final String OPSTR_BIND_ACCESSIBILITY_SERVICE = "android:bind_accessibility_service";
field public static final String OPSTR_CHANGE_WIFI_STATE = "android:change_wifi_state";
field public static final String OPSTR_GET_ACCOUNTS = "android:get_accounts";
@@ -702,12 +703,12 @@ package android.app {
public final class StatsManager {
method @RequiresPermission(allOf={android.Manifest.permission.DUMP, android.Manifest.permission.PACKAGE_USAGE_STATS}) public void addConfig(long, byte[]) throws android.app.StatsManager.StatsUnavailableException;
method @Deprecated @RequiresPermission(allOf={android.Manifest.permission.DUMP, android.Manifest.permission.PACKAGE_USAGE_STATS}) public boolean addConfiguration(long, byte[]);
+ method @RequiresPermission(android.Manifest.permission.REGISTER_STATS_PULL_ATOM) public void clearPullAtomCallback(int);
method @Deprecated @Nullable @RequiresPermission(allOf={android.Manifest.permission.DUMP, android.Manifest.permission.PACKAGE_USAGE_STATS}) public byte[] getData(long);
method @Deprecated @Nullable @RequiresPermission(allOf={android.Manifest.permission.DUMP, android.Manifest.permission.PACKAGE_USAGE_STATS}) public byte[] getMetadata();
method @RequiresPermission(allOf={android.Manifest.permission.DUMP, android.Manifest.permission.PACKAGE_USAGE_STATS}) public long[] getRegisteredExperimentIds() throws android.app.StatsManager.StatsUnavailableException;
method @RequiresPermission(allOf={android.Manifest.permission.DUMP, android.Manifest.permission.PACKAGE_USAGE_STATS}) public byte[] getReports(long) throws android.app.StatsManager.StatsUnavailableException;
method @RequiresPermission(allOf={android.Manifest.permission.DUMP, android.Manifest.permission.PACKAGE_USAGE_STATS}) public byte[] getStatsMetadata() throws android.app.StatsManager.StatsUnavailableException;
- method @RequiresPermission(android.Manifest.permission.REGISTER_STATS_PULL_ATOM) public void registerPullAtomCallback(int, @Nullable android.app.StatsManager.PullAtomMetadata, @NonNull java.util.concurrent.Executor, @NonNull android.app.StatsManager.StatsPullAtomCallback);
method @RequiresPermission(allOf={android.Manifest.permission.DUMP, android.Manifest.permission.PACKAGE_USAGE_STATS}) public void removeConfig(long) throws android.app.StatsManager.StatsUnavailableException;
method @Deprecated @RequiresPermission(allOf={android.Manifest.permission.DUMP, android.Manifest.permission.PACKAGE_USAGE_STATS}) public boolean removeConfiguration(long);
method @NonNull @RequiresPermission(allOf={android.Manifest.permission.DUMP, android.Manifest.permission.PACKAGE_USAGE_STATS}) public long[] setActiveConfigsChangedOperation(@Nullable android.app.PendingIntent) throws android.app.StatsManager.StatsUnavailableException;
@@ -715,7 +716,7 @@ package android.app {
method @Deprecated @RequiresPermission(allOf={android.Manifest.permission.DUMP, android.Manifest.permission.PACKAGE_USAGE_STATS}) public boolean setBroadcastSubscriber(long, long, android.app.PendingIntent);
method @Deprecated @RequiresPermission(allOf={android.Manifest.permission.DUMP, android.Manifest.permission.PACKAGE_USAGE_STATS}) public boolean setDataFetchOperation(long, android.app.PendingIntent);
method @RequiresPermission(allOf={android.Manifest.permission.DUMP, android.Manifest.permission.PACKAGE_USAGE_STATS}) public void setFetchReportsOperation(android.app.PendingIntent, long) throws android.app.StatsManager.StatsUnavailableException;
- method @RequiresPermission(android.Manifest.permission.REGISTER_STATS_PULL_ATOM) public void unregisterPullAtomCallback(int);
+ method @RequiresPermission(android.Manifest.permission.REGISTER_STATS_PULL_ATOM) public void setPullAtomCallback(int, @Nullable android.app.StatsManager.PullAtomMetadata, @NonNull java.util.concurrent.Executor, @NonNull android.app.StatsManager.StatsPullAtomCallback);
field public static final String ACTION_STATSD_STARTED = "android.app.action.STATSD_STARTED";
field public static final String EXTRA_STATS_ACTIVE_CONFIG_KEYS = "android.app.extra.STATS_ACTIVE_CONFIG_KEYS";
field public static final String EXTRA_STATS_BROADCAST_SUBSCRIBER_COOKIES = "android.app.extra.STATS_BROADCAST_SUBSCRIBER_COOKIES";
@@ -729,14 +730,17 @@ package android.app {
}
public static class StatsManager.PullAtomMetadata {
+ method @Nullable public int[] getAdditiveFields();
+ method public long getCoolDownMillis();
+ method public long getTimeoutMillis();
}
public static class StatsManager.PullAtomMetadata.Builder {
ctor public StatsManager.PullAtomMetadata.Builder();
method @NonNull public android.app.StatsManager.PullAtomMetadata build();
method @NonNull public android.app.StatsManager.PullAtomMetadata.Builder setAdditiveFields(@NonNull int[]);
- method @NonNull public android.app.StatsManager.PullAtomMetadata.Builder setCoolDownNs(long);
- method @NonNull public android.app.StatsManager.PullAtomMetadata.Builder setTimeoutNs(long);
+ method @NonNull public android.app.StatsManager.PullAtomMetadata.Builder setCoolDownMillis(long);
+ method @NonNull public android.app.StatsManager.PullAtomMetadata.Builder setTimeoutMillis(long);
}
public static interface StatsManager.StatsPullAtomCallback {
@@ -921,14 +925,6 @@ package android.app.admin {
}
-package android.app.appsearch {
-
- public class AppSearchManagerFrameworkInitializer {
- method public static void initialize();
- }
-
-}
-
package android.app.assist {
public static class AssistStructure.ViewNode {
@@ -1469,16 +1465,16 @@ package android.app.usage {
package android.bluetooth {
public final class BluetoothA2dp implements android.bluetooth.BluetoothProfile {
- method @RequiresPermission(android.Manifest.permission.BLUETOOTH_PRIVILEGED) public void disableOptionalCodecs(@Nullable android.bluetooth.BluetoothDevice);
- method @RequiresPermission(android.Manifest.permission.BLUETOOTH_PRIVILEGED) public void enableOptionalCodecs(@Nullable android.bluetooth.BluetoothDevice);
+ method @RequiresPermission(android.Manifest.permission.BLUETOOTH_PRIVILEGED) public void disableOptionalCodecs(@NonNull android.bluetooth.BluetoothDevice);
+ method @RequiresPermission(android.Manifest.permission.BLUETOOTH_PRIVILEGED) public void enableOptionalCodecs(@NonNull android.bluetooth.BluetoothDevice);
method @Nullable @RequiresPermission(android.Manifest.permission.BLUETOOTH) public android.bluetooth.BluetoothDevice getActiveDevice();
- method @Nullable @RequiresPermission(android.Manifest.permission.BLUETOOTH) public android.bluetooth.BluetoothCodecStatus getCodecStatus(@Nullable android.bluetooth.BluetoothDevice);
+ method @Nullable @RequiresPermission(android.Manifest.permission.BLUETOOTH) public android.bluetooth.BluetoothCodecStatus getCodecStatus(@NonNull android.bluetooth.BluetoothDevice);
method @RequiresPermission(android.Manifest.permission.BLUETOOTH) public int getConnectionPolicy(@NonNull android.bluetooth.BluetoothDevice);
- method @RequiresPermission(android.Manifest.permission.BLUETOOTH_ADMIN) public int getOptionalCodecsEnabled(@Nullable android.bluetooth.BluetoothDevice);
- method @RequiresPermission(android.Manifest.permission.BLUETOOTH_PRIVILEGED) public void setCodecConfigPreference(@Nullable android.bluetooth.BluetoothDevice, @Nullable android.bluetooth.BluetoothCodecConfig);
+ method @RequiresPermission(android.Manifest.permission.BLUETOOTH_ADMIN) public int isOptionalCodecsEnabled(@NonNull android.bluetooth.BluetoothDevice);
+ method @RequiresPermission(android.Manifest.permission.BLUETOOTH_ADMIN) public int isOptionalCodecsSupported(@NonNull android.bluetooth.BluetoothDevice);
+ method @RequiresPermission(android.Manifest.permission.BLUETOOTH_PRIVILEGED) public void setCodecConfigPreference(@NonNull android.bluetooth.BluetoothDevice, @NonNull android.bluetooth.BluetoothCodecConfig);
method @RequiresPermission(android.Manifest.permission.BLUETOOTH_ADMIN) public boolean setConnectionPolicy(@NonNull android.bluetooth.BluetoothDevice, int);
- method @RequiresPermission(android.Manifest.permission.BLUETOOTH_PRIVILEGED) public void setOptionalCodecsEnabled(@Nullable android.bluetooth.BluetoothDevice, int);
- method @RequiresPermission(android.Manifest.permission.BLUETOOTH_ADMIN) public int supportsOptionalCodecs(@Nullable android.bluetooth.BluetoothDevice);
+ method @RequiresPermission(android.Manifest.permission.BLUETOOTH_PRIVILEGED) public void setOptionalCodecsEnabled(@NonNull android.bluetooth.BluetoothDevice, int);
field public static final int OPTIONAL_CODECS_NOT_SUPPORTED = 0; // 0x0
field public static final int OPTIONAL_CODECS_PREF_DISABLED = 0; // 0x0
field public static final int OPTIONAL_CODECS_PREF_ENABLED = 1; // 0x1
@@ -1763,8 +1759,8 @@ package android.companion {
package android.content {
- public class ApexContext {
- method @NonNull public static android.content.ApexContext getApexContext(@NonNull String);
+ public class ApexEnvironment {
+ method @NonNull public static android.content.ApexEnvironment getApexEnvironment(@NonNull String);
method @NonNull public java.io.File getCredentialProtectedDataDirForUser(@NonNull android.os.UserHandle);
method @NonNull public java.io.File getDeviceProtectedDataDir();
method @NonNull public java.io.File getDeviceProtectedDataDirForUser(@NonNull android.os.UserHandle);
@@ -2019,7 +2015,6 @@ package android.content.pm {
}
public final class InstallationFile {
- ctor public InstallationFile(int, @NonNull String, long, @Nullable byte[], @Nullable byte[]);
method public long getLengthBytes();
method public int getLocation();
method @Nullable public byte[] getMetadata();
@@ -2221,9 +2216,7 @@ package android.content.pm {
field public static final String FEATURE_TELEPHONY_CARRIERLOCK = "android.hardware.telephony.carrierlock";
field public static final int FLAGS_PERMISSION_RESERVED_PERMISSIONCONTROLLER = -268435456; // 0xf0000000
field public static final int FLAG_PERMISSION_APPLY_RESTRICTION = 16384; // 0x4000
- field public static final int FLAG_PERMISSION_AUTO_REVOKED = 1048576; // 0x100000
- field public static final int FLAG_PERMISSION_AUTO_REVOKE_IF_UNUSED = 131072; // 0x20000
- field public static final int FLAG_PERMISSION_AUTO_REVOKE_USER_SET = 262144; // 0x40000
+ field public static final int FLAG_PERMISSION_AUTO_REVOKED = 131072; // 0x20000
field public static final int FLAG_PERMISSION_GRANTED_BY_DEFAULT = 32; // 0x20
field public static final int FLAG_PERMISSION_GRANTED_BY_ROLE = 32768; // 0x8000
field public static final int FLAG_PERMISSION_ONE_TIME = 65536; // 0x10000
@@ -2307,7 +2300,7 @@ package android.content.pm {
method public void onPermissionsChanged(int);
}
- @IntDef(prefix={"FLAG_PERMISSION_"}, value={android.content.pm.PackageManager.FLAG_PERMISSION_USER_SET, android.content.pm.PackageManager.FLAG_PERMISSION_USER_FIXED, android.content.pm.PackageManager.FLAG_PERMISSION_POLICY_FIXED, android.content.pm.PackageManager.FLAG_PERMISSION_REVOKE_ON_UPGRADE, android.content.pm.PackageManager.FLAG_PERMISSION_SYSTEM_FIXED, android.content.pm.PackageManager.FLAG_PERMISSION_GRANTED_BY_DEFAULT, android.content.pm.PackageManager.FLAG_PERMISSION_USER_SENSITIVE_WHEN_GRANTED, android.content.pm.PackageManager.FLAG_PERMISSION_USER_SENSITIVE_WHEN_DENIED, android.content.pm.PackageManager.FLAG_PERMISSION_RESTRICTION_UPGRADE_EXEMPT, android.content.pm.PackageManager.FLAG_PERMISSION_RESTRICTION_SYSTEM_EXEMPT, android.content.pm.PackageManager.FLAG_PERMISSION_RESTRICTION_INSTALLER_EXEMPT, android.content.pm.PackageManager.FLAG_PERMISSION_APPLY_RESTRICTION, android.content.pm.PackageManager.FLAG_PERMISSION_GRANTED_BY_ROLE, android.content.pm.PackageManager.FLAG_PERMISSION_REVOKED_COMPAT, android.content.pm.PackageManager.FLAG_PERMISSION_ONE_TIME, android.content.pm.PackageManager.FLAG_PERMISSION_AUTO_REVOKE_IF_UNUSED, android.content.pm.PackageManager.FLAG_PERMISSION_AUTO_REVOKE_USER_SET, android.content.pm.PackageManager.FLAG_PERMISSION_AUTO_REVOKED}) @java.lang.annotation.Retention(java.lang.annotation.RetentionPolicy.SOURCE) public static @interface PackageManager.PermissionFlags {
+ @IntDef(prefix={"FLAG_PERMISSION_"}, value={android.content.pm.PackageManager.FLAG_PERMISSION_USER_SET, android.content.pm.PackageManager.FLAG_PERMISSION_USER_FIXED, android.content.pm.PackageManager.FLAG_PERMISSION_POLICY_FIXED, android.content.pm.PackageManager.FLAG_PERMISSION_REVOKE_ON_UPGRADE, android.content.pm.PackageManager.FLAG_PERMISSION_SYSTEM_FIXED, android.content.pm.PackageManager.FLAG_PERMISSION_GRANTED_BY_DEFAULT, android.content.pm.PackageManager.FLAG_PERMISSION_USER_SENSITIVE_WHEN_GRANTED, android.content.pm.PackageManager.FLAG_PERMISSION_USER_SENSITIVE_WHEN_DENIED, android.content.pm.PackageManager.FLAG_PERMISSION_RESTRICTION_UPGRADE_EXEMPT, android.content.pm.PackageManager.FLAG_PERMISSION_RESTRICTION_SYSTEM_EXEMPT, android.content.pm.PackageManager.FLAG_PERMISSION_RESTRICTION_INSTALLER_EXEMPT, android.content.pm.PackageManager.FLAG_PERMISSION_APPLY_RESTRICTION, android.content.pm.PackageManager.FLAG_PERMISSION_GRANTED_BY_ROLE, android.content.pm.PackageManager.FLAG_PERMISSION_REVOKED_COMPAT, android.content.pm.PackageManager.FLAG_PERMISSION_ONE_TIME, android.content.pm.PackageManager.FLAG_PERMISSION_AUTO_REVOKED}) @java.lang.annotation.Retention(java.lang.annotation.RetentionPolicy.SOURCE) public static @interface PackageManager.PermissionFlags {
}
public class PermissionGroupInfo extends android.content.pm.PackageItemInfo implements android.os.Parcelable {
@@ -4730,7 +4723,7 @@ package android.media.tv {
public final class TvInputManager {
method @RequiresPermission(android.Manifest.permission.TV_INPUT_HARDWARE) public android.media.tv.TvInputManager.Hardware acquireTvInputHardware(int, @NonNull android.media.tv.TvInputInfo, @NonNull android.media.tv.TvInputManager.HardwareCallback);
- method @Nullable @RequiresPermission(android.Manifest.permission.TV_INPUT_HARDWARE) public android.media.tv.TvInputManager.Hardware acquireTvInputHardware(int, @NonNull android.media.tv.TvInputInfo, @NonNull android.media.tv.TvInputManager.HardwareCallback, @Nullable String, int);
+ method @Nullable @RequiresPermission(android.Manifest.permission.TV_INPUT_HARDWARE) public android.media.tv.TvInputManager.Hardware acquireTvInputHardware(int, @NonNull android.media.tv.TvInputInfo, @Nullable String, int, @NonNull java.util.concurrent.Executor, @NonNull android.media.tv.TvInputManager.HardwareCallback);
method @RequiresPermission(android.Manifest.permission.MODIFY_PARENTAL_CONTROLS) public void addBlockedRating(@NonNull android.media.tv.TvContentRating);
method @RequiresPermission(android.Manifest.permission.CAPTURE_TV_INPUT) public boolean captureFrame(String, android.view.Surface, android.media.tv.TvStreamConfig);
method @RequiresPermission(android.Manifest.permission.CAPTURE_TV_INPUT) public java.util.List<android.media.tv.TvStreamConfig> getAvailableTvStreamConfigList(String);
@@ -5000,6 +4993,11 @@ package android.media.tv.tuner.filter {
field public static final int LENGTH_TYPE_UNDEFINED = 0; // 0x0
field public static final int LENGTH_TYPE_WITHOUT_ADDITIONAL_HEADER = 1; // 0x1
field public static final int LENGTH_TYPE_WITH_ADDITIONAL_HEADER = 2; // 0x2
+ field public static final int PACKET_TYPE_COMPRESSED = 2; // 0x2
+ field public static final int PACKET_TYPE_EXTENSION = 6; // 0x6
+ field public static final int PACKET_TYPE_IPV4 = 0; // 0x0
+ field public static final int PACKET_TYPE_MPEG2_TS = 7; // 0x7
+ field public static final int PACKET_TYPE_SIGNALING = 4; // 0x4
}
public static class AlpFilterConfiguration.Builder extends android.media.tv.tuner.filter.FilterConfiguration.Builder<android.media.tv.tuner.filter.AlpFilterConfiguration.Builder> {
@@ -5080,6 +5078,7 @@ package android.media.tv.tuner.filter {
field public static final int TYPE_MMTP = 2; // 0x2
field public static final int TYPE_TLV = 8; // 0x8
field public static final int TYPE_TS = 1; // 0x1
+ field public static final int TYPE_UNDEFINED = 0; // 0x0
}
public interface FilterCallback {
@@ -5090,9 +5089,6 @@ package android.media.tv.tuner.filter {
public abstract class FilterConfiguration {
method @Nullable public android.media.tv.tuner.filter.Settings getSettings();
method public abstract int getType();
- field public static final int PACKET_TYPE_COMPRESSED = 2; // 0x2
- field public static final int PACKET_TYPE_IPV4 = 0; // 0x0
- field public static final int PACKET_TYPE_SIGNALING = 4; // 0x4
}
public abstract static class FilterConfiguration.Builder<T extends android.media.tv.tuner.filter.FilterConfiguration.Builder<T>> {
@@ -5290,6 +5286,11 @@ package android.media.tv.tuner.filter {
method public int getType();
method public boolean isCompressedIpPacket();
method public boolean isPassthrough();
+ field public static final int PACKET_TYPE_COMPRESSED = 3; // 0x3
+ field public static final int PACKET_TYPE_IPV4 = 1; // 0x1
+ field public static final int PACKET_TYPE_IPV6 = 2; // 0x2
+ field public static final int PACKET_TYPE_NULL = 255; // 0xff
+ field public static final int PACKET_TYPE_SIGNALING = 254; // 0xfe
}
public static class TlvFilterConfiguration.Builder extends android.media.tv.tuner.filter.FilterConfiguration.Builder<android.media.tv.tuner.filter.TlvFilterConfiguration.Builder> {
@@ -6125,7 +6126,7 @@ package android.net {
}
public class EthernetManager {
- method @NonNull public android.net.EthernetManager.TetheredInterfaceRequest requestTetheredInterface(@NonNull android.net.EthernetManager.TetheredInterfaceCallback);
+ method @NonNull @RequiresPermission(anyOf={android.Manifest.permission.NETWORK_STACK, android.net.NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK}) public android.net.EthernetManager.TetheredInterfaceRequest requestTetheredInterface(@NonNull java.util.concurrent.Executor, @NonNull android.net.EthernetManager.TetheredInterfaceCallback);
}
public static interface EthernetManager.TetheredInterfaceCallback {
@@ -6591,6 +6592,9 @@ package android.net {
field public static final int TETHER_ERROR_UNKNOWN_IFACE = 1; // 0x1
field public static final int TETHER_ERROR_UNSUPPORTED = 3; // 0x3
field public static final int TETHER_ERROR_UNTETHER_IFACE_ERROR = 7; // 0x7
+ field public static final int TETHER_HARDWARE_OFFLOAD_FAILED = 2; // 0x2
+ field public static final int TETHER_HARDWARE_OFFLOAD_STARTED = 1; // 0x1
+ field public static final int TETHER_HARDWARE_OFFLOAD_STOPPED = 0; // 0x0
}
public static interface TetheringManager.OnTetheringEntitlementResultListener {
@@ -6607,6 +6611,7 @@ package android.net {
ctor public TetheringManager.TetheringEventCallback();
method public void onClientsChanged(@NonNull java.util.Collection<android.net.TetheredClient>);
method public void onError(@NonNull String, int);
+ method public void onOffloadStatusChanged(int);
method @Deprecated public void onTetherableInterfaceRegexpsChanged(@NonNull android.net.TetheringManager.TetheringInterfaceRegexps);
method public void onTetherableInterfacesChanged(@NonNull java.util.List<java.lang.String>);
method public void onTetheredInterfacesChanged(@NonNull java.util.List<java.lang.String>);
@@ -7325,7 +7330,7 @@ package android.net.wifi {
method @RequiresPermission(android.Manifest.permission.CONNECTIVITY_INTERNAL) public void factoryReset();
method @RequiresPermission(anyOf={android.Manifest.permission.NETWORK_SETTINGS, android.Manifest.permission.NETWORK_SETUP_WIZARD, android.Manifest.permission.NETWORK_STACK}) public void forget(int, @Nullable android.net.wifi.WifiManager.ActionListener);
method @NonNull @RequiresPermission(anyOf={android.Manifest.permission.NETWORK_SETTINGS, android.Manifest.permission.NETWORK_SETUP_WIZARD}) public java.util.List<android.util.Pair<android.net.wifi.WifiConfiguration,java.util.Map<java.lang.Integer,java.util.List<android.net.wifi.ScanResult>>>> getAllMatchingWifiConfigs(@NonNull java.util.List<android.net.wifi.ScanResult>);
- method @Nullable @RequiresPermission(android.Manifest.permission.CONNECTIVITY_INTERNAL) public String getCountryCode();
+ method @Nullable @RequiresPermission(android.Manifest.permission.NETWORK_SETTINGS) public String getCountryCode();
method @Nullable @RequiresPermission(anyOf={android.Manifest.permission.NETWORK_SETTINGS, android.Manifest.permission.NETWORK_SETUP_WIZARD}) public android.net.Network getCurrentNetwork();
method @NonNull @RequiresPermission(android.Manifest.permission.NETWORK_SETTINGS) public String[] getFactoryMacAddresses();
method @NonNull @RequiresPermission(anyOf={android.Manifest.permission.NETWORK_SETTINGS, android.Manifest.permission.NETWORK_SETUP_WIZARD}) public java.util.Map<android.net.wifi.hotspot2.OsuProvider,java.util.List<android.net.wifi.ScanResult>> getMatchingOsuProviders(@Nullable java.util.List<android.net.wifi.ScanResult>);
@@ -7453,9 +7458,9 @@ package android.net.wifi {
method public void onWifiUsabilityStats(int, boolean, @NonNull android.net.wifi.WifiUsabilityStatsEntry);
}
- public static interface WifiManager.ScoreChangeCallback {
- method public void onScoreChange(int, int);
- method public void onTriggerUpdateOfWifiUsabilityStats(int);
+ public static interface WifiManager.ScoreUpdateObserver {
+ method public void notifyScoreUpdate(int, int);
+ method public void triggerUpdateOfWifiUsabilityStats(int);
}
public static interface WifiManager.SoftApCallback {
@@ -7475,9 +7480,9 @@ package android.net.wifi {
}
public static interface WifiManager.WifiConnectedNetworkScorer {
- method public void setScoreChangeCallback(@NonNull android.net.wifi.WifiManager.ScoreChangeCallback);
- method public void start(int);
- method public void stop(int);
+ method public void onSetScoreUpdateObserver(@NonNull android.net.wifi.WifiManager.ScoreUpdateObserver);
+ method public void onStart(int);
+ method public void onStop(int);
}
public final class WifiMigration {
@@ -7809,9 +7814,6 @@ package android.net.wifi.nl80211 {
method public int getMaxNumberTxSpatialStreams();
method public boolean isChannelWidthSupported(int);
method public boolean isWifiStandardSupported(int);
- method public void setChannelWidthSupported(int, boolean);
- method public void setMaxNumberRxSpatialStreams(int);
- method public void setMaxNumberTxSpatialStreams(int);
method public void setWifiStandardSupport(int, boolean);
method public void writeToParcel(@NonNull android.os.Parcel, int);
field @NonNull public static final android.os.Parcelable.Creator<android.net.wifi.nl80211.DeviceWiphyCapabilities> CREATOR;
@@ -8140,8 +8142,8 @@ package android.os {
method @RequiresPermission(android.Manifest.permission.UPDATE_DEVICE_STATS) public void reportFullWifiLockReleasedFromSource(@NonNull android.os.WorkSource);
method @RequiresPermission(android.Manifest.permission.UPDATE_DEVICE_STATS) public void reportWifiBatchedScanStartedFromSource(@NonNull android.os.WorkSource, @IntRange(from=0) int);
method @RequiresPermission(android.Manifest.permission.UPDATE_DEVICE_STATS) public void reportWifiBatchedScanStoppedFromSource(@NonNull android.os.WorkSource);
- method @RequiresPermission(android.Manifest.permission.UPDATE_DEVICE_STATS) public void reportWifiMulticastDisabled(int);
- method @RequiresPermission(android.Manifest.permission.UPDATE_DEVICE_STATS) public void reportWifiMulticastEnabled(int);
+ method @RequiresPermission(android.Manifest.permission.UPDATE_DEVICE_STATS) public void reportWifiMulticastDisabled(@NonNull android.os.WorkSource);
+ method @RequiresPermission(android.Manifest.permission.UPDATE_DEVICE_STATS) public void reportWifiMulticastEnabled(@NonNull android.os.WorkSource);
method @RequiresPermission(android.Manifest.permission.UPDATE_DEVICE_STATS) public void reportWifiOff();
method @RequiresPermission(android.Manifest.permission.UPDATE_DEVICE_STATS) public void reportWifiOn();
method @RequiresPermission(android.Manifest.permission.UPDATE_DEVICE_STATS) public void reportWifiRssiChanged(@IntRange(from=0xffffff81, to=0) int);
@@ -8464,10 +8466,6 @@ package android.os {
method public boolean hasSingleFileDescriptor();
}
- public class ParcelFileDescriptor implements java.io.Closeable android.os.Parcelable {
- method @NonNull public static android.os.ParcelFileDescriptor wrap(@NonNull android.os.ParcelFileDescriptor, @NonNull android.os.Handler, @NonNull android.os.ParcelFileDescriptor.OnCloseListener) throws java.io.IOException;
- }
-
public final class PowerManager {
method @RequiresPermission(allOf={android.Manifest.permission.READ_DREAM_STATE, android.Manifest.permission.WRITE_DREAM_STATE}) public void dream(long);
method @RequiresPermission(android.Manifest.permission.DEVICE_POWER) public boolean forceSuspend();
@@ -9128,6 +9126,7 @@ package android.provider {
field public static final String NAMESPACE_ATTENTION_MANAGER_SERVICE = "attention_manager_service";
field public static final String NAMESPACE_AUTOFILL = "autofill";
field public static final String NAMESPACE_BIOMETRICS = "biometrics";
+ field public static final String NAMESPACE_BLOBSTORE = "blobstore";
field public static final String NAMESPACE_CONNECTIVITY = "connectivity";
field public static final String NAMESPACE_CONTENT_CAPTURE = "content_capture";
field @Deprecated public static final String NAMESPACE_DEX_BOOT = "dex_boot";
@@ -9200,9 +9199,9 @@ package android.provider {
public final class MediaStore {
method @NonNull public static android.net.Uri rewriteToLegacy(@NonNull android.net.Uri);
- method @NonNull public static android.net.Uri scanFile(@NonNull android.content.ContentResolver, @NonNull java.io.File);
- method public static void scanVolume(@NonNull android.content.ContentResolver, @NonNull String);
- method public static void waitForIdle(@NonNull android.content.ContentResolver);
+ method @NonNull @WorkerThread public static android.net.Uri scanFile(@NonNull android.content.ContentResolver, @NonNull java.io.File);
+ method @WorkerThread public static void scanVolume(@NonNull android.content.ContentResolver, @NonNull String);
+ method @WorkerThread public static void waitForIdle(@NonNull android.content.ContentResolver);
field public static final String AUTHORITY_LEGACY = "media_legacy";
field @NonNull public static final android.net.Uri AUTHORITY_LEGACY_URI;
}
@@ -9863,10 +9862,10 @@ package android.service.autofill.augmented {
public static final class FillResponse.Builder {
ctor public FillResponse.Builder();
method @NonNull public android.service.autofill.augmented.FillResponse build();
- method @NonNull public android.service.autofill.augmented.FillResponse.Builder setClientState(@Nullable android.os.Bundle);
- method @NonNull public android.service.autofill.augmented.FillResponse.Builder setFillWindow(@Nullable android.service.autofill.augmented.FillWindow);
- method @NonNull public android.service.autofill.augmented.FillResponse.Builder setInlineActions(@Nullable java.util.List<android.service.autofill.InlinePresentation>);
- method @NonNull public android.service.autofill.augmented.FillResponse.Builder setInlineSuggestions(@Nullable java.util.List<android.service.autofill.Dataset>);
+ method @NonNull public android.service.autofill.augmented.FillResponse.Builder setClientState(@NonNull android.os.Bundle);
+ method @NonNull public android.service.autofill.augmented.FillResponse.Builder setFillWindow(@NonNull android.service.autofill.augmented.FillWindow);
+ method @NonNull public android.service.autofill.augmented.FillResponse.Builder setInlineActions(@NonNull java.util.List<android.service.autofill.InlineAction>);
+ method @NonNull public android.service.autofill.augmented.FillResponse.Builder setInlineSuggestions(@NonNull java.util.List<android.service.autofill.Dataset>);
}
public final class FillWindow implements java.lang.AutoCloseable {
@@ -10912,19 +10911,6 @@ package android.telephony {
method @NonNull public java.util.List<android.telephony.CbGeoUtils.LatLng> getVertices();
}
- public final class CdmaEriInformation implements android.os.Parcelable {
- method public int describeContents();
- method public int getEriIconIndex();
- method public int getEriIconMode();
- method public void writeToParcel(@NonNull android.os.Parcel, int);
- field @NonNull public static final android.os.Parcelable.Creator<android.telephony.CdmaEriInformation> CREATOR;
- field public static final int ERI_FLASH = 2; // 0x2
- field public static final int ERI_ICON_MODE_FLASH = 1; // 0x1
- field public static final int ERI_ICON_MODE_NORMAL = 0; // 0x0
- field public static final int ERI_OFF = 1; // 0x1
- field public static final int ERI_ON = 0; // 0x0
- }
-
public class CellBroadcastIntents {
method public static void sendSmsCbReceivedBroadcast(@NonNull android.content.Context, @Nullable android.os.UserHandle, @NonNull android.telephony.SmsCbMessage, @Nullable android.content.BroadcastReceiver, @Nullable android.os.Handler, int, int);
field public static final String ACTION_AREA_INFO_UPDATED = "android.telephony.action.AREA_INFO_UPDATED";
@@ -11523,7 +11509,7 @@ package android.telephony {
public class SmsMessage {
method @Nullable public static android.telephony.SmsMessage createFromNativeSmsSubmitPdu(@NonNull byte[], boolean);
method @Nullable public static android.telephony.SmsMessage.SubmitPdu getSmsPdu(int, int, @Nullable String, @NonNull String, @NonNull String, long);
- method @NonNull @RequiresPermission(android.Manifest.permission.BLUETOOTH_PRIVILEGED) public static byte[] getSubmitPduEncodedMessage(boolean, @NonNull String, @NonNull String, int, int, int, int, int, int);
+ method @NonNull @RequiresPermission(android.Manifest.permission.BLUETOOTH_PRIVILEGED) public static byte[] getSubmitPduEncodedMessage(boolean, @NonNull String, @NonNull String, int, @IntRange(from=0) int, @IntRange(from=0) int, @IntRange(from=0, to=255) int, @IntRange(from=1, to=255) int, @IntRange(from=1, to=255) int);
}
public class SubscriptionInfo implements android.os.Parcelable {
@@ -11620,7 +11606,6 @@ package android.telephony {
method @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public int getCarrierPrivilegeStatus(int);
method @NonNull @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public java.util.List<java.lang.String> getCarrierPrivilegedPackagesForAllActiveSubscriptions();
method @Nullable @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public android.telephony.CarrierRestrictionRules getCarrierRestrictionRules();
- method @NonNull @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public android.telephony.CdmaEriInformation getCdmaEriInformation();
method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public String getCdmaMdn();
method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public String getCdmaMdn(int);
method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public String getCdmaMin();
@@ -11666,7 +11651,6 @@ package android.telephony {
method @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public boolean isAnyRadioPoweredOn();
method @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public boolean isApnMetered(int);
method @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public boolean isApplicationOnUicc(int);
- method public boolean isCurrentSimOperator(@NonNull String, int, @Nullable String);
method @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public boolean isDataAllowedInVoiceCall();
method @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public boolean isDataConnectionEnabled();
method public boolean isDataConnectivityPossible();
@@ -11685,6 +11669,7 @@ package android.telephony {
method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public boolean isTetheringApnRequired();
method @Deprecated @RequiresPermission(anyOf={android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE, android.Manifest.permission.READ_PHONE_STATE}) public boolean isVideoCallingEnabled();
method @Deprecated @RequiresPermission(android.Manifest.permission.READ_PHONE_STATE) public boolean isVisualVoicemailEnabled(android.telecom.PhoneAccountHandle);
+ method @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public boolean matchesCurrentSimOperator(@NonNull String, int, @Nullable String);
method public boolean modifyDevicePolicyOverrideApn(@NonNull android.content.Context, int, @NonNull android.telephony.data.ApnSetting);
method public boolean needsOtaServiceProvisioning();
method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public void notifyOtaEmergencyNumberDbInstalled();
@@ -11697,6 +11682,7 @@ package android.telephony {
method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public void resetAllCarrierActions();
method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public void resetCarrierKeysForImsiEncryption();
method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) @WorkerThread public void resetIms(int);
+ method @RequiresPermission(android.Manifest.permission.READ_ACTIVE_EMERGENCY_SESSION) public void resetOtaEmergencyNumberDbFilePath();
method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public boolean resetRadioConfig();
method @RequiresPermission(android.Manifest.permission.CONNECTIVITY_INTERNAL) public void resetSettings();
method @Deprecated @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public int setAllowedCarriers(int, java.util.List<android.service.carrier.CarrierIdentifier>);
@@ -11734,8 +11720,8 @@ package android.telephony {
method @Deprecated @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public int[] supplyPukReportResult(String, String);
method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public boolean switchSlots(int[]);
method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public void toggleRadioOnOff();
+ method @RequiresPermission(android.Manifest.permission.READ_ACTIVE_EMERGENCY_SESSION) public void updateOtaEmergencyNumberDbFilePath(@NonNull android.os.ParcelFileDescriptor);
method public void updateServiceLocation();
- method @RequiresPermission(android.Manifest.permission.READ_ACTIVE_EMERGENCY_SESSION) public void updateTestOtaEmergencyNumberDbFilePath(@NonNull String);
field @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public static final String ACTION_ANOMALY_REPORTED = "android.telephony.action.ANOMALY_REPORTED";
field public static final String ACTION_CARRIER_SIGNAL_DEFAULT_NETWORK_AVAILABLE = "com.android.internal.telephony.CARRIER_SIGNAL_DEFAULT_NETWORK_AVAILABLE";
field public static final String ACTION_CARRIER_SIGNAL_PCO_VALUE = "com.android.internal.telephony.CARRIER_SIGNAL_PCO_VALUE";
@@ -12245,7 +12231,7 @@ package android.telephony.ims {
method public int getEmergencyServiceCategories();
method @NonNull public java.util.List<java.lang.String> getEmergencyUrns();
method public android.telephony.ims.ImsStreamMediaProfile getMediaProfile();
- method @Nullable public android.os.Bundle getProprietaryCallExtras();
+ method @NonNull public android.os.Bundle getProprietaryCallExtras();
method public int getRestrictCause();
method public int getServiceType();
method public static int getVideoStateFromCallType(int);
@@ -12703,8 +12689,8 @@ package android.telephony.ims {
field public static final int KEY_RCS_CAPABILITY_DISCOVERY_ENABLED = 17; // 0x11
field public static final int KEY_RCS_CAPABILITY_POLL_LIST_SUB_EXP_SEC = 23; // 0x17
field public static final int KEY_RCS_MAX_NUM_ENTRIES_IN_RCL = 22; // 0x16
+ field public static final int KEY_RCS_PUBLISH_OFFLINE_AVAILABILITY_TIMER_SEC = 16; // 0x10
field public static final int KEY_RCS_PUBLISH_SOURCE_THROTTLE_MS = 21; // 0x15
- field public static final int KEY_RCS_PUBLISH_TIMER_EXTENDED_SEC = 16; // 0x10
field public static final int KEY_RCS_PUBLISH_TIMER_SEC = 15; // 0xf
field public static final int KEY_REGISTRATION_DOMAIN_NAME = 12; // 0xc
field public static final int KEY_REGISTRATION_RETRY_BASE_TIME_SEC = 33; // 0x21
diff --git a/api/system-removed.txt b/api/system-removed.txt
index 07b896905986..23e2499236b3 100644
--- a/api/system-removed.txt
+++ b/api/system-removed.txt
@@ -11,6 +11,12 @@ package android.app {
public class AppOpsManager {
method @Deprecated @NonNull @RequiresPermission(android.Manifest.permission.GET_APP_OPS_STATS) public java.util.List<android.app.AppOpsManager.PackageOps> getOpsForPackage(int, @NonNull String, @Nullable int[]);
+ method @Deprecated public void setNotedAppOpsCollector(@Nullable android.app.AppOpsManager.AppOpsCollector);
+ }
+
+ @Deprecated public abstract static class AppOpsManager.AppOpsCollector extends android.app.AppOpsManager.OnOpNotedCallback {
+ ctor public AppOpsManager.AppOpsCollector();
+ method @NonNull public java.util.concurrent.Executor getAsyncNotedExecutor();
}
public class Notification implements android.os.Parcelable {
diff --git a/api/test-current.txt b/api/test-current.txt
index a42710da1000..9d284b59cdb3 100644
--- a/api/test-current.txt
+++ b/api/test-current.txt
@@ -590,6 +590,14 @@ package android.app.backup {
}
+package android.app.blob {
+
+ public class BlobStoreManager {
+ method public void waitForIdle(long) throws java.lang.InterruptedException, java.util.concurrent.TimeoutException;
+ }
+
+}
+
package android.app.prediction {
public final class AppPredictionContext implements android.os.Parcelable {
@@ -784,6 +792,8 @@ package android.content {
}
public abstract class ContentResolver {
+ method @NonNull public static android.net.Uri decodeFromFile(@NonNull java.io.File);
+ method @NonNull public static java.io.File encodeToFile(@NonNull android.net.Uri);
method public static String[] getSyncAdapterPackagesForAuthorityAsUser(String, int);
}
@@ -1727,7 +1737,7 @@ package android.net {
}
public class EthernetManager {
- method @NonNull public android.net.EthernetManager.TetheredInterfaceRequest requestTetheredInterface(@NonNull android.net.EthernetManager.TetheredInterfaceCallback);
+ method @NonNull @RequiresPermission(anyOf={android.Manifest.permission.NETWORK_STACK, android.net.NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK}) public android.net.EthernetManager.TetheredInterfaceRequest requestTetheredInterface(@NonNull java.util.concurrent.Executor, @NonNull android.net.EthernetManager.TetheredInterfaceCallback);
}
public static interface EthernetManager.TetheredInterfaceCallback {
@@ -1909,6 +1919,9 @@ package android.net {
field public static final int TETHER_ERROR_UNKNOWN_IFACE = 1; // 0x1
field public static final int TETHER_ERROR_UNSUPPORTED = 3; // 0x3
field public static final int TETHER_ERROR_UNTETHER_IFACE_ERROR = 7; // 0x7
+ field public static final int TETHER_HARDWARE_OFFLOAD_FAILED = 2; // 0x2
+ field public static final int TETHER_HARDWARE_OFFLOAD_STARTED = 1; // 0x1
+ field public static final int TETHER_HARDWARE_OFFLOAD_STOPPED = 0; // 0x0
}
public static interface TetheringManager.OnTetheringEntitlementResultListener {
@@ -1925,6 +1938,7 @@ package android.net {
ctor public TetheringManager.TetheringEventCallback();
method public void onClientsChanged(@NonNull java.util.Collection<android.net.TetheredClient>);
method public void onError(@NonNull String, int);
+ method public void onOffloadStatusChanged(int);
method @Deprecated public void onTetherableInterfaceRegexpsChanged(@NonNull android.net.TetheringManager.TetheringInterfaceRegexps);
method public void onTetherableInterfacesChanged(@NonNull java.util.List<java.lang.String>);
method public void onTetheredInterfacesChanged(@NonNull java.util.List<java.lang.String>);
@@ -2915,10 +2929,15 @@ package android.provider {
method @NonNull public android.provider.DeviceConfig.Properties.Builder setString(@NonNull String, @Nullable String);
}
+ public final class DocumentsContract {
+ method public static boolean isManageMode(@NonNull android.net.Uri);
+ method @NonNull public static android.net.Uri setManageMode(@NonNull android.net.Uri);
+ }
+
public final class MediaStore {
- method @NonNull public static android.net.Uri scanFile(@NonNull android.content.ContentResolver, @NonNull java.io.File);
- method public static void scanVolume(@NonNull android.content.ContentResolver, @NonNull String);
- method public static void waitForIdle(@NonNull android.content.ContentResolver);
+ method @NonNull @WorkerThread public static android.net.Uri scanFile(@NonNull android.content.ContentResolver, @NonNull java.io.File);
+ method @WorkerThread public static void scanVolume(@NonNull android.content.ContentResolver, @NonNull String);
+ method @WorkerThread public static void waitForIdle(@NonNull android.content.ContentResolver);
}
public final class Settings {
@@ -3223,10 +3242,10 @@ package android.service.autofill.augmented {
public static final class FillResponse.Builder {
ctor public FillResponse.Builder();
method @NonNull public android.service.autofill.augmented.FillResponse build();
- method @NonNull public android.service.autofill.augmented.FillResponse.Builder setClientState(@Nullable android.os.Bundle);
- method @NonNull public android.service.autofill.augmented.FillResponse.Builder setFillWindow(@Nullable android.service.autofill.augmented.FillWindow);
- method @NonNull public android.service.autofill.augmented.FillResponse.Builder setInlineActions(@Nullable java.util.List<android.service.autofill.InlinePresentation>);
- method @NonNull public android.service.autofill.augmented.FillResponse.Builder setInlineSuggestions(@Nullable java.util.List<android.service.autofill.Dataset>);
+ method @NonNull public android.service.autofill.augmented.FillResponse.Builder setClientState(@NonNull android.os.Bundle);
+ method @NonNull public android.service.autofill.augmented.FillResponse.Builder setFillWindow(@NonNull android.service.autofill.augmented.FillWindow);
+ method @NonNull public android.service.autofill.augmented.FillResponse.Builder setInlineActions(@NonNull java.util.List<android.service.autofill.InlineAction>);
+ method @NonNull public android.service.autofill.augmented.FillResponse.Builder setInlineSuggestions(@NonNull java.util.List<android.service.autofill.Dataset>);
}
public final class FillWindow implements java.lang.AutoCloseable {
@@ -3728,11 +3747,12 @@ package android.telephony {
method public android.util.Pair<java.lang.Integer,java.lang.Integer> getRadioHalVersion();
method public boolean modifyDevicePolicyOverrideApn(@NonNull android.content.Context, int, @NonNull android.telephony.data.ApnSetting);
method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public void refreshUiccProfile();
+ method @RequiresPermission("android.permission.READ_ACTIVE_EMERGENCY_SESSION") public void resetOtaEmergencyNumberDbFilePath();
method @Deprecated public void setCarrierTestOverride(String, String, String, String, String, String, String);
method public void setCarrierTestOverride(String, String, String, String, String, String, String, String, String);
method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public void setSystemSelectionChannels(@NonNull java.util.List<android.telephony.RadioAccessSpecifier>, @NonNull java.util.concurrent.Executor, @NonNull java.util.function.Consumer<java.lang.Boolean>);
method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public void setSystemSelectionChannels(@NonNull java.util.List<android.telephony.RadioAccessSpecifier>);
- method @RequiresPermission("android.permission.READ_ACTIVE_EMERGENCY_SESSION") public void updateTestOtaEmergencyNumberDbFilePath(@NonNull String);
+ method @RequiresPermission("android.permission.READ_ACTIVE_EMERGENCY_SESSION") public void updateOtaEmergencyNumberDbFilePath(@NonNull android.os.ParcelFileDescriptor);
field public static final int CARRIER_PRIVILEGE_STATUS_ERROR_LOADING_RULES = -2; // 0xfffffffe
field public static final int CARRIER_PRIVILEGE_STATUS_HAS_ACCESS = 1; // 0x1
field public static final int CARRIER_PRIVILEGE_STATUS_NO_ACCESS = 0; // 0x0
@@ -3833,7 +3853,7 @@ package android.telephony.ims {
method public int getEmergencyServiceCategories();
method @NonNull public java.util.List<java.lang.String> getEmergencyUrns();
method public android.telephony.ims.ImsStreamMediaProfile getMediaProfile();
- method @Nullable public android.os.Bundle getProprietaryCallExtras();
+ method @NonNull public android.os.Bundle getProprietaryCallExtras();
method public int getRestrictCause();
method public int getServiceType();
method public static int getVideoStateFromCallType(int);
@@ -4288,8 +4308,8 @@ package android.telephony.ims {
field public static final int KEY_RCS_CAPABILITY_DISCOVERY_ENABLED = 17; // 0x11
field public static final int KEY_RCS_CAPABILITY_POLL_LIST_SUB_EXP_SEC = 23; // 0x17
field public static final int KEY_RCS_MAX_NUM_ENTRIES_IN_RCL = 22; // 0x16
+ field public static final int KEY_RCS_PUBLISH_OFFLINE_AVAILABILITY_TIMER_SEC = 16; // 0x10
field public static final int KEY_RCS_PUBLISH_SOURCE_THROTTLE_MS = 21; // 0x15
- field public static final int KEY_RCS_PUBLISH_TIMER_EXTENDED_SEC = 16; // 0x10
field public static final int KEY_RCS_PUBLISH_TIMER_SEC = 15; // 0xf
field public static final int KEY_REGISTRATION_DOMAIN_NAME = 12; // 0xc
field public static final int KEY_REGISTRATION_RETRY_BASE_TIME_SEC = 33; // 0x21
diff --git a/cmds/incident/main.cpp b/cmds/incident/main.cpp
index eb2b98a666b9..6e0bd0629274 100644
--- a/cmds/incident/main.cpp
+++ b/cmds/incident/main.cpp
@@ -52,9 +52,13 @@ public:
virtual Status onReportServiceStatus(const String16& service, int32_t status);
virtual Status onReportFinished();
virtual Status onReportFailed();
+
+ int getExitCodeOrElse(int defaultCode);
+ private:
+ int mExitCode;
};
-StatusListener::StatusListener()
+StatusListener::StatusListener(): mExitCode(-1)
{
}
@@ -89,7 +93,7 @@ StatusListener::onReportFinished()
{
fprintf(stderr, "done\n");
ALOGD("done\n");
- exit(0);
+ mExitCode = 0;
return Status::ok();
}
@@ -98,10 +102,15 @@ StatusListener::onReportFailed()
{
fprintf(stderr, "failed\n");
ALOGD("failed\n");
- exit(1);
+ mExitCode = 1;
return Status::ok();
}
+int
+StatusListener::getExitCodeOrElse(int defaultCode) {
+ return mExitCode == -1 ? defaultCode : mExitCode;
+}
+
// ================================================================================
static void section_list(FILE* out) {
IncidentSection sections[INCIDENT_SECTION_COUNT];
@@ -201,20 +210,13 @@ parse_receiver_arg(const string& arg, string* pkg, string* cls)
static int
stream_output(const int read_fd, const int write_fd) {
while (true) {
- uint8_t buf[4096];
- ssize_t amt = TEMP_FAILURE_RETRY(read(read_fd, buf, sizeof(buf)));
+ int amt = splice(read_fd, NULL, write_fd, NULL, 4096, 0);
if (amt < 0) {
- break;
- } else if (amt == 0) {
- break;
- }
-
- ssize_t wamt = TEMP_FAILURE_RETRY(write(write_fd, buf, amt));
- if (wamt != amt) {
return errno;
+ } else if (amt == 0) {
+ return 0;
}
}
- return 0;
}
// ================================================================================
@@ -229,6 +231,7 @@ usage(FILE* out)
fprintf(out, " -l list available sections\n");
fprintf(out, " -p privacy spec, LOCAL, EXPLICIT or AUTOMATIC. Default AUTOMATIC.\n");
fprintf(out, " -r REASON human readable description of why the report is taken.\n");
+ fprintf(out, " -z gzip the incident report, i.e. pipe the output through gzip.\n");
fprintf(out, "\n");
fprintf(out, "and one of these destinations:\n");
fprintf(out, " -b (default) print the report to stdout (in proto format)\n");
@@ -253,7 +256,7 @@ main(int argc, char** argv)
// Parse the args
int opt;
- while ((opt = getopt(argc, argv, "bhdlp:r:s:u")) != -1) {
+ while ((opt = getopt(argc, argv, "bhdlp:r:s:uz")) != -1) {
switch (opt) {
case 'h':
usage(stdout);
@@ -300,6 +303,9 @@ main(int argc, char** argv)
destination = DEST_BROADCAST;
receiverArg = optarg;
break;
+ case 'z':
+ args.setGzip(true);
+ break;
default:
usage(stderr);
return 1;
@@ -384,7 +390,7 @@ main(int argc, char** argv)
// Wait for the result and print out the data they send.
//IPCThreadState::self()->joinThreadPool();
- return stream_output(fds[0], STDOUT_FILENO);
+ return listener->getExitCodeOrElse(stream_output(fds[0], STDOUT_FILENO));
} else if (destination == DEST_DUMPSTATE) {
// Call into the service
sp<StatusListener> listener(new StatusListener());
@@ -393,7 +399,7 @@ main(int argc, char** argv)
fprintf(stderr, "reportIncident returned \"%s\"\n", status.toString8().string());
return 1;
}
- return stream_output(fds[0], STDOUT_FILENO);
+ return listener->getExitCodeOrElse(stream_output(fds[0], STDOUT_FILENO));
} else {
status = service->reportIncident(args);
if (!status.isOk()) {
diff --git a/cmds/incidentd/src/Reporter.cpp b/cmds/incidentd/src/Reporter.cpp
index aa40f85fd340..ad253422452e 100644
--- a/cmds/incidentd/src/Reporter.cpp
+++ b/cmds/incidentd/src/Reporter.cpp
@@ -35,10 +35,12 @@
#include <dirent.h>
#include <errno.h>
#include <fcntl.h>
+#include <sys/prctl.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <string>
#include <time.h>
+#include <wait.h>
namespace android {
namespace os {
@@ -51,6 +53,8 @@ using namespace android::util;
* frameworks/base/core/proto/android/os/incident.proto
*/
const int FIELD_ID_METADATA = 2;
+// Args for exec gzip
+static const char* GZIP[] = {"/system/bin/gzip", NULL};
IncidentMetadata_Destination privacy_policy_to_dest(uint8_t privacyPolicy) {
switch (privacyPolicy) {
@@ -142,7 +146,8 @@ ReportRequest::ReportRequest(const IncidentReportArgs& a,
mListener(listener),
mFd(fd),
mIsStreaming(fd >= 0),
- mStatus(NO_ERROR) {
+ mStatus(OK),
+ mZipPid(-1) {
}
ReportRequest::~ReportRequest() {
@@ -153,7 +158,14 @@ ReportRequest::~ReportRequest() {
}
bool ReportRequest::ok() {
- return mFd >= 0 && mStatus == NO_ERROR;
+ if (mStatus != OK) {
+ return false;
+ }
+ if (!args.gzip()) {
+ return mFd >= 0;
+ }
+ // Send a blank signal to check if mZipPid is alive
+ return mZipPid > 0 && kill(mZipPid, 0) == 0;
}
bool ReportRequest::containsSection(int sectionId) const {
@@ -161,10 +173,45 @@ bool ReportRequest::containsSection(int sectionId) const {
}
void ReportRequest::closeFd() {
- if (mIsStreaming && mFd >= 0) {
+ if (!mIsStreaming) {
+ return;
+ }
+ if (mFd >= 0) {
close(mFd);
mFd = -1;
}
+ if (mZipPid > 0) {
+ mZipPipe.close();
+ // Gzip may take some time.
+ status_t err = wait_child(mZipPid, /* timeout_ms= */ 10 * 1000);
+ if (err != 0) {
+ ALOGW("[ReportRequest] abnormal child process: %s", strerror(-err));
+ }
+ }
+}
+
+int ReportRequest::getFd() {
+ return mZipPid > 0 ? mZipPipe.writeFd().get() : mFd;
+}
+
+status_t ReportRequest::initGzipIfNecessary() {
+ if (!mIsStreaming || !args.gzip()) {
+ return OK;
+ }
+ if (!mZipPipe.init()) {
+ ALOGE("[ReportRequest] Failed to setup pipe for gzip");
+ mStatus = -errno;
+ return mStatus;
+ }
+ int status = 0;
+ pid_t pid = fork_execute_cmd((char* const*)GZIP, mZipPipe.readFd().release(), mFd, &status);
+ if (pid < 0 || status != 0) {
+ mStatus = status;
+ return mStatus;
+ }
+ mZipPid = pid;
+ mFd = -1;
+ return OK;
}
// ================================================================================
@@ -562,6 +609,13 @@ void Reporter::runReport(size_t* reportByteSize) {
reportId = (spec.tv_sec) * 1000 + spec.tv_nsec;
}
+ mBatch->forEachStreamingRequest([](const sp<ReportRequest>& request) {
+ status_t err = request->initGzipIfNecessary();
+ if (err != 0) {
+ ALOGW("Error forking gzip: %s", strerror(err));
+ }
+ });
+
// Write the incident report headers - each request gets its own headers. It's different
// from the other top-level fields in IncidentReport that are the sections where the rest
// is all shared data (although with their own individual privacy filtering).
diff --git a/cmds/incidentd/src/Reporter.h b/cmds/incidentd/src/Reporter.h
index cbc8b136e7e3..bd47a23d369e 100644
--- a/cmds/incidentd/src/Reporter.h
+++ b/cmds/incidentd/src/Reporter.h
@@ -15,6 +15,7 @@
*/
#pragma once
+#include "incidentd_util.h"
#include "FdBuffer.h"
#include "WorkDirectory.h"
@@ -63,10 +64,12 @@ public:
sp<IIncidentReportStatusListener> getListener() { return mListener; }
- int getFd() { return mFd; }
+ int getFd();
int setPersistedFd(int fd);
+ status_t initGzipIfNecessary();
+
void closeFd();
private:
@@ -74,6 +77,8 @@ private:
int mFd;
bool mIsStreaming;
status_t mStatus;
+ pid_t mZipPid;
+ Fpipe mZipPipe;
};
// ================================================================================
diff --git a/cmds/incidentd/src/WorkDirectory.cpp b/cmds/incidentd/src/WorkDirectory.cpp
index 9963533c08ac..1944d6ecc720 100644
--- a/cmds/incidentd/src/WorkDirectory.cpp
+++ b/cmds/incidentd/src/WorkDirectory.cpp
@@ -16,10 +16,10 @@
#include "Log.h"
-#include "WorkDirectory.h"
-
+#include "incidentd_util.h"
#include "proto_util.h"
#include "PrivacyFilter.h"
+#include "WorkDirectory.h"
#include <google/protobuf/io/zero_copy_stream_impl.h>
#include <private/android_filesystem_config.h>
@@ -68,6 +68,9 @@ const ComponentName DROPBOX_SENTINEL("android", "DROPBOX");
/** metadata field id in IncidentProto */
const int FIELD_ID_INCIDENT_METADATA = 2;
+// Args for exec gzip
+static const char* GZIP[] = {"/system/bin/gzip", NULL};
+
/**
* Read a protobuf from disk into the message.
*/
@@ -292,6 +295,7 @@ void ReportFile::addReport(const IncidentReportArgs& args) {
report->set_cls(args.receiverCls());
report->set_privacy_policy(args.getPrivacyPolicy());
report->set_all_sections(args.all());
+ report->set_gzip(args.gzip());
for (int section: args.sections()) {
report->add_section(section);
}
@@ -417,6 +421,24 @@ status_t ReportFile::startFilteringData(int writeFd, const IncidentReportArgs& a
return BAD_VALUE;
}
+ pid_t zipPid = 0;
+ if (args.gzip()) {
+ Fpipe zipPipe;
+ if (!zipPipe.init()) {
+ ALOGE("[ReportFile] Failed to setup pipe for gzip");
+ close(writeFd);
+ return -errno;
+ }
+ int status = 0;
+ zipPid = fork_execute_cmd((char* const*)GZIP, zipPipe.readFd().release(), writeFd, &status);
+ close(writeFd);
+ if (zipPid < 0 || status != 0) {
+ ALOGE("[ReportFile] Failed to fork and exec gzip");
+ return status;
+ }
+ writeFd = zipPipe.writeFd().release();
+ }
+
status_t err;
for (const auto& report : mEnvelope.report()) {
@@ -437,6 +459,13 @@ status_t ReportFile::startFilteringData(int writeFd, const IncidentReportArgs& a
}
close(writeFd);
+ if (zipPid > 0) {
+ status_t err = wait_child(zipPid, /* timeout_ms= */ 10 * 1000);
+ if (err != 0) {
+ ALOGE("[ReportFile] abnormal child process: %s", strerror(-err));
+ }
+ return err;
+ }
return NO_ERROR;
}
@@ -621,7 +650,7 @@ void WorkDirectory::commitAll(const string& pkg) {
map<string,WorkDirectoryEntry> files;
get_directory_contents_locked(&files, 0);
-
+
for (map<string,WorkDirectoryEntry>::iterator it = files.begin();
it != files.end(); it++) {
sp<ReportFile> reportFile = new ReportFile(this, it->second.timestampNs,
@@ -815,6 +844,7 @@ void get_args_from_report(IncidentReportArgs* out, const ReportFileProto_Report&
out->setAll(report.all_sections());
out->setReceiverPkg(report.pkg());
out->setReceiverCls(report.cls());
+ out->setGzip(report.gzip());
const int sectionCount = report.section_size();
for (int i = 0; i < sectionCount; i++) {
diff --git a/cmds/incidentd/src/incidentd_util.cpp b/cmds/incidentd/src/incidentd_util.cpp
index dfaf89392f90..2649fb975792 100644
--- a/cmds/incidentd/src/incidentd_util.cpp
+++ b/cmds/incidentd/src/incidentd_util.cpp
@@ -18,6 +18,7 @@
#include "incidentd_util.h"
+#include <fcntl.h>
#include <sys/prctl.h>
#include <wait.h>
@@ -64,28 +65,52 @@ unique_fd& Fpipe::readFd() { return mRead; }
unique_fd& Fpipe::writeFd() { return mWrite; }
-pid_t fork_execute_cmd(char* const argv[], Fpipe* input, Fpipe* output) {
- // fork used in multithreaded environment, avoid adding unnecessary code in child process
+pid_t fork_execute_cmd(char* const argv[], Fpipe* input, Fpipe* output, int* status) {
+ int in = -1;
+ if (input != nullptr) {
+ in = input->readFd().release();
+ // Auto close write end of the input pipe on exec to prevent leaking fd in child process
+ fcntl(input->writeFd().get(), F_SETFD, FD_CLOEXEC);
+ }
+ int out = output->writeFd().release();
+ // Auto close read end of the output pipe on exec
+ fcntl(output->readFd().get(), F_SETFD, FD_CLOEXEC);
+ return fork_execute_cmd(argv, in, out, status);
+}
+
+pid_t fork_execute_cmd(char* const argv[], int in, int out, int* status) {
+ int dummy_status = 0;
+ if (status == nullptr) {
+ status = &dummy_status;
+ }
+ *status = 0;
pid_t pid = fork();
+ if (pid < 0) {
+ *status = -errno;
+ return -1;
+ }
if (pid == 0) {
- if (input != NULL && (TEMP_FAILURE_RETRY(dup2(input->readFd().get(), STDIN_FILENO)) < 0 ||
- !input->close())) {
+ // In child
+ if (in >= 0 && (TEMP_FAILURE_RETRY(dup2(in, STDIN_FILENO)) < 0 || close(in))) {
ALOGW("Failed to dup2 stdin.");
_exit(EXIT_FAILURE);
}
- if (TEMP_FAILURE_RETRY(dup2(output->writeFd().get(), STDOUT_FILENO)) < 0 ||
- !output->close()) {
+ if (TEMP_FAILURE_RETRY(dup2(out, STDOUT_FILENO)) < 0 || close(out)) {
ALOGW("Failed to dup2 stdout.");
_exit(EXIT_FAILURE);
}
- /* make sure the child dies when incidentd dies */
+ // Make sure the child dies when incidentd dies
prctl(PR_SET_PDEATHSIG, SIGKILL);
execvp(argv[0], argv);
_exit(errno); // always exits with failure if any
}
- // close the fds used in child process.
- if (input != NULL) input->readFd().reset();
- output->writeFd().reset();
+ // In parent
+ if ((in >= 0 && close(in) < 0) || close(out) < 0) {
+ ALOGW("Failed to close pd. Killing child process");
+ *status = -errno;
+ kill_child(pid);
+ return -1;
+ }
return pid;
}
@@ -120,9 +145,6 @@ uint64_t Nanotime() {
}
// ================================================================================
-const int WAIT_MAX = 5;
-const struct timespec WAIT_INTERVAL_NS = {0, 200 * 1000 * 1000};
-
static status_t statusCode(int status) {
if (WIFSIGNALED(status)) {
VLOG("return by signal: %s", strerror(WTERMSIG(status)));
@@ -134,25 +156,64 @@ static status_t statusCode(int status) {
return NO_ERROR;
}
+static bool waitpid_with_timeout(pid_t pid, int timeout_ms, int* status) {
+ sigset_t child_mask, old_mask;
+ sigemptyset(&child_mask);
+ sigaddset(&child_mask, SIGCHLD);
+
+ if (sigprocmask(SIG_BLOCK, &child_mask, &old_mask) == -1) {
+ ALOGW("sigprocmask failed: %s", strerror(errno));
+ return false;
+ }
+
+ timespec ts;
+ ts.tv_sec = timeout_ms / 1000;
+ ts.tv_nsec = (timeout_ms % 1000) * 1000000;
+ int ret = TEMP_FAILURE_RETRY(sigtimedwait(&child_mask, nullptr, &ts));
+ int saved_errno = errno;
+
+ // Set the signals back the way they were.
+ if (sigprocmask(SIG_SETMASK, &old_mask, nullptr) == -1) {
+ ALOGW("sigprocmask failed: %s", strerror(errno));
+ if (ret == 0) {
+ return false;
+ }
+ }
+ if (ret == -1) {
+ errno = saved_errno;
+ if (errno == EAGAIN) {
+ errno = ETIMEDOUT;
+ } else {
+ ALOGW("sigtimedwait failed: %s", strerror(errno));
+ }
+ return false;
+ }
+
+ pid_t child_pid = waitpid(pid, status, WNOHANG);
+ if (child_pid == pid) {
+ return true;
+ }
+ if (child_pid == -1) {
+ ALOGW("waitpid failed: %s", strerror(errno));
+ } else {
+ ALOGW("Waiting for pid %d, got pid %d instead", pid, child_pid);
+ }
+ return false;
+}
+
status_t kill_child(pid_t pid) {
int status;
- VLOG("try to kill child process %d", pid);
kill(pid, SIGKILL);
if (waitpid(pid, &status, 0) == -1) return -1;
return statusCode(status);
}
-status_t wait_child(pid_t pid) {
+status_t wait_child(pid_t pid, int timeout_ms) {
int status;
- bool died = false;
- // wait for child to report status up to 1 seconds
- for (int loop = 0; !died && loop < WAIT_MAX; loop++) {
- if (waitpid(pid, &status, WNOHANG) == pid) died = true;
- // sleep for 0.2 second
- nanosleep(&WAIT_INTERVAL_NS, NULL);
+ if (waitpid_with_timeout(pid, timeout_ms, &status)) {
+ return statusCode(status);
}
- if (!died) return kill_child(pid);
- return statusCode(status);
+ return kill_child(pid);
}
} // namespace incidentd
diff --git a/cmds/incidentd/src/incidentd_util.h b/cmds/incidentd/src/incidentd_util.h
index cc30768fa704..a54993fed42d 100644
--- a/cmds/incidentd/src/incidentd_util.h
+++ b/cmds/incidentd/src/incidentd_util.h
@@ -56,11 +56,24 @@ private:
};
/**
- * Forks and exec a command with two pipes, one connects stdin for input,
- * one connects stdout for output. It returns the pid of the child.
- * Input pipe can be NULL to indicate child process doesn't read stdin.
+ * Forks and exec a command with two pipes and returns the pid of the child, or -1 when it fails.
+ *
+ * input connects stdin for input. output connects stdout for output. input can be nullptr to
+ * indicate that child process doesn't read stdin. This function will close in and out fds upon
+ * success. If status is not NULL, the status information will be stored in the int to which it
+ * points.
+ */
+pid_t fork_execute_cmd(char* const argv[], Fpipe* input, Fpipe* output, int* status = nullptr);
+
+/**
+ * Forks and exec a command that reads from in fd and writes to out fd and returns the pid of the
+ * child, or -1 when it fails.
+ *
+ * in can be -1 to indicate that child process doesn't read stdin. This function will close in and
+ * out fds upon success. If status is not NULL, the status information will be stored in the int
+ * to which it points.
*/
-pid_t fork_execute_cmd(char* const argv[], Fpipe* input, Fpipe* output);
+pid_t fork_execute_cmd(char* const argv[], int in, int out, int* status = nullptr);
/**
* Grabs varargs from stack and stores them in heap with NULL-terminated array.
@@ -76,7 +89,7 @@ uint64_t Nanotime();
* Methods to wait or kill child process, return exit status code.
*/
status_t kill_child(pid_t pid);
-status_t wait_child(pid_t pid);
+status_t wait_child(pid_t pid, int timeout_ms = 1000);
status_t start_detached_thread(const function<void ()>& func);
diff --git a/cmds/incidentd/src/report_file.proto b/cmds/incidentd/src/report_file.proto
index 7563da2c2148..85fd2da6c65c 100644
--- a/cmds/incidentd/src/report_file.proto
+++ b/cmds/incidentd/src/report_file.proto
@@ -65,6 +65,11 @@ message ReportFileProto {
* the given client.
*/
optional bool share_approved = 8;
+
+ /**
+ * Whether the report is gzipped.
+ */
+ optional bool gzip = 9;
}
/**
diff --git a/cmds/statsd/Android.bp b/cmds/statsd/Android.bp
index 0c3a49a9d340..bd6ca47cb4b8 100644
--- a/cmds/statsd/Android.bp
+++ b/cmds/statsd/Android.bp
@@ -122,7 +122,6 @@ cc_defaults {
"libbinder_ndk",
"libincident",
"liblog",
- "libstatssocket",
"statsd-aidl-ndk_platform",
],
}
@@ -165,10 +164,6 @@ cc_library_static {
export_generated_headers: [
"atoms_info.h",
],
- shared_libs: [
- "libcutils",
- "libstatslog",
- ],
apex_available: [
//TODO(b/149782403): Remove this once statsd no longer links against libstatsmetadata
"com.android.os.statsd",
@@ -215,7 +210,10 @@ cc_binary {
type: "lite",
},
- shared_libs: ["libgtest_prod"],
+ shared_libs: [
+ "libgtest_prod",
+ "libstatssocket",
+ ],
apex_available: [
"com.android.os.statsd",
diff --git a/cmds/statsd/src/HashableDimensionKey.cpp b/cmds/statsd/src/HashableDimensionKey.cpp
index d95d59454dd8..23d8f59e94ea 100644
--- a/cmds/statsd/src/HashableDimensionKey.cpp
+++ b/cmds/statsd/src/HashableDimensionKey.cpp
@@ -40,53 +40,62 @@ const static int STATS_DIMENSIONS_VALUE_TUPLE_TYPE = 7;
* Recursive helper function that populates a parent StatsDimensionsValueParcel
* with children StatsDimensionsValueParcels.
*
+ * \param parent parcel that will be populated with children
+ * \param childDepth depth of children FieldValues
+ * \param childPrefix expected FieldValue prefix of children
* \param dims vector of FieldValues stored by HashableDimensionKey
- * \param index positions in dims vector to start reading children from
- * \param depth level of parent parcel in the full StatsDimensionsValueParcel
- * tree
+ * \param index position in dims to start reading children from
*/
-static void populateStatsDimensionsValueParcelChildren(StatsDimensionsValueParcel &parentParcel,
- const vector<FieldValue>& dims, size_t& index,
- int depth, int prefix) {
+static void populateStatsDimensionsValueParcelChildren(StatsDimensionsValueParcel& parent,
+ int childDepth, int childPrefix,
+ const vector<FieldValue>& dims,
+ size_t& index) {
+ if (childDepth > 2) {
+ ALOGE("Depth > 2 not supported by StatsDimensionsValueParcel.");
+ return;
+ }
+
while (index < dims.size()) {
const FieldValue& dim = dims[index];
int fieldDepth = dim.mField.getDepth();
- int fieldPrefix = dim.mField.getPrefix(depth);
- StatsDimensionsValueParcel childParcel;
- childParcel.field = dim.mField.getPosAtDepth(depth);
- if (depth > 2) {
- ALOGE("Depth > 2 not supported by StatsDimensionsValueParcel.");
- return;
- }
- if (depth == fieldDepth && prefix == fieldPrefix) {
+ int fieldPrefix = dim.mField.getPrefix(childDepth);
+
+ StatsDimensionsValueParcel child;
+ child.field = dim.mField.getPosAtDepth(childDepth);
+
+ if (fieldDepth == childDepth && fieldPrefix == childPrefix) {
switch (dim.mValue.getType()) {
case INT:
- childParcel.valueType = STATS_DIMENSIONS_VALUE_INT_TYPE;
- childParcel.intValue = dim.mValue.int_value;
+ child.valueType = STATS_DIMENSIONS_VALUE_INT_TYPE;
+ child.intValue = dim.mValue.int_value;
break;
case LONG:
- childParcel.valueType = STATS_DIMENSIONS_VALUE_LONG_TYPE;
- childParcel.longValue = dim.mValue.long_value;
+ child.valueType = STATS_DIMENSIONS_VALUE_LONG_TYPE;
+ child.longValue = dim.mValue.long_value;
break;
case FLOAT:
- childParcel.valueType = STATS_DIMENSIONS_VALUE_FLOAT_TYPE;
- childParcel.floatValue = dim.mValue.float_value;
+ child.valueType = STATS_DIMENSIONS_VALUE_FLOAT_TYPE;
+ child.floatValue = dim.mValue.float_value;
break;
case STRING:
- childParcel.valueType = STATS_DIMENSIONS_VALUE_STRING_TYPE;
- childParcel.stringValue = dim.mValue.str_value;
+ child.valueType = STATS_DIMENSIONS_VALUE_STRING_TYPE;
+ child.stringValue = dim.mValue.str_value;
break;
default:
ALOGE("Encountered FieldValue with unsupported value type.");
break;
}
index++;
- parentParcel.tupleValue.push_back(childParcel);
- } else if (fieldDepth > depth && fieldPrefix == prefix) {
- childParcel.valueType = STATS_DIMENSIONS_VALUE_TUPLE_TYPE;
- populateStatsDimensionsValueParcelChildren(childParcel, dims, index, depth + 1,
- dim.mField.getPrefix(depth + 1));
- parentParcel.tupleValue.push_back(childParcel);
+ parent.tupleValue.push_back(child);
+ } else if (fieldDepth > childDepth && fieldPrefix == childPrefix) {
+ // This FieldValue is not a child of the current parent, but it is
+ // an indirect descendant. Thus, create a direct child of TUPLE_TYPE
+ // and recurse to parcel the indirect descendants.
+ child.valueType = STATS_DIMENSIONS_VALUE_TUPLE_TYPE;
+ populateStatsDimensionsValueParcelChildren(child, childDepth + 1,
+ dim.mField.getPrefix(childDepth + 1), dims,
+ index);
+ parent.tupleValue.push_back(child);
} else {
return;
}
@@ -94,17 +103,21 @@ static void populateStatsDimensionsValueParcelChildren(StatsDimensionsValueParce
}
StatsDimensionsValueParcel HashableDimensionKey::toStatsDimensionsValueParcel() const {
- StatsDimensionsValueParcel parcel;
+ StatsDimensionsValueParcel root;
if (mValues.size() == 0) {
- return parcel;
+ return root;
}
- parcel.field = mValues[0].mField.getTag();
- parcel.valueType = STATS_DIMENSIONS_VALUE_TUPLE_TYPE;
+ root.field = mValues[0].mField.getTag();
+ root.valueType = STATS_DIMENSIONS_VALUE_TUPLE_TYPE;
+ // Children of the root correspond to top-level (depth = 0) FieldValues.
+ int childDepth = 0;
+ int childPrefix = 0;
size_t index = 0;
- populateStatsDimensionsValueParcelChildren(parcel, mValues, index, /*depth=*/0, /*prefix=*/0);
- return parcel;
+ populateStatsDimensionsValueParcelChildren(root, childDepth, childPrefix, mValues, index);
+
+ return root;
}
android::hash_t hashDimension(const HashableDimensionKey& value) {
diff --git a/cmds/statsd/src/StatsService.cpp b/cmds/statsd/src/StatsService.cpp
index 7ab6c7111b3e..cd10457dcd40 100644
--- a/cmds/statsd/src/StatsService.cpp
+++ b/cmds/statsd/src/StatsService.cpp
@@ -930,8 +930,6 @@ Status StatsService::informOnePackage(const string& app, int32_t uid, int64_t ve
ENFORCE_UID(AID_SYSTEM);
VLOG("StatsService::informOnePackage was called");
- // TODO(b/149254662): This is gross. We should consider changing statsd
- // internals to use std::string.
String16 utf16App = String16(app.c_str());
String16 utf16VersionString = String16(versionString.c_str());
String16 utf16Installer = String16(installer.c_str());
@@ -1196,13 +1194,14 @@ Status StatsService::sendAppBreadcrumbAtom(int32_t label, int32_t state) {
return Status::ok();
}
-Status StatsService::registerPullAtomCallback(int32_t uid, int32_t atomTag, int64_t coolDownNs,
- int64_t timeoutNs, const std::vector<int32_t>& additiveFields,
- const shared_ptr<IPullAtomCallback>& pullerCallback) {
+Status StatsService::registerPullAtomCallback(int32_t uid, int32_t atomTag, int64_t coolDownMillis,
+ int64_t timeoutMillis,
+ const std::vector<int32_t>& additiveFields,
+ const shared_ptr<IPullAtomCallback>& pullerCallback) {
ENFORCE_UID(AID_SYSTEM);
-
VLOG("StatsService::registerPullAtomCallback called.");
- mPullerManager->RegisterPullAtomCallback(uid, atomTag, coolDownNs, timeoutNs, additiveFields,
+ mPullerManager->RegisterPullAtomCallback(uid, atomTag, MillisToNano(coolDownMillis),
+ MillisToNano(timeoutMillis), additiveFields,
pullerCallback);
return Status::ok();
}
diff --git a/cmds/statsd/src/StatsService.h b/cmds/statsd/src/StatsService.h
index e6723c83e02a..c256e1f2ae9c 100644
--- a/cmds/statsd/src/StatsService.h
+++ b/cmds/statsd/src/StatsService.h
@@ -167,8 +167,9 @@ public:
/**
* Binder call to register a callback function for a pulled atom.
*/
- virtual Status registerPullAtomCallback(int32_t uid, int32_t atomTag, int64_t coolDownNs,
- int64_t timeoutNs, const std::vector<int32_t>& additiveFields,
+ virtual Status registerPullAtomCallback(
+ int32_t uid, int32_t atomTag, int64_t coolDownMillis, int64_t timeoutMillis,
+ const std::vector<int32_t>& additiveFields,
const shared_ptr<IPullAtomCallback>& pullerCallback) override;
/**
diff --git a/cmds/statsd/src/anomaly/AlarmMonitor.cpp b/cmds/statsd/src/anomaly/AlarmMonitor.cpp
index 02291181b81b..b632d040eb43 100644
--- a/cmds/statsd/src/anomaly/AlarmMonitor.cpp
+++ b/cmds/statsd/src/anomaly/AlarmMonitor.cpp
@@ -38,8 +38,6 @@ AlarmMonitor::~AlarmMonitor() {}
void AlarmMonitor::setStatsCompanionService(
shared_ptr<IStatsCompanionService> statsCompanionService) {
std::lock_guard<std::mutex> lock(mLock);
- // TODO(b/149254662): determine if tmpForLock is needed now that we have moved
- // from sp to shared_ptr
shared_ptr<IStatsCompanionService> tmpForLock = mStatsCompanionService;
mStatsCompanionService = statsCompanionService;
if (statsCompanionService == nullptr) {
diff --git a/cmds/statsd/src/atom_field_options.proto b/cmds/statsd/src/atom_field_options.proto
index 9c875ba7502d..40a24dc52e52 100644
--- a/cmds/statsd/src/atom_field_options.proto
+++ b/cmds/statsd/src/atom_field_options.proto
@@ -116,5 +116,5 @@ extend google.protobuf.FieldOptions {
optional bool allow_from_any_uid = 50003 [default = false];
- optional string module = 50004;
+ repeated string module = 50004;
}
diff --git a/cmds/statsd/src/atoms.proto b/cmds/statsd/src/atoms.proto
index e58e7bc11315..80f9fea6a2fb 100644
--- a/cmds/statsd/src/atoms.proto
+++ b/cmds/statsd/src/atoms.proto
@@ -3600,9 +3600,10 @@ message Notification {
// See NotificationSectionsManager.PriorityBucket.
enum NotificationSection {
SECTION_UNKNOWN = 0;
- SECTION_PEOPLE = 1;
- SECTION_ALERTING = 2;
- SECTION_SILENT = 3;
+ SECTION_HEADS_UP = 1;
+ SECTION_PEOPLE = 2;
+ SECTION_ALERTING = 3;
+ SECTION_SILENT = 4;
}
optional NotificationSection section = 6;
}
@@ -7639,6 +7640,9 @@ message AppFeaturesOps {
// Whether AppOps is guarded by Runtime permission
optional bool is_runtime_permission = 11;
+
+ // Sampling rate used on device, from 0 to 100
+ optional int32 sampling_rate = 12;
}
/**
diff --git a/cmds/statsd/src/config/ConfigManager.cpp b/cmds/statsd/src/config/ConfigManager.cpp
index 9bdb5881cc94..6d9c644bb40e 100644
--- a/cmds/statsd/src/config/ConfigManager.cpp
+++ b/cmds/statsd/src/config/ConfigManager.cpp
@@ -54,20 +54,22 @@ struct ConfigReceiverDeathCookie {
shared_ptr<IPendingIntentRef> mPir;
};
-static void configReceiverDied(void* cookie) {
+void ConfigManager::configReceiverDied(void* cookie) {
auto cookie_ = static_cast<ConfigReceiverDeathCookie*>(cookie);
- sp<ConfigManager> configManager = cookie_->mConfigManager;
- ConfigKey configKey = cookie_->mConfigKey;
- shared_ptr<IPendingIntentRef> pir = cookie_->mPir;
-
- // TODO(b/149254662): Fix threading. This currently fails if a new
- // pir gets set between the get and the remove.
- if (configManager->GetConfigReceiver(configKey) == pir) {
- configManager->RemoveConfigReceiver(configKey);
+ sp<ConfigManager>& thiz = cookie_->mConfigManager;
+ ConfigKey& configKey = cookie_->mConfigKey;
+ shared_ptr<IPendingIntentRef>& pir = cookie_->mPir;
+
+ // Erase the mapping from the config key to the config receiver (pir) if the
+ // mapping still exists.
+ lock_guard<mutex> lock(thiz->mMutex);
+ auto it = thiz->mConfigReceivers.find(configKey);
+ if (it != thiz->mConfigReceivers.end() && it->second == pir) {
+ thiz->mConfigReceivers.erase(configKey);
}
- // The death recipient corresponding to this specific pir can never
- // be triggered again, so free up resources.
- // TODO(b/149254662): Investigate other options to manage the memory.
+
+ // The death recipient corresponding to this specific pir can never be
+ // triggered again, so free up resources.
delete cookie_;
}
@@ -83,26 +85,29 @@ struct ActiveConfigChangedReceiverDeathCookie {
shared_ptr<IPendingIntentRef> mPir;
};
-static void activeConfigChangedReceiverDied(void* cookie) {
+void ConfigManager::activeConfigChangedReceiverDied(void* cookie) {
auto cookie_ = static_cast<ActiveConfigChangedReceiverDeathCookie*>(cookie);
- sp<ConfigManager> configManager = cookie_->mConfigManager;
+ sp<ConfigManager>& thiz = cookie_->mConfigManager;
int uid = cookie_->mUid;
- shared_ptr<IPendingIntentRef> pir = cookie_->mPir;
-
- // TODO(b/149254662): Fix threading. This currently fails if a new
- // pir gets set between the get and the remove.
- if (configManager->GetActiveConfigsChangedReceiver(uid) == pir) {
- configManager->RemoveActiveConfigsChangedReceiver(uid);
+ shared_ptr<IPendingIntentRef>& pir = cookie_->mPir;
+
+ // Erase the mapping from the config key to the active config changed
+ // receiver (pir) if the mapping still exists.
+ lock_guard<mutex> lock(thiz->mMutex);
+ auto it = thiz->mActiveConfigsChangedReceivers.find(uid);
+ if (it != thiz->mActiveConfigsChangedReceivers.end() && it->second == pir) {
+ thiz->mActiveConfigsChangedReceivers.erase(uid);
}
+
// The death recipient corresponding to this specific pir can never
// be triggered again, so free up resources.
delete cookie_;
}
-ConfigManager::ConfigManager():
+ConfigManager::ConfigManager() :
mConfigReceiverDeathRecipient(AIBinder_DeathRecipient_new(configReceiverDied)),
mActiveConfigChangedReceiverDeathRecipient(
- AIBinder_DeathRecipient_new(activeConfigChangedReceiverDied)) {
+ AIBinder_DeathRecipient_new(activeConfigChangedReceiverDied)) {
}
ConfigManager::~ConfigManager() {
@@ -189,8 +194,10 @@ void ConfigManager::RemoveConfigReceiver(const ConfigKey& key) {
void ConfigManager::SetActiveConfigsChangedReceiver(const int uid,
const shared_ptr<IPendingIntentRef>& pir) {
- lock_guard<mutex> lock(mMutex);
- mActiveConfigsChangedReceivers[uid] = pir;
+ {
+ lock_guard<mutex> lock(mMutex);
+ mActiveConfigsChangedReceivers[uid] = pir;
+ }
AIBinder_linkToDeath(pir->asBinder().get(), mActiveConfigChangedReceiverDeathRecipient.get(),
new ActiveConfigChangedReceiverDeathCookie(this, uid, pir));
}
diff --git a/cmds/statsd/src/config/ConfigManager.h b/cmds/statsd/src/config/ConfigManager.h
index 824e58849b78..40146b1b2bec 100644
--- a/cmds/statsd/src/config/ConfigManager.h
+++ b/cmds/statsd/src/config/ConfigManager.h
@@ -161,6 +161,19 @@ private:
// IPendingIntentRef dies.
::ndk::ScopedAIBinder_DeathRecipient mConfigReceiverDeathRecipient;
::ndk::ScopedAIBinder_DeathRecipient mActiveConfigChangedReceiverDeathRecipient;
+
+ /**
+ * Death recipient callback that is called when a config receiver dies.
+ * The cookie is a pointer to a ConfigReceiverDeathCookie.
+ */
+ static void configReceiverDied(void* cookie);
+
+ /**
+ * Death recipient callback that is called when an active config changed
+ * receiver dies. The cookie is a pointer to an
+ * ActiveConfigChangedReceiverDeathCookie.
+ */
+ static void activeConfigChangedReceiverDied(void* cookie);
};
} // namespace statsd
diff --git a/cmds/statsd/src/external/StatsPullerManager.cpp b/cmds/statsd/src/external/StatsPullerManager.cpp
index 1c38542b9017..0115ba2b6bc0 100644
--- a/cmds/statsd/src/external/StatsPullerManager.cpp
+++ b/cmds/statsd/src/external/StatsPullerManager.cpp
@@ -85,12 +85,9 @@ void StatsPullerManager::updateAlarmLocked() {
return;
}
- // TODO(b/149254662): Why are we creating a copy here? This is different
- // from the other places where we create a copy because we don't reassign
- // mStatsCompanionService so a destructor can't implicitly be called...
- shared_ptr<IStatsCompanionService> statsCompanionServiceCopy = mStatsCompanionService;
- if (statsCompanionServiceCopy != nullptr) {
- statsCompanionServiceCopy->setPullingAlarm(mNextPullTimeNs / 1000000);
+ // TODO(b/151045771): do not hold a lock while making a binder call
+ if (mStatsCompanionService != nullptr) {
+ mStatsCompanionService->setPullingAlarm(mNextPullTimeNs / 1000000);
} else {
VLOG("StatsCompanionService not available. Alarm not set.");
}
@@ -99,8 +96,6 @@ void StatsPullerManager::updateAlarmLocked() {
void StatsPullerManager::SetStatsCompanionService(
shared_ptr<IStatsCompanionService> statsCompanionService) {
- // TODO(b/149254662): Why are we using AutoMutex instead of lock_guard?
- // Additionally, do we need the temporary shared_ptr to prevent deadlocks?
AutoMutex _l(mLock);
shared_ptr<IStatsCompanionService> tmpForLock = mStatsCompanionService;
mStatsCompanionService = statsCompanionService;
diff --git a/cmds/statsd/src/subscriber/SubscriberReporter.cpp b/cmds/statsd/src/subscriber/SubscriberReporter.cpp
index 93af5e937228..c915ef3bf069 100644
--- a/cmds/statsd/src/subscriber/SubscriberReporter.cpp
+++ b/cmds/statsd/src/subscriber/SubscriberReporter.cpp
@@ -39,33 +39,47 @@ struct BroadcastSubscriberDeathCookie {
shared_ptr<IPendingIntentRef> mPir;
};
-static void broadcastSubscriberDied(void* cookie) {
- BroadcastSubscriberDeathCookie* cookie_ = (BroadcastSubscriberDeathCookie*)cookie;
- ConfigKey configKey = cookie_->mConfigKey;
+void SubscriberReporter::broadcastSubscriberDied(void* cookie) {
+ auto cookie_ = static_cast<BroadcastSubscriberDeathCookie*>(cookie);
+ ConfigKey& configKey = cookie_->mConfigKey;
int64_t subscriberId = cookie_->mSubscriberId;
- shared_ptr<IPendingIntentRef> pir = cookie_->mPir;
-
- // TODO(b/149254662): Fix threading. This currently fails if a new pir gets
- // set between the get and the unset.
- if (SubscriberReporter::getInstance().getBroadcastSubscriber(configKey, subscriberId) == pir) {
- SubscriberReporter::getInstance().unsetBroadcastSubscriber(configKey, subscriberId);
+ shared_ptr<IPendingIntentRef>& pir = cookie_->mPir;
+
+ SubscriberReporter& thiz = getInstance();
+
+ // Erase the mapping from a (config_key, subscriberId) to a pir if the
+ // mapping exists.
+ lock_guard<mutex> lock(thiz.mLock);
+ auto subscriberMapIt = thiz.mIntentMap.find(configKey);
+ if (subscriberMapIt != thiz.mIntentMap.end()) {
+ auto subscriberMap = subscriberMapIt->second;
+ auto pirIt = subscriberMap.find(subscriberId);
+ if (pirIt != subscriberMap.end() && pirIt->second == pir) {
+ subscriberMap.erase(subscriberId);
+ if (subscriberMap.empty()) {
+ thiz.mIntentMap.erase(configKey);
+ }
+ }
}
+
// The death recipient corresponding to this specific pir can never be
// triggered again, so free up resources.
delete cookie_;
}
-static ::ndk::ScopedAIBinder_DeathRecipient sBroadcastSubscriberDeathRecipient(
- AIBinder_DeathRecipient_new(broadcastSubscriberDied));
+SubscriberReporter::SubscriberReporter() :
+ mBroadcastSubscriberDeathRecipient(AIBinder_DeathRecipient_new(broadcastSubscriberDied)) {
+}
void SubscriberReporter::setBroadcastSubscriber(const ConfigKey& configKey,
int64_t subscriberId,
const shared_ptr<IPendingIntentRef>& pir) {
VLOG("SubscriberReporter::setBroadcastSubscriber called.");
- lock_guard<mutex> lock(mLock);
- mIntentMap[configKey][subscriberId] = pir;
- // TODO(b/149254662): Is it ok to call linkToDeath while holding a lock?
- AIBinder_linkToDeath(pir->asBinder().get(), sBroadcastSubscriberDeathRecipient.get(),
+ {
+ lock_guard<mutex> lock(mLock);
+ mIntentMap[configKey][subscriberId] = pir;
+ }
+ AIBinder_linkToDeath(pir->asBinder().get(), mBroadcastSubscriberDeathRecipient.get(),
new BroadcastSubscriberDeathCookie(configKey, subscriberId, pir));
}
@@ -103,8 +117,6 @@ void SubscriberReporter::alertBroadcastSubscriber(const ConfigKey& configKey,
}
int64_t subscriberId = subscription.broadcast_subscriber_details().subscriber_id();
- // TODO(b/149254662): Is there a way to convert a RepeatedPtrField into a
- // vector without copying?
vector<string> cookies;
cookies.reserve(subscription.broadcast_subscriber_details().cookie_size());
for (auto& cookie : subscription.broadcast_subscriber_details().cookie()) {
diff --git a/cmds/statsd/src/subscriber/SubscriberReporter.h b/cmds/statsd/src/subscriber/SubscriberReporter.h
index 0f97d397e331..4fe428198e71 100644
--- a/cmds/statsd/src/subscriber/SubscriberReporter.h
+++ b/cmds/statsd/src/subscriber/SubscriberReporter.h
@@ -78,7 +78,7 @@ public:
int64_t subscriberId);
private:
- SubscriberReporter() {};
+ SubscriberReporter();
mutable mutex mLock;
@@ -94,6 +94,14 @@ private:
const Subscription& subscription,
const vector<string>& cookies,
const MetricDimensionKey& dimKey) const;
+
+ ::ndk::ScopedAIBinder_DeathRecipient mBroadcastSubscriberDeathRecipient;
+
+ /**
+ * Death recipient callback that is called when a broadcast subscriber dies.
+ * The cookie is a pointer to a BroadcastSubscriberDeathCookie.
+ */
+ static void broadcastSubscriberDied(void* cookie);
};
} // namespace statsd
diff --git a/core/java/android/accessibilityservice/AccessibilityService.java b/core/java/android/accessibilityservice/AccessibilityService.java
index a7129561c754..3a3eea966a86 100644
--- a/core/java/android/accessibilityservice/AccessibilityService.java
+++ b/core/java/android/accessibilityservice/AccessibilityService.java
@@ -48,6 +48,7 @@ import android.util.Slog;
import android.util.SparseArray;
import android.view.Display;
import android.view.KeyEvent;
+import android.view.SurfaceView;
import android.view.WindowManager;
import android.view.WindowManagerImpl;
import android.view.accessibility.AccessibilityEvent;
@@ -1832,6 +1833,14 @@ public abstract class AccessibilityService extends Service {
* setting the {@link AccessibilityServiceInfo#FLAG_RETRIEVE_INTERACTIVE_WINDOWS}
* flag. Otherwise, the search will be performed only in the active window.
* </p>
+ * <p>
+ * <strong>Note:</strong> If the view with {@link AccessibilityNodeInfo#FOCUS_INPUT}
+ * is on an embedded view hierarchy which is embedded in a {@link SurfaceView} via
+ * {@link SurfaceView#setChildSurfacePackage}, there is a limitation that this API
+ * won't be able to find the node for the view. It's because views don't know about
+ * the embedded hierarchies. Instead, you could traverse all the nodes to find the
+ * focus.
+ * </p>
*
* @param focus The focus to find. One of {@link AccessibilityNodeInfo#FOCUS_INPUT} or
* {@link AccessibilityNodeInfo#FOCUS_ACCESSIBILITY}.
diff --git a/core/java/android/app/Activity.java b/core/java/android/app/Activity.java
index 5f49bb217900..8d6bc7222abd 100644
--- a/core/java/android/app/Activity.java
+++ b/core/java/android/app/Activity.java
@@ -7943,7 +7943,8 @@ public class Activity extends ContextThemeWrapper
mCurrentConfig = config;
mWindow.setColorMode(info.colorMode);
- mWindow.setPreferMinimalPostProcessing(info.preferMinimalPostProcessing);
+ mWindow.setPreferMinimalPostProcessing(
+ (info.flags & ActivityInfo.FLAG_PREFER_MINIMAL_POST_PROCESSING) != 0);
setAutofillOptions(application.getAutofillOptions());
setContentCaptureOptions(application.getContentCaptureOptions());
diff --git a/core/java/android/app/AppOpsManager.java b/core/java/android/app/AppOpsManager.java
index a53fc3508001..eeb5d4122cc7 100644
--- a/core/java/android/app/AppOpsManager.java
+++ b/core/java/android/app/AppOpsManager.java
@@ -16,10 +16,6 @@
package android.app;
-import static android.util.StatsLogInternal.RUNTIME_APP_OP_ACCESS__SAMPLING_STRATEGY__DEFAULT;
-import static android.util.StatsLogInternal.RUNTIME_APP_OP_ACCESS__SAMPLING_STRATEGY__RARELY_USED;
-import static android.util.StatsLogInternal.RUNTIME_APP_OP_ACCESS__SAMPLING_STRATEGY__UNIFORM;
-
import android.Manifest;
import android.annotation.CallbackExecutor;
import android.annotation.IntDef;
@@ -74,6 +70,7 @@ import com.android.internal.os.RuntimeInit;
import com.android.internal.os.ZygoteInit;
import com.android.internal.util.ArrayUtils;
import com.android.internal.util.DataClass;
+import com.android.internal.util.FrameworkStatsLog;
import com.android.internal.util.Parcelling;
import com.android.internal.util.Preconditions;
@@ -165,7 +162,7 @@ import java.util.function.Supplier;
* might also make sense inside of a single app if the access is forwarded between two features of
* the app.
*
- * <p>An app can register an {@link AppOpsCollector} to get informed about what accesses the
+ * <p>An app can register an {@link OnOpNotedCallback} to get informed about what accesses the
* system is tracking for it. As each runtime permission has an associated app-op this API is
* particularly useful for an app that want to find unexpected private data accesses.
*/
@@ -209,16 +206,16 @@ public class AppOpsManager {
private static final Object sLock = new Object();
- /** Current {@link AppOpsCollector}. Change via {@link #setNotedAppOpsCollector} */
+ /** Current {@link OnOpNotedCallback}. Change via {@link #setOnOpNotedCallback} */
@GuardedBy("sLock")
- private static @Nullable AppOpsCollector sNotedAppOpsCollector;
+ private static @Nullable OnOpNotedCallback sOnOpNotedCallback;
/**
* Additional collector that collect accesses and forwards a few of them them via
* {@link IAppOpsService#reportRuntimeAppOpAccessMessageAndGetConfig}.
*/
- private static AppOpsCollector sMessageCollector =
- new AppOpsCollector() {
+ private static OnOpNotedCallback sMessageCollector =
+ new OnOpNotedCallback() {
@Override
public void onNoted(@NonNull SyncNotedAppOp op) {
reportStackTraceIfNeeded(op);
@@ -388,6 +385,15 @@ public class AppOpsManager {
*/
public static final int WATCH_FOREGROUND_CHANGES = 1 << 0;
+
+ /**
+ * Flag to determine whether we should log noteOp/startOp calls to make sure they
+ * are correctly used
+ *
+ * @hide
+ */
+ public static final boolean NOTE_OP_COLLECTION_ENABLED = false;
+
/**
* @hide
*/
@@ -666,15 +672,31 @@ public class AppOpsManager {
}
}
+ // These constants are redefined here to work around a metalava limitation/bug where
+ // @IntDef is not able to see @hide symbols when they are hidden via package hiding:
+ // frameworks/base/core/java/com/android/internal/package.html
+
+ /** @hide */
+ public static final int SAMPLING_STRATEGY_DEFAULT =
+ FrameworkStatsLog.RUNTIME_APP_OP_ACCESS__SAMPLING_STRATEGY__DEFAULT;
+
+ /** @hide */
+ public static final int SAMPLING_STRATEGY_UNIFORM =
+ FrameworkStatsLog.RUNTIME_APP_OP_ACCESS__SAMPLING_STRATEGY__UNIFORM;
+
+ /** @hide */
+ public static final int SAMPLING_STRATEGY_RARELY_USED =
+ FrameworkStatsLog.RUNTIME_APP_OP_ACCESS__SAMPLING_STRATEGY__RARELY_USED;
+
/**
* Strategies used for message sampling
* @hide
*/
@Retention(RetentionPolicy.SOURCE)
- @IntDef(prefix = {"RUNTIME_APP_OPS_ACCESS__SAMPLING_STRATEGY__"}, value = {
- RUNTIME_APP_OP_ACCESS__SAMPLING_STRATEGY__DEFAULT,
- RUNTIME_APP_OP_ACCESS__SAMPLING_STRATEGY__UNIFORM,
- RUNTIME_APP_OP_ACCESS__SAMPLING_STRATEGY__RARELY_USED
+ @IntDef(prefix = {"SAMPLING_STRATEGY_"}, value = {
+ SAMPLING_STRATEGY_DEFAULT,
+ SAMPLING_STRATEGY_UNIFORM,
+ SAMPLING_STRATEGY_RARELY_USED
})
public @interface SamplingStrategy {}
@@ -1038,9 +1060,12 @@ public class AppOpsManager {
/** @hide Access telephony call audio */
public static final int OP_ACCESS_CALL_AUDIO = 96;
+ /** @hide Auto-revoke app permissions if app is unused for an extended period */
+ public static final int OP_AUTO_REVOKE_PERMISSIONS_IF_UNUSED = 97;
+
/** @hide */
@UnsupportedAppUsage
- public static final int _NUM_OP = 97;
+ public static final int _NUM_OP = 98;
/** Access to coarse location information. */
public static final String OPSTR_COARSE_LOCATION = "android:coarse_location";
@@ -1335,6 +1360,11 @@ public class AppOpsManager {
@SystemApi
public static final String OPSTR_ACCESS_CALL_AUDIO = "android:access_call_audio";
+ /** @hide Auto-revoke app permissions if app is unused for an extended period */
+ @SystemApi
+ public static final String OPSTR_AUTO_REVOKE_PERMISSIONS_IF_UNUSED =
+ "android:auto_revoke_permissions_if_unused";
+
/** @hide Communicate cross-profile within the same profile group. */
@SystemApi
public static final String OPSTR_INTERACT_ACROSS_PROFILES = "android:interact_across_profiles";
@@ -1424,6 +1454,7 @@ public class AppOpsManager {
OP_INTERACT_ACROSS_PROFILES,
OP_LOADER_USAGE_STATS,
OP_ACCESS_CALL_AUDIO,
+ OP_AUTO_REVOKE_PERMISSIONS_IF_UNUSED,
};
/**
@@ -1532,6 +1563,7 @@ public class AppOpsManager {
OP_ACTIVATE_PLATFORM_VPN, // ACTIVATE_PLATFORM_VPN
OP_LOADER_USAGE_STATS, // LOADER_USAGE_STATS
OP_ACCESS_CALL_AUDIO, // ACCESS_CALL_AUDIO
+ OP_AUTO_REVOKE_PERMISSIONS_IF_UNUSED, //AUTO_REVOKE_PERMISSIONS_IF_UNUSED
};
/**
@@ -1635,6 +1667,7 @@ public class AppOpsManager {
OPSTR_ACTIVATE_PLATFORM_VPN,
OPSTR_LOADER_USAGE_STATS,
OPSTR_ACCESS_CALL_AUDIO,
+ OPSTR_AUTO_REVOKE_PERMISSIONS_IF_UNUSED,
};
/**
@@ -1739,6 +1772,7 @@ public class AppOpsManager {
"ACTIVATE_PLATFORM_VPN",
"LOADER_USAGE_STATS",
"ACCESS_CALL_AUDIO",
+ "AUTO_REVOKE_PERMISSIONS_IF_UNUSED",
};
/**
@@ -1844,6 +1878,7 @@ public class AppOpsManager {
null, // no permission for OP_ACTIVATE_PLATFORM_VPN
android.Manifest.permission.LOADER_USAGE_STATS,
Manifest.permission.ACCESS_CALL_AUDIO,
+ null, // no permission for OP_AUTO_REVOKE_PERMISSIONS_IF_UNUSED
};
/**
@@ -1949,6 +1984,7 @@ public class AppOpsManager {
null, // ACTIVATE_PLATFORM_VPN
null, // LOADER_USAGE_STATS
null, // ACCESS_CALL_AUDIO
+ null, // AUTO_REVOKE_PERMISSIONS_IF_UNUSED
};
/**
@@ -2053,6 +2089,7 @@ public class AppOpsManager {
false, // ACTIVATE_PLATFORM_VPN
false, // LOADER_USAGE_STATS
false, // ACCESS_CALL_AUDIO
+ false, // AUTO_REVOKE_PERMISSIONS_IF_UNUSED
};
/**
@@ -2156,6 +2193,7 @@ public class AppOpsManager {
AppOpsManager.MODE_IGNORED, // ACTIVATE_PLATFORM_VPN
AppOpsManager.MODE_DEFAULT, // LOADER_USAGE_STATS
AppOpsManager.MODE_DEFAULT, // ACCESS_CALL_AUDIO
+ AppOpsManager.MODE_DEFAULT, // OP_AUTO_REVOKE_PERMISSIONS_IF_UNUSED
};
/**
@@ -2263,6 +2301,7 @@ public class AppOpsManager {
false, // ACTIVATE_PLATFORM_VPN
false, // LOADER_USAGE_STATS
false, // ACCESS_CALL_AUDIO
+ false, // AUTO_REVOKE_PERMISSIONS_IF_UNUSED
};
/**
@@ -7090,6 +7129,7 @@ public class AppOpsManager {
public int noteOpNoThrow(int op, int uid, @Nullable String packageName,
@Nullable String featureId, @Nullable String message) {
try {
+ collectNoteOpCallsForValidation(op);
int collectionMode = getNotedOpCollectionMode(uid, packageName, op);
if (collectionMode == COLLECT_ASYNC) {
if (message == null) {
@@ -7250,6 +7290,7 @@ public class AppOpsManager {
int myUid = Process.myUid();
try {
+ collectNoteOpCallsForValidation(op);
int collectionMode = getNotedOpCollectionMode(proxiedUid, proxiedPackageName, op);
if (collectionMode == COLLECT_ASYNC) {
if (message == null) {
@@ -7570,6 +7611,7 @@ public class AppOpsManager {
public int startOpNoThrow(int op, int uid, @NonNull String packageName,
boolean startIfModeDefault, @Nullable String featureId, @Nullable String message) {
try {
+ collectNoteOpCallsForValidation(op);
int collectionMode = getNotedOpCollectionMode(uid, packageName, op);
if (collectionMode == COLLECT_ASYNC) {
if (message == null) {
@@ -7758,8 +7800,8 @@ public class AppOpsManager {
*/
private void collectNotedOpForSelf(int op, @Nullable String featureId) {
synchronized (sLock) {
- if (sNotedAppOpsCollector != null) {
- sNotedAppOpsCollector.onSelfNoted(new SyncNotedAppOp(op, featureId));
+ if (sOnOpNotedCallback != null) {
+ sOnOpNotedCallback.onSelfNoted(new SyncNotedAppOp(op, featureId));
}
}
sMessageCollector.onSelfNoted(new SyncNotedAppOp(op, featureId));
@@ -7908,8 +7950,8 @@ public class AppOpsManager {
synchronized (sLock) {
for (int code = notedAppOps.nextSetBit(0); code != -1;
code = notedAppOps.nextSetBit(code + 1)) {
- if (sNotedAppOpsCollector != null) {
- sNotedAppOpsCollector.onNoted(new SyncNotedAppOp(code, featureId));
+ if (sOnOpNotedCallback != null) {
+ sOnOpNotedCallback.onNoted(new SyncNotedAppOp(code, featureId));
}
}
}
@@ -7922,33 +7964,45 @@ public class AppOpsManager {
}
/**
- * Register a new {@link AppOpsCollector}.
+ * Set a new {@link OnOpNotedCallback}.
*
- * <p>There can only ever be one collector per process. If there currently is a collector
- * registered, it will be unregistered.
+ * <p>There can only ever be one collector per process. If there currently is another callback
+ * set, this will fail.
*
- * <p><b>Only appops related to dangerous permissions are collected.</b>
+ * @param asyncExecutor executor to execute {@link OnOpNotedCallback#onAsyncNoted} on, {@code
+ * null} to unset
+ * @param callback listener to set, {@code null} to unset
*
- * @param collector The collector to set or {@code null} to unregister.
+ * @throws IllegalStateException If another callback is already registered
*/
- public void setNotedAppOpsCollector(@Nullable AppOpsCollector collector) {
+ public void setOnOpNotedCallback(@Nullable @CallbackExecutor Executor asyncExecutor,
+ @Nullable OnOpNotedCallback callback) {
+ Preconditions.checkState((callback == null) == (asyncExecutor == null));
+
synchronized (sLock) {
- if (sNotedAppOpsCollector != null) {
+ if (callback == null) {
+ Preconditions.checkState(sOnOpNotedCallback != null,
+ "No callback is currently registered");
+
try {
mService.stopWatchingAsyncNoted(mContext.getPackageName(),
- sNotedAppOpsCollector.mAsyncCb);
+ sOnOpNotedCallback.mAsyncCb);
} catch (RemoteException e) {
e.rethrowFromSystemServer();
}
- }
- sNotedAppOpsCollector = collector;
+ sOnOpNotedCallback = null;
+ } else {
+ Preconditions.checkState(sOnOpNotedCallback == null,
+ "Another callback is already registered");
+
+ callback.mAsyncExecutor = asyncExecutor;
+ sOnOpNotedCallback = callback;
- if (sNotedAppOpsCollector != null) {
List<AsyncNotedAppOp> missedAsyncOps = null;
try {
mService.startWatchingAsyncNoted(mContext.getPackageName(),
- sNotedAppOpsCollector.mAsyncCb);
+ sOnOpNotedCallback.mAsyncCb);
missedAsyncOps = mService.extractAsyncOps(mContext.getPackageName());
} catch (RemoteException e) {
e.rethrowFromSystemServer();
@@ -7958,10 +8012,9 @@ public class AppOpsManager {
int numMissedAsyncOps = missedAsyncOps.size();
for (int i = 0; i < numMissedAsyncOps; i++) {
final AsyncNotedAppOp asyncNotedAppOp = missedAsyncOps.get(i);
- if (sNotedAppOpsCollector != null) {
- sNotedAppOpsCollector.getAsyncNotedExecutor().execute(
- () -> sNotedAppOpsCollector.onAsyncNoted(
- asyncNotedAppOp));
+ if (sOnOpNotedCallback != null) {
+ sOnOpNotedCallback.getAsyncNotedExecutor().execute(
+ () -> sOnOpNotedCallback.onAsyncNoted(asyncNotedAppOp));
}
}
}
@@ -7969,27 +8022,50 @@ public class AppOpsManager {
}
}
+ // TODO moltmann: Remove
+ /**
+ * Will be removed before R ships, leave it just to not break apps immediately.
+ *
+ * @removed
+ *
+ * @hide
+ */
+ @SystemApi
+ @Deprecated
+ public void setNotedAppOpsCollector(@Nullable AppOpsCollector collector) {
+ synchronized (sLock) {
+ if (collector != null) {
+ if (isListeningForOpNoted()) {
+ setOnOpNotedCallback(null, null);
+ }
+ setOnOpNotedCallback(new HandlerExecutor(Handler.getMain()), collector);
+ } else if (sOnOpNotedCallback != null) {
+ setOnOpNotedCallback(null, null);
+ }
+ }
+ }
+
/**
* @return {@code true} iff the process currently is currently collecting noted appops.
*
- * @see #setNotedAppOpsCollector(AppOpsCollector)
+ * @see #setOnOpNotedCallback
*
* @hide
*/
- public static boolean isCollectingNotedAppOps() {
- return sNotedAppOpsCollector != null;
+ public static boolean isListeningForOpNoted() {
+ return sOnOpNotedCallback != null;
}
/**
- * Callback an app can {@link #setNotedAppOpsCollector register} to monitor the app-ops the
+ * Callback an app can {@link #setOnOpNotedCallback set} to monitor the app-ops the
* system has tracked for it. I.e. each time any app calls {@link #noteOp} or {@link #startOp}
- * one of the callback methods of this object is called.
+ * one of a method of this object is called.
*
- * <p><b>There will be a callback for all app-ops related to runtime permissions, but not
+ * <p><b>There will be a call for all app-ops related to runtime permissions, but not
* necessarily for all other app-ops.
*
* <pre>
- * setNotedAppOpsCollector(new AppOpsCollector() {
+ * setOnOpNotedCallback(getMainExecutor(), new OnOpNotedCallback() {
* ArraySet<Pair<String, String>> opsNotedForThisProcess = new ArraySet<>();
*
* private synchronized void addAccess(String op, String accessLocation) {
@@ -8014,24 +8090,36 @@ public class AppOpsManager {
* });
* </pre>
*
- * @see #setNotedAppOpsCollector
+ * @see #setOnOpNotedCallback
*/
- public abstract static class AppOpsCollector {
+ public abstract static class OnOpNotedCallback {
+ private @NonNull Executor mAsyncExecutor;
+
/** Callback registered with the system. This will receive the async notes ops */
private final IAppOpsAsyncNotedCallback mAsyncCb = new IAppOpsAsyncNotedCallback.Stub() {
@Override
public void opNoted(AsyncNotedAppOp op) {
Objects.requireNonNull(op);
- getAsyncNotedExecutor().execute(() -> onAsyncNoted(op));
+ long token = Binder.clearCallingIdentity();
+ try {
+ getAsyncNotedExecutor().execute(() -> onAsyncNoted(op));
+ } finally {
+ Binder.restoreCallingIdentity(token);
+ }
}
};
+ // TODO moltmann: Remove
/**
+ * Will be removed before R ships.
+ *
* @return The executor for the system to use when calling {@link #onAsyncNoted}.
+ *
+ * @hide
*/
- public @NonNull Executor getAsyncNotedExecutor() {
- return new HandlerExecutor(Handler.getMain());
+ protected @NonNull Executor getAsyncNotedExecutor() {
+ return mAsyncExecutor;
}
/**
@@ -8041,7 +8129,7 @@ public class AppOpsManager {
* <p>Called on the calling thread before the API returns. This allows the app to e.g.
* collect stack traces to figure out where the access came from.
*
- * @param op The op noted
+ * @param op op noted
*/
public abstract void onNoted(@NonNull SyncNotedAppOp op);
@@ -8051,7 +8139,7 @@ public class AppOpsManager {
* <p>This is very similar to {@link #onNoted} only that the tracking was not caused by the
* API provider in a separate process, but by one in the app's own process.
*
- * @param op The op noted
+ * @param op op noted
*/
public abstract void onSelfNoted(@NonNull SyncNotedAppOp op);
@@ -8063,14 +8151,30 @@ public class AppOpsManager {
* guaranteed. Due to how async calls work in Android this might even be delivered slightly
* before the private data is delivered to the app.
*
- * <p>If the app is not running or no {@link AppOpsCollector} is registered a small amount
- * of noted app-ops are buffered and then delivered as soon as a collector is registered.
+ * <p>If the app is not running or no {@link OnOpNotedCallback} is registered a small amount
+ * of noted app-ops are buffered and then delivered as soon as a listener is registered.
*
- * @param asyncOp The op noted
+ * @param asyncOp op noted
*/
public abstract void onAsyncNoted(@NonNull AsyncNotedAppOp asyncOp);
}
+ // TODO moltmann: Remove
+ /**
+ * Will be removed before R ships, leave it just to not break apps immediately.
+ *
+ * @removed
+ *
+ * @hide
+ */
+ @SystemApi
+ @Deprecated
+ public abstract static class AppOpsCollector extends OnOpNotedCallback {
+ public @NonNull Executor getAsyncNotedExecutor() {
+ return new HandlerExecutor(Handler.getMain());
+ }
+ };
+
/**
* Generate a stack trace used for noted app-ops logging.
*
@@ -8479,4 +8583,24 @@ public class AppOpsManager {
public static int leftCircularDistance(int from, int to, int size) {
return (to + size - from) % size;
}
+
+ /**
+ * Helper method for noteOp, startOp and noteProxyOp to call AppOpsService to collect/log
+ * stack traces
+ *
+ * <p> For each call, the stacktrace op code, package name and long version code will be
+ * passed along where it will be logged/collected
+ *
+ * @param op The operation to note
+ */
+ private void collectNoteOpCallsForValidation(int op) {
+ if (NOTE_OP_COLLECTION_ENABLED) {
+ try {
+ mService.collectNoteOpCallsForValidation(getFormattedStackTrace(),
+ op, mContext.getOpPackageName(), mContext.getApplicationInfo().longVersionCode);
+ } catch (RemoteException e) {
+ // Swallow error, only meant for logging ops, should not affect flow of the code
+ }
+ }
+ }
}
diff --git a/core/java/android/app/ApplicationExitInfo.java b/core/java/android/app/ApplicationExitInfo.java
index c55453e94960..5df3257f2444 100644
--- a/core/java/android/app/ApplicationExitInfo.java
+++ b/core/java/android/app/ApplicationExitInfo.java
@@ -16,6 +16,7 @@
package android.app;
+import android.annotation.CurrentTimeMillisLong;
import android.annotation.IntDef;
import android.annotation.NonNull;
import android.annotation.Nullable;
@@ -121,11 +122,30 @@ public final class ApplicationExitInfo implements Parcelable {
public static final int REASON_EXCESSIVE_RESOURCE_USAGE = 9;
/**
- * Application process was killed by the system for various other reasons,
- * for example, the application package got disabled by the user;
- * {@link #getDescription} will specify the cause given by the system.
+ * Application process was killed because of the user request, for example,
+ * user clicked the "Force stop" button of the application in the Settings,
+ * or removed the application away from Recents.
*/
- public static final int REASON_OTHER = 10;
+ public static final int REASON_USER_REQUESTED = 10;
+
+ /**
+ * Application process was killed, because the user it is running as on devices
+ * with mutlple users, was stopped.
+ */
+ public static final int REASON_USER_STOPPED = 11;
+
+ /**
+ * Application process was killed because its dependency was going away, for example,
+ * a stable content provider connection's client will be killed if the provider is killed.
+ */
+ public static final int REASON_DEPENDENCY_DIED = 12;
+
+ /**
+ * Application process was killed by the system for various other reasons which are
+ * not by problems in apps and not actionable by apps, for example, the system just
+ * finished updates; {@link #getDescription} will specify the cause given by the system.
+ */
+ public static final int REASON_OTHER = 13;
/**
* Application process kills subreason is unknown.
@@ -202,6 +222,105 @@ public final class ApplicationExitInfo implements Parcelable {
public static final int SUBREASON_EXCESSIVE_CPU = 7;
/**
+ * System update has done (so the system update process should be killed);
+ * this would be set only when the reason is {@link #REASON_OTHER}.
+ *
+ * For internal use only.
+ * @hide
+ */
+ public static final int SUBREASON_SYSTEM_UPDATE_DONE = 8;
+
+ /**
+ * Kill all foreground services, for now it only occurs when enabling the quiet
+ * mode for the managed profile;
+ * this would be set only when the reason is {@link #REASON_OTHER}.
+ *
+ * For internal use only.
+ * @hide
+ */
+ public static final int SUBREASON_KILL_ALL_FG = 9;
+
+ /**
+ * All background processes except certain ones were killed, for now it only occurs
+ * when the density of the default display is changed;
+ * this would be set only when the reason is {@link #REASON_OTHER}.
+ *
+ * For internal use only.
+ * @hide
+ */
+ public static final int SUBREASON_KILL_ALL_BG_EXCEPT = 10;
+
+ /**
+ * The process associated with the UID was explicitly killed, for example,
+ * it could be because of platform compatibility overrides;
+ * this would be set only when the reason is {@link #REASON_OTHER}.
+ *
+ * For internal use only.
+ * @hide
+ */
+ public static final int SUBREASON_KILL_UID = 11;
+
+ /**
+ * The process was explicitly killed with its PID, typically because of
+ * the low memory for surfaces;
+ * this would be set only when the reason is {@link #REASON_OTHER}.
+ *
+ * For internal use only.
+ * @hide
+ */
+ public static final int SUBREASON_KILL_PID = 12;
+
+ /**
+ * The start of the process was invalid;
+ * this would be set only when the reason is {@link #REASON_OTHER}.
+ *
+ * For internal use only.
+ * @hide
+ */
+ public static final int SUBREASON_INVALID_START = 13;
+
+ /**
+ * The process was killed because it's in an invalid state, typically
+ * it's triggered from SHELL;
+ * this would be set only when the reason is {@link #REASON_OTHER}.
+ *
+ * For internal use only.
+ * @hide
+ */
+ public static final int SUBREASON_INVALID_STATE = 14;
+
+ /**
+ * The process was killed when it's imperceptible to user, because it was
+ * in a bad state;
+ * this would be set only when the reason is {@link #REASON_OTHER}.
+ *
+ * For internal use only.
+ * @hide
+ */
+ public static final int SUBREASON_IMPERCEPTIBLE = 15;
+
+ /**
+ * The process was killed because it's being moved out from LRU list;
+ * this would be set only when the reason is {@link #REASON_OTHER}.
+ *
+ * For internal use only.
+ * @hide
+ */
+ public static final int SUBREASON_REMOVE_LRU = 16;
+
+ /**
+ * The process was killed because it's isolated and was in a cached state;
+ * this would be set only when the reason is {@link #REASON_OTHER}.
+ *
+ * For internal use only.
+ * @hide
+ */
+ public static final int SUBREASON_ISOLATED_NOT_NEEDED = 17;
+
+ // If there is any OEM code which involves additional app kill reasons, it should
+ // be categorized in {@link #REASON_OTHER}, with subreason code starting from 1000.
+
+ /**
* @see {@link #getPid}
*/
private int mPid;
@@ -254,7 +373,7 @@ public final class ApplicationExitInfo implements Parcelable {
/**
* @see {@link #getTimestamp}
*/
- private long mTimestamp;
+ private @CurrentTimeMillisLong long mTimestamp;
/**
* @see {@link #getDescription}
@@ -293,6 +412,9 @@ public final class ApplicationExitInfo implements Parcelable {
REASON_INITIALIZATION_FAILURE,
REASON_PERMISSION_CHANGE,
REASON_EXCESSIVE_RESOURCE_USAGE,
+ REASON_USER_REQUESTED,
+ REASON_USER_STOPPED,
+ REASON_DEPENDENCY_DIED,
REASON_OTHER,
})
@Retention(RetentionPolicy.SOURCE)
@@ -308,6 +430,16 @@ public final class ApplicationExitInfo implements Parcelable {
SUBREASON_LARGE_CACHED,
SUBREASON_MEMORY_PRESSURE,
SUBREASON_EXCESSIVE_CPU,
+ SUBREASON_SYSTEM_UPDATE_DONE,
+ SUBREASON_KILL_ALL_FG,
+ SUBREASON_KILL_ALL_BG_EXCEPT,
+ SUBREASON_KILL_UID,
+ SUBREASON_KILL_PID,
+ SUBREASON_INVALID_START,
+ SUBREASON_INVALID_STATE,
+ SUBREASON_IMPERCEPTIBLE,
+ SUBREASON_REMOVE_LRU,
+ SUBREASON_ISOLATED_NOT_NEEDED,
})
@Retention(RetentionPolicy.SOURCE)
public @interface SubReason {}
@@ -403,7 +535,7 @@ public final class ApplicationExitInfo implements Parcelable {
* The timestamp of the process's death, in milliseconds since the epoch,
* as returned by {@link System#currentTimeMillis System.currentTimeMillis()}.
*/
- public long getTimestamp() {
+ public @CurrentTimeMillisLong long getTimestamp() {
return mTimestamp;
}
@@ -564,7 +696,7 @@ public final class ApplicationExitInfo implements Parcelable {
*
* @hide
*/
- public void setTimestamp(final long timestamp) {
+ public void setTimestamp(final @CurrentTimeMillisLong long timestamp) {
mTimestamp = timestamp;
}
@@ -656,6 +788,8 @@ public final class ApplicationExitInfo implements Parcelable {
mRss = other.mRss;
mTimestamp = other.mTimestamp;
mDescription = other.mDescription;
+ mPackageName = other.mPackageName;
+ mPackageList = other.mPackageList;
}
private ApplicationExitInfo(@NonNull Parcel in) {
@@ -748,6 +882,12 @@ public final class ApplicationExitInfo implements Parcelable {
return "PERMISSION CHANGE";
case REASON_EXCESSIVE_RESOURCE_USAGE:
return "EXCESSIVE RESOURCE USAGE";
+ case REASON_USER_REQUESTED:
+ return "USER REQUESTED";
+ case REASON_USER_STOPPED:
+ return "USER STOPPED";
+ case REASON_DEPENDENCY_DIED:
+ return "DEPENDENCY DIED";
case REASON_OTHER:
return "OTHER KILLS BY SYSTEM";
default:
@@ -772,6 +912,26 @@ public final class ApplicationExitInfo implements Parcelable {
return "MEMORY PRESSURE";
case SUBREASON_EXCESSIVE_CPU:
return "EXCESSIVE CPU USAGE";
+ case SUBREASON_SYSTEM_UPDATE_DONE:
+ return "SYSTEM UPDATE_DONE";
+ case SUBREASON_KILL_ALL_FG:
+ return "KILL ALL FG";
+ case SUBREASON_KILL_ALL_BG_EXCEPT:
+ return "KILL ALL BG EXCEPT";
+ case SUBREASON_KILL_UID:
+ return "KILL UID";
+ case SUBREASON_KILL_PID:
+ return "KILL PID";
+ case SUBREASON_INVALID_START:
+ return "INVALID START";
+ case SUBREASON_INVALID_STATE:
+ return "INVALID STATE";
+ case SUBREASON_IMPERCEPTIBLE:
+ return "IMPERCEPTIBLE";
+ case SUBREASON_REMOVE_LRU:
+ return "REMOVE LRU";
+ case SUBREASON_ISOLATED_NOT_NEEDED:
+ return "ISOLATED NOT NEEDED";
default:
return "UNKNOWN";
}
diff --git a/core/java/android/app/AsyncNotedAppOp.java b/core/java/android/app/AsyncNotedAppOp.java
index 6b1afdad82df..4d955dbe8703 100644
--- a/core/java/android/app/AsyncNotedAppOp.java
+++ b/core/java/android/app/AsyncNotedAppOp.java
@@ -16,6 +16,7 @@
package android.app;
+import android.annotation.CurrentTimeMillisLong;
import android.annotation.IntRange;
import android.annotation.NonNull;
import android.annotation.Nullable;
@@ -23,13 +24,15 @@ import android.os.Parcelable;
import com.android.internal.annotations.Immutable;
import com.android.internal.util.DataClass;
+import com.android.internal.util.Preconditions;
/**
* When an {@link AppOpsManager#noteOp(String, int, String, String, String) app-op is noted} and the
- * app the app-op is noted for has a {@link AppOpsManager.AppOpsCollector} registered the note-event
- * needs to be delivered to the collector. Usually this is done via an {@link SyncNotedAppOp}, but
- * in some cases this is not possible. In this case an {@link AsyncNotedAppOp} is send to the system
- * server and then forwarded to the {@link AppOpsManager.AppOpsCollector} in the app.
+ * app the app-op is noted for has a {@link AppOpsManager.OnOpNotedCallback} registered the
+ * note-event needs to be delivered to the callback. Usually this is done via an
+ * {@link SyncNotedAppOp}, but in some cases this is not possible. In this case an
+ * {@link AsyncNotedAppOp} is send to the system server and then forwarded to the
+ * {@link AppOpsManager.OnOpNotedCallback} in the app.
*/
@Immutable
@DataClass(genEqualsHashCode = true,
@@ -40,7 +43,7 @@ import com.android.internal.util.DataClass;
@DataClass.Suppress({"getOpCode"})
public final class AsyncNotedAppOp implements Parcelable {
/** Op that was noted */
- private final @IntRange(from = 0, to = AppOpsManager._NUM_OP - 1) int mOpCode;
+ private final @IntRange(from = 0) int mOpCode;
/** Uid that noted the op */
private final @IntRange(from = 0) int mNotingUid;
@@ -52,7 +55,7 @@ public final class AsyncNotedAppOp implements Parcelable {
private final @NonNull String mMessage;
/** Milliseconds since epoch when the op was noted */
- private final @IntRange(from = 0) long mTime;
+ private final @CurrentTimeMillisLong long mTime;
/**
* @return Op that was noted.
@@ -61,9 +64,15 @@ public final class AsyncNotedAppOp implements Parcelable {
return AppOpsManager.opToPublicName(mOpCode);
}
+ //TODO eugenesusla: support inlinable expressions in annotation params of @DataClass members to
+ // allow validating via @IntRange(from = 0, to = AppOpsManager._NUM_OP - 1)
+ private void onConstructed() {
+ Preconditions.checkArgumentInRange(mOpCode, 0, AppOpsManager._NUM_OP - 1, "opCode");
+ }
+
- // Code below generated by codegen v1.0.14.
+ // Code below generated by codegen v1.0.15.
//
// DO NOT MODIFY!
// CHECKSTYLE:OFF Generated code
@@ -93,16 +102,15 @@ public final class AsyncNotedAppOp implements Parcelable {
*/
@DataClass.Generated.Member
public AsyncNotedAppOp(
- @IntRange(from = 0, to = AppOpsManager._NUM_OP - 1) int opCode,
+ @IntRange(from = 0) int opCode,
@IntRange(from = 0) int notingUid,
@Nullable String featureId,
@NonNull String message,
- @IntRange(from = 0) long time) {
+ @CurrentTimeMillisLong long time) {
this.mOpCode = opCode;
com.android.internal.util.AnnotationValidations.validate(
IntRange.class, null, mOpCode,
- "from", 0,
- "to", AppOpsManager._NUM_OP - 1);
+ "from", 0);
this.mNotingUid = notingUid;
com.android.internal.util.AnnotationValidations.validate(
IntRange.class, null, mNotingUid,
@@ -113,10 +121,9 @@ public final class AsyncNotedAppOp implements Parcelable {
NonNull.class, null, mMessage);
this.mTime = time;
com.android.internal.util.AnnotationValidations.validate(
- IntRange.class, null, mTime,
- "from", 0);
+ CurrentTimeMillisLong.class, null, mTime);
- // onConstructed(); // You can define this method to get a callback
+ onConstructed();
}
/**
@@ -147,7 +154,7 @@ public final class AsyncNotedAppOp implements Parcelable {
* Milliseconds since epoch when the op was noted
*/
@DataClass.Generated.Member
- public @IntRange(from = 0) long getTime() {
+ public @CurrentTimeMillisLong long getTime() {
return mTime;
}
@@ -223,8 +230,7 @@ public final class AsyncNotedAppOp implements Parcelable {
this.mOpCode = opCode;
com.android.internal.util.AnnotationValidations.validate(
IntRange.class, null, mOpCode,
- "from", 0,
- "to", AppOpsManager._NUM_OP - 1);
+ "from", 0);
this.mNotingUid = notingUid;
com.android.internal.util.AnnotationValidations.validate(
IntRange.class, null, mNotingUid,
@@ -235,10 +241,9 @@ public final class AsyncNotedAppOp implements Parcelable {
NonNull.class, null, mMessage);
this.mTime = time;
com.android.internal.util.AnnotationValidations.validate(
- IntRange.class, null, mTime,
- "from", 0);
+ CurrentTimeMillisLong.class, null, mTime);
- // onConstructed(); // You can define this method to get a callback
+ onConstructed();
}
@DataClass.Generated.Member
@@ -256,10 +261,10 @@ public final class AsyncNotedAppOp implements Parcelable {
};
@DataClass.Generated(
- time = 1581728574427L,
- codegenVersion = "1.0.14",
+ time = 1583866178330L,
+ codegenVersion = "1.0.15",
sourceFile = "frameworks/base/core/java/android/app/AsyncNotedAppOp.java",
- inputSignatures = "private final @android.annotation.IntRange(from=0L, to=96L) int mOpCode\nprivate final @android.annotation.IntRange(from=0L) int mNotingUid\nprivate final @android.annotation.Nullable java.lang.String mFeatureId\nprivate final @android.annotation.NonNull java.lang.String mMessage\nprivate final @android.annotation.IntRange(from=0L) long mTime\npublic @android.annotation.NonNull java.lang.String getOp()\nclass AsyncNotedAppOp extends java.lang.Object implements [android.os.Parcelable]\n@com.android.internal.util.DataClass(genEqualsHashCode=true, genAidl=true, genHiddenConstructor=true)")
+ inputSignatures = "private final @android.annotation.IntRange(from=0L) int mOpCode\nprivate final @android.annotation.IntRange(from=0L) int mNotingUid\nprivate final @android.annotation.Nullable java.lang.String mFeatureId\nprivate final @android.annotation.NonNull java.lang.String mMessage\nprivate final @android.annotation.CurrentTimeMillisLong long mTime\npublic @android.annotation.NonNull java.lang.String getOp()\nprivate void onConstructed()\nclass AsyncNotedAppOp extends java.lang.Object implements [android.os.Parcelable]\n@com.android.internal.util.DataClass(genEqualsHashCode=true, genAidl=true, genHiddenConstructor=true)")
@Deprecated
private void __metadata() {}
diff --git a/core/java/android/app/NotificationHistory.java b/core/java/android/app/NotificationHistory.java
index 8c2cc9492e39..59dc9991c832 100644
--- a/core/java/android/app/NotificationHistory.java
+++ b/core/java/android/app/NotificationHistory.java
@@ -22,6 +22,7 @@ import android.graphics.drawable.Icon;
import android.os.Parcel;
import android.os.Parcelable;
import android.text.TextUtils;
+import android.util.Slog;
import java.util.ArrayList;
import java.util.Arrays;
@@ -107,9 +108,11 @@ public final class NotificationHistory implements Parcelable {
", mChannelName='" + mChannelName + '\'' +
", mChannelId='" + mChannelId + '\'' +
", mUserId=" + mUserId +
+ ", mUid=" + mUid +
", mTitle='" + mTitle + '\'' +
", mText='" + mText + '\'' +
", mIcon=" + mIcon +
+ ", mPostedTimeMs=" + mPostedTimeMs +
", mConversationId=" + mConversationId +
'}';
}
@@ -285,9 +288,7 @@ public final class NotificationHistory implements Parcelable {
if (!hasNextNotification()) {
return null;
}
-
HistoricalNotification n = readNotificationFromParcel(mParcel);
-
mIndex++;
if (!hasNextNotification()) {
mParcel.recycle();
diff --git a/core/java/android/app/SyncNotedAppOp.java b/core/java/android/app/SyncNotedAppOp.java
index aa11b9510c94..13b90ca6ced1 100644
--- a/core/java/android/app/SyncNotedAppOp.java
+++ b/core/java/android/app/SyncNotedAppOp.java
@@ -28,9 +28,9 @@ import com.android.internal.util.DataClass;
* Description of an app-op that was noted for the current process.
*
* <p>This is either delivered after a
- * {@link AppOpsManager.AppOpsCollector#onNoted(SyncNotedAppOp) two way binder call} or
+ * {@link AppOpsManager.OnOpNotedCallback#onNoted(SyncNotedAppOp) two way binder call} or
* when the app
- * {@link AppOpsManager.AppOpsCollector#onSelfNoted(SyncNotedAppOp) notes an app-op for
+ * {@link AppOpsManager.OnOpNotedCallback#onSelfNoted(SyncNotedAppOp) notes an app-op for
* itself}.
*/
@Immutable
diff --git a/core/java/android/app/SystemServiceRegistry.java b/core/java/android/app/SystemServiceRegistry.java
index d04630c747a3..a3bcc9cee39b 100644
--- a/core/java/android/app/SystemServiceRegistry.java
+++ b/core/java/android/app/SystemServiceRegistry.java
@@ -23,7 +23,6 @@ import android.annotation.SystemApi;
import android.app.ContextImpl.ServiceInitializationState;
import android.app.admin.DevicePolicyManager;
import android.app.admin.IDevicePolicyManager;
-import android.app.appsearch.AppSearchManagerFrameworkInitializer;
import android.app.blob.BlobStoreManagerFrameworkInitializer;
import android.app.contentsuggestions.ContentSuggestionsManager;
import android.app.contentsuggestions.IContentSuggestionsManager;
@@ -1297,9 +1296,6 @@ public final class SystemServiceRegistry {
throws ServiceNotFoundException {
return new LightsManager(ctx);
}});
- //TODO(b/136132412): refactor this: 1) merge IIncrementalManager.aidl and
- //IIncrementalManagerNative.aidl, 2) implement the binder interface in
- //IncrementalManagerService.java, 3) use JNI to call native functions
registerService(Context.INCREMENTAL_SERVICE, IncrementalManager.class,
new CachedServiceFetcher<IncrementalManager>() {
@Override
@@ -1346,7 +1342,6 @@ public final class SystemServiceRegistry {
JobSchedulerFrameworkInitializer.registerServiceWrappers();
BlobStoreManagerFrameworkInitializer.initialize();
TelephonyFrameworkInitializer.registerServiceWrappers();
- AppSearchManagerFrameworkInitializer.initialize();
WifiFrameworkInitializer.registerServiceWrappers();
StatsFrameworkInitializer.registerServiceWrappers();
} finally {
diff --git a/core/java/android/app/WindowContext.java b/core/java/android/app/WindowContext.java
index 568456270809..878993ebcd19 100644
--- a/core/java/android/app/WindowContext.java
+++ b/core/java/android/app/WindowContext.java
@@ -60,7 +60,6 @@ public class WindowContext extends ContextWrapper {
mWms = WindowManagerGlobal.getWindowManagerService();
mToken = new WindowTokenClient();
-
final ContextImpl contextImpl = createBaseWindowContext(base, mToken);
attachBaseContext(contextImpl);
contextImpl.setOuterContext(this);
diff --git a/core/java/android/app/admin/DevicePolicyManager.java b/core/java/android/app/admin/DevicePolicyManager.java
index b219394ddfa9..c532279676a0 100644
--- a/core/java/android/app/admin/DevicePolicyManager.java
+++ b/core/java/android/app/admin/DevicePolicyManager.java
@@ -8781,18 +8781,20 @@ public class DevicePolicyManager {
}
/**
+ * This method is mostly deprecated.
+ * Most of the settings that still have an effect have dedicated setter methods or user
+ * restrictions. See individual settings for details.
+ * <p>
* Called by device owner to update {@link android.provider.Settings.Global} settings.
* Validation that the value of the setting is in the correct form for the setting type should
* be performed by the caller.
* <p>
* The settings that can be updated with this method are:
* <ul>
- * <li>{@link android.provider.Settings.Global#ADB_ENABLED}</li>
- * <li>{@link android.provider.Settings.Global#AUTO_TIME}</li>
- * <li>{@link android.provider.Settings.Global#AUTO_TIME_ZONE}</li>
- * <li>{@link android.provider.Settings.Global#DATA_ROAMING}</li>
+ * <li>{@link android.provider.Settings.Global#ADB_ENABLED} : use
+ * {@link UserManager#DISALLOW_DEBUGGING_FEATURES} instead to restrict users from enabling
+ * debugging features and this setting to turn adb on.</li>
* <li>{@link android.provider.Settings.Global#USB_MASS_STORAGE_ENABLED}</li>
- * <li>{@link android.provider.Settings.Global#WIFI_SLEEP_POLICY}</li>
* <li>{@link android.provider.Settings.Global#STAY_ON_WHILE_PLUGGED_IN} This setting is only
* available from {@link android.os.Build.VERSION_CODES#M} onwards and can only be set if
* {@link #setMaximumTimeToLock} is not used to set a timeout.</li>
@@ -8800,6 +8802,16 @@ public class DevicePolicyManager {
* setting is only available from {@link android.os.Build.VERSION_CODES#M} onwards.</li>
* </ul>
* <p>
+ * The following settings used to be supported, but can be controlled in other ways:
+ * <ul>
+ * <li>{@link android.provider.Settings.Global#AUTO_TIME} : Use {@link #setAutoTime} and
+ * {@link UserManager#DISALLOW_CONFIG_DATE_TIME} instead.</li>
+ * <li>{@link android.provider.Settings.Global#AUTO_TIME_ZONE} : Use {@link #setAutoTimeZone}
+ * and {@link UserManager#DISALLOW_CONFIG_DATE_TIME} instead.</li>
+ * <li>{@link android.provider.Settings.Global#DATA_ROAMING} : Use
+ * {@link UserManager#DISALLOW_DATA_ROAMING} instead.</li>
+ * </ul>
+ * <p>
* Changing the following settings has no effect as of {@link android.os.Build.VERSION_CODES#M}:
* <ul>
* <li>{@link android.provider.Settings.Global#BLUETOOTH_ON}. Use
@@ -8811,6 +8823,7 @@ public class DevicePolicyManager {
* <li>{@link android.provider.Settings.Global#NETWORK_PREFERENCE}</li>
* <li>{@link android.provider.Settings.Global#WIFI_ON}. Use
* {@link android.net.wifi.WifiManager#setWifiEnabled(boolean)} instead.</li>
+ * <li>{@link android.provider.Settings.Global#WIFI_SLEEP_POLICY}. No longer has effect.</li>
* </ul>
*
* @param admin Which {@link DeviceAdminReceiver} this request is associated with.
@@ -8989,6 +9002,11 @@ public class DevicePolicyManager {
}
/**
+ * This method is mostly deprecated.
+ * Most of the settings that still have an effect have dedicated setter methods
+ * (e.g. {@link #setLocationEnabled}) or user restrictions.
+ * <p>
+ *
* Called by profile or device owners to update {@link android.provider.Settings.Secure}
* settings. Validation that the value of the setting is in the correct form for the setting
* type should be performed by the caller.
@@ -9001,7 +9019,7 @@ public class DevicePolicyManager {
* <p>
* A device owner can additionally update the following settings:
* <ul>
- * <li>{@link android.provider.Settings.Secure#LOCATION_MODE}</li>
+ * <li>{@link android.provider.Settings.Secure#LOCATION_MODE}, but see note below.</li>
* </ul>
*
* <strong>Note: Starting from Android O, apps should no longer call this method with the
@@ -10355,19 +10373,23 @@ public class DevicePolicyManager {
}
/**
- * Indicates the entity that controls the device or profile owner. Two users/profiles are
- * affiliated if the set of ids set by their device or profile owners intersect.
+ * Indicates the entity that controls the device. Two users are
+ * affiliated if the set of ids set by the device owner and the admin of the secondary user.
*
- * <p>A user/profile that is affiliated with the device owner user is considered to be
+ * <p>A user that is affiliated with the device owner user is considered to be
* affiliated with the device.
*
* <p><strong>Note:</strong> Features that depend on user affiliation (such as security logging
- * or {@link #bindDeviceAdminServiceAsUser}) won't be available when a secondary user or profile
+ * or {@link #bindDeviceAdminServiceAsUser}) won't be available when a secondary user
* is created, until it becomes affiliated. Therefore it is recommended that the appropriate
- * affiliation ids are set by its profile owner as soon as possible after the user/profile is
+ * affiliation ids are set by its owner as soon as possible after the user is
* created.
+ * <p>
+ * Note: This method used to be available for affiliating device owner and profile
+ * owner. However, since Android 11, this combination is not possible. This method is now
+ * only useful for affiliating the primary user with managed secondary users.
*
- * @param admin Which profile or device owner this request is associated with.
+ * @param admin Which device owner, or owner of secondary user, this request is associated with.
* @param ids A set of opaque non-empty affiliation ids.
*
* @throws IllegalArgumentException if {@code ids} is null or contains an empty string.
@@ -10399,10 +10421,10 @@ public class DevicePolicyManager {
}
/**
- * Returns whether this user/profile is affiliated with the device.
+ * Returns whether this user is affiliated with the device.
* <p>
* By definition, the user that the device owner runs on is always affiliated with the device.
- * Any other user/profile is considered affiliated with the device if the set specified by its
+ * Any other user is considered affiliated with the device if the set specified by its
* profile owner via {@link #setAffiliationIds} intersects with the device owner's.
* @see #setAffiliationIds
*/
@@ -10706,14 +10728,18 @@ public class DevicePolicyManager {
}
/**
- * Called by a device owner to bind to a service from a profile owner or vice versa.
- * See {@link #getBindDeviceAdminTargetUsers} for a definition of which
- * device/profile owners are allowed to bind to services of another profile/device owner.
+ * Called by a device owner to bind to a service from a secondary managed user or vice versa.
+ * See {@link #getBindDeviceAdminTargetUsers} for the pre-requirements of a
+ * device owner to bind to services of another managed user.
* <p>
* The service must be protected by {@link android.Manifest.permission#BIND_DEVICE_ADMIN}.
* Note that the {@link Context} used to obtain this
* {@link DevicePolicyManager} instance via {@link Context#getSystemService(Class)} will be used
* to bind to the {@link android.app.Service}.
+ * <p>
+ * Note: This method used to be available for communication between device owner and profile
+ * owner. However, since Android 11, this combination is not possible. This method is now
+ * only useful for communication between device owner and managed secondary users.
*
* @param admin Which {@link DeviceAdminReceiver} this request is associated with.
* @param serviceIntent Identifies the service to connect to. The Intent must specify either an
@@ -10751,14 +10777,11 @@ public class DevicePolicyManager {
}
/**
- * Returns the list of target users that the calling device or profile owner can use when
- * calling {@link #bindDeviceAdminServiceAsUser}.
+ * Returns the list of target users that the calling device owner or owner of secondary user
+ * can use when calling {@link #bindDeviceAdminServiceAsUser}.
* <p>
- * A device owner can bind to a service from a profile owner and vice versa, provided that:
- * <ul>
- * <li>Both belong to the same package name.
- * <li>Both users are affiliated. See {@link #setAffiliationIds}.
- * </ul>
+ * A device owner can bind to a service from a secondary managed user and vice versa, provided
+ * that both users are affiliated. See {@link #setAffiliationIds}.
*/
public @NonNull List<UserHandle> getBindDeviceAdminTargetUsers(@NonNull ComponentName admin) {
throwIfParentInstance("getBindDeviceAdminTargetUsers");
diff --git a/core/java/android/bluetooth/BluetoothA2dp.java b/core/java/android/bluetooth/BluetoothA2dp.java
index d8c653c6d0d5..b672a0857cca 100644
--- a/core/java/android/bluetooth/BluetoothA2dp.java
+++ b/core/java/android/bluetooth/BluetoothA2dp.java
@@ -643,8 +643,9 @@ public final class BluetoothA2dp implements BluetoothProfile {
@SystemApi
@Nullable
@RequiresPermission(Manifest.permission.BLUETOOTH)
- public BluetoothCodecStatus getCodecStatus(@Nullable BluetoothDevice device) {
+ public BluetoothCodecStatus getCodecStatus(@NonNull BluetoothDevice device) {
if (DBG) Log.d(TAG, "getCodecStatus(" + device + ")");
+ verifyDeviceNotNull(device, "getCodecStatus");
try {
final IBluetoothA2dp service = getService();
if (service != null && isEnabled()) {
@@ -670,9 +671,14 @@ public final class BluetoothA2dp implements BluetoothProfile {
*/
@SystemApi
@RequiresPermission(Manifest.permission.BLUETOOTH_PRIVILEGED)
- public void setCodecConfigPreference(@Nullable BluetoothDevice device,
- @Nullable BluetoothCodecConfig codecConfig) {
+ public void setCodecConfigPreference(@NonNull BluetoothDevice device,
+ @NonNull BluetoothCodecConfig codecConfig) {
if (DBG) Log.d(TAG, "setCodecConfigPreference(" + device + ")");
+ verifyDeviceNotNull(device, "setCodecConfigPreference");
+ if (codecConfig == null) {
+ Log.e(TAG, "setCodecConfigPreference: Codec config can't be null");
+ throw new IllegalArgumentException("codecConfig cannot be null");
+ }
try {
final IBluetoothA2dp service = getService();
if (service != null && isEnabled()) {
@@ -695,8 +701,9 @@ public final class BluetoothA2dp implements BluetoothProfile {
*/
@SystemApi
@RequiresPermission(Manifest.permission.BLUETOOTH_PRIVILEGED)
- public void enableOptionalCodecs(@Nullable BluetoothDevice device) {
+ public void enableOptionalCodecs(@NonNull BluetoothDevice device) {
if (DBG) Log.d(TAG, "enableOptionalCodecs(" + device + ")");
+ verifyDeviceNotNull(device, "enableOptionalCodecs");
enableDisableOptionalCodecs(device, true);
}
@@ -709,8 +716,9 @@ public final class BluetoothA2dp implements BluetoothProfile {
*/
@SystemApi
@RequiresPermission(Manifest.permission.BLUETOOTH_PRIVILEGED)
- public void disableOptionalCodecs(@Nullable BluetoothDevice device) {
+ public void disableOptionalCodecs(@NonNull BluetoothDevice device) {
if (DBG) Log.d(TAG, "disableOptionalCodecs(" + device + ")");
+ verifyDeviceNotNull(device, "disableOptionalCodecs");
enableDisableOptionalCodecs(device, false);
}
@@ -750,7 +758,8 @@ public final class BluetoothA2dp implements BluetoothProfile {
@SystemApi
@RequiresPermission(Manifest.permission.BLUETOOTH_ADMIN)
@OptionalCodecsSupportStatus
- public int supportsOptionalCodecs(@Nullable BluetoothDevice device) {
+ public int isOptionalCodecsSupported(@NonNull BluetoothDevice device) {
+ verifyDeviceNotNull(device, "isOptionalCodecsSupported");
try {
final IBluetoothA2dp service = getService();
if (service != null && isEnabled() && isValidDevice(device)) {
@@ -775,7 +784,8 @@ public final class BluetoothA2dp implements BluetoothProfile {
@SystemApi
@RequiresPermission(Manifest.permission.BLUETOOTH_ADMIN)
@OptionalCodecsPreferenceStatus
- public int getOptionalCodecsEnabled(@Nullable BluetoothDevice device) {
+ public int isOptionalCodecsEnabled(@NonNull BluetoothDevice device) {
+ verifyDeviceNotNull(device, "isOptionalCodecsEnabled");
try {
final IBluetoothA2dp service = getService();
if (service != null && isEnabled() && isValidDevice(device)) {
@@ -800,8 +810,9 @@ public final class BluetoothA2dp implements BluetoothProfile {
*/
@SystemApi
@RequiresPermission(Manifest.permission.BLUETOOTH_PRIVILEGED)
- public void setOptionalCodecsEnabled(@Nullable BluetoothDevice device,
+ public void setOptionalCodecsEnabled(@NonNull BluetoothDevice device,
@OptionalCodecsPreferenceStatus int value) {
+ verifyDeviceNotNull(device, "setOptionalCodecsEnabled");
try {
if (value != BluetoothA2dp.OPTIONAL_CODECS_PREF_UNKNOWN
&& value != BluetoothA2dp.OPTIONAL_CODECS_PREF_DISABLED
@@ -854,6 +865,13 @@ public final class BluetoothA2dp implements BluetoothProfile {
return false;
}
+ private void verifyDeviceNotNull(BluetoothDevice device, String methodName) {
+ if (device == null) {
+ Log.e(TAG, methodName + ": device param is null");
+ throw new IllegalArgumentException("Device cannot be null");
+ }
+ }
+
private boolean isValidDevice(BluetoothDevice device) {
if (device == null) return false;
diff --git a/core/java/android/bluetooth/BluetoothAdapter.java b/core/java/android/bluetooth/BluetoothAdapter.java
index 66bfcbd27ca6..6ae68fcad6f4 100644
--- a/core/java/android/bluetooth/BluetoothAdapter.java
+++ b/core/java/android/bluetooth/BluetoothAdapter.java
@@ -1229,10 +1229,11 @@ public final class BluetoothAdapter {
public boolean factoryReset() {
try {
mServiceLock.readLock().lock();
- if (mService != null) {
- return mService.factoryReset();
+ if (mService != null && mService.factoryReset()
+ && mManagerService != null && mManagerService.onFactoryReset()) {
+ return true;
}
- Log.e(TAG, "factoryReset(): IBluetooth Service is null");
+ Log.e(TAG, "factoryReset(): Setting persist.bluetooth.factoryreset to retry later");
SystemProperties.set("persist.bluetooth.factoryreset", "true");
} catch (RemoteException e) {
Log.e(TAG, "", e);
diff --git a/core/java/android/content/ApexContext.java b/core/java/android/content/ApexEnvironment.java
index fe5cedca4654..b4cc3c2bb156 100644
--- a/core/java/android/content/ApexContext.java
+++ b/core/java/android/content/ApexEnvironment.java
@@ -30,29 +30,29 @@ import java.util.Objects;
* @hide
*/
@SystemApi
-public class ApexContext {
+public class ApexEnvironment {
private static final String APEX_DATA = "apexdata";
/**
- * Returns an ApexContext instance for the APEX with the provided {@code apexModuleName}.
+ * Returns an ApexEnvironment instance for the APEX with the provided {@code apexModuleName}.
*
- * <p>To preserve the safety and integrity of APEX modules, you must only obtain the ApexContext
- * for your specific APEX, and you <em>must never</em> attempt to obtain an ApexContext for
- * another APEX. Any coordination between APEXs must be performed through well-defined
- * interfaces; attempting to directly read or write raw files belonging to another APEX will
- * violate the hermetic storage requirements placed upon each module.
+ * <p>To preserve the safety and integrity of APEX modules, you must only obtain the
+ * ApexEnvironment for your specific APEX, and you <em>must never</em> attempt to obtain an
+ * ApexEnvironment for another APEX. Any coordination between APEXs must be performed through
+ * well-defined interfaces; attempting to directly read or write raw files belonging to another
+ * APEX will violate the hermetic storage requirements placed upon each module.
*/
@NonNull
- public static ApexContext getApexContext(@NonNull String apexModuleName) {
+ public static ApexEnvironment getApexEnvironment(@NonNull String apexModuleName) {
Objects.requireNonNull(apexModuleName, "apexModuleName cannot be null");
//TODO(b/141148175): Check that apexModuleName is an actual APEX name
- return new ApexContext(apexModuleName);
+ return new ApexEnvironment(apexModuleName);
}
private final String mApexModuleName;
- private ApexContext(String apexModuleName) {
+ private ApexEnvironment(String apexModuleName) {
mApexModuleName = apexModuleName;
}
diff --git a/core/java/android/content/ContentResolver.java b/core/java/android/content/ContentResolver.java
index c7f42cb85943..911ffa06ed38 100644
--- a/core/java/android/content/ContentResolver.java
+++ b/core/java/android/content/ContentResolver.java
@@ -23,6 +23,7 @@ import android.annotation.IntDef;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.annotation.RequiresPermission;
+import android.annotation.SuppressLint;
import android.annotation.SystemApi;
import android.annotation.TestApi;
import android.annotation.UserIdInt;
@@ -629,7 +630,10 @@ public abstract class ContentResolver implements ContentInterface {
/** @hide */
@IntDef(flag = true, prefix = { "NOTIFY_" }, value = {
NOTIFY_SYNC_TO_NETWORK,
- NOTIFY_SKIP_NOTIFY_FOR_DESCENDANTS
+ NOTIFY_SKIP_NOTIFY_FOR_DESCENDANTS,
+ NOTIFY_INSERT,
+ NOTIFY_UPDATE,
+ NOTIFY_DELETE
})
@Retention(RetentionPolicy.SOURCE)
public @interface NotifyFlags {}
@@ -651,6 +655,36 @@ public abstract class ContentResolver implements ContentInterface {
public static final int NOTIFY_SKIP_NOTIFY_FOR_DESCENDANTS = 1<<1;
/**
+ * Flag for {@link #notifyChange(Uri, ContentObserver, int)}: typically set
+ * by a {@link ContentProvider} to indicate that this notification is the
+ * result of an {@link ContentProvider#insert} call.
+ * <p>
+ * Sending these detailed flags are optional, but providers are strongly
+ * recommended to send them.
+ */
+ public static final int NOTIFY_INSERT = 1 << 2;
+
+ /**
+ * Flag for {@link #notifyChange(Uri, ContentObserver, int)}: typically set
+ * by a {@link ContentProvider} to indicate that this notification is the
+ * result of an {@link ContentProvider#update} call.
+ * <p>
+ * Sending these detailed flags are optional, but providers are strongly
+ * recommended to send them.
+ */
+ public static final int NOTIFY_UPDATE = 1 << 3;
+
+ /**
+ * Flag for {@link #notifyChange(Uri, ContentObserver, int)}: typically set
+ * by a {@link ContentProvider} to indicate that this notification is the
+ * result of a {@link ContentProvider#delete} call.
+ * <p>
+ * Sending these detailed flags are optional, but providers are strongly
+ * recommended to send them.
+ */
+ public static final int NOTIFY_DELETE = 1 << 4;
+
+ /**
* No exception, throttled by app standby normally.
* @hide
*/
@@ -3981,6 +4015,10 @@ public abstract class ContentResolver implements ContentInterface {
* @hide
*/
@SystemApi
+ @TestApi
+ // We can't accept an already-opened FD here, since these methods are
+ // rewriting actual filesystem paths
+ @SuppressLint("StreamFiles")
public static @NonNull Uri decodeFromFile(@NonNull File file) {
return translateDeprecatedDataPath(file.getAbsolutePath());
}
@@ -3997,6 +4035,10 @@ public abstract class ContentResolver implements ContentInterface {
* @hide
*/
@SystemApi
+ @TestApi
+ // We can't accept an already-opened FD here, since these methods are
+ // rewriting actual filesystem paths
+ @SuppressLint("StreamFiles")
public static @NonNull File encodeToFile(@NonNull Uri uri) {
return new File(translateDeprecatedDataPath(uri));
}
diff --git a/core/java/android/content/Context.java b/core/java/android/content/Context.java
index a8f7610ecaf0..6cba3270042d 100644
--- a/core/java/android/content/Context.java
+++ b/core/java/android/content/Context.java
@@ -5109,16 +5109,6 @@ public abstract class Context {
/**
* Use with {@link #getSystemService(String)} to retrieve an
- * {@link android.app.appsearch.AppSearchManager} for
- * indexing and querying app data managed by the system.
- *
- * @see #getSystemService(String)
- * @hide
- */
- public static final String APP_SEARCH_SERVICE = "app_search";
-
- /**
- * Use with {@link #getSystemService(String)} to retrieve an
* {@link android.content.integrity.AppIntegrityManager}.
* @hide
*/
@@ -5138,7 +5128,7 @@ public abstract class Context {
* {@link android.os.incremental.IncrementalManager}.
* @hide
*/
- public static final String INCREMENTAL_SERVICE = "incremental_service";
+ public static final String INCREMENTAL_SERVICE = "incremental";
/**
* Use with {@link #getSystemService(String)} to retrieve an
diff --git a/core/java/android/content/Intent.java b/core/java/android/content/Intent.java
index c6f6972bfc4d..4bb7346d6416 100644
--- a/core/java/android/content/Intent.java
+++ b/core/java/android/content/Intent.java
@@ -1881,6 +1881,20 @@ public class Intent implements Parcelable, Cloneable {
"android.intent.action.MANAGE_PERMISSIONS";
/**
+ * Activity action: Launch UI to manage auto-revoke state.
+ * <p>
+ * Input: {@link #EXTRA_PACKAGE_NAME} specifies the package whose
+ * auto-revoke state will be reviewed (mandatory).
+ * </p>
+ * <p>
+ * Output: Nothing.
+ * </p>
+ */
+ @SdkConstant(SdkConstantType.ACTIVITY_INTENT_ACTION)
+ public static final String ACTION_AUTO_REVOKE_PERMISSIONS =
+ "android.intent.action.AUTO_REVOKE_PERMISSIONS";
+
+ /**
* Activity action: Launch UI to review permissions for an app.
* The system uses this intent if permission review for apps not
* supporting the new runtime permissions model is enabled. In
diff --git a/core/java/android/content/om/OverlayManager.java b/core/java/android/content/om/OverlayManager.java
index dbe39547b0ca..2bdca7d87a78 100644
--- a/core/java/android/content/om/OverlayManager.java
+++ b/core/java/android/content/om/OverlayManager.java
@@ -27,14 +27,50 @@ import android.compat.annotation.ChangeId;
import android.compat.annotation.EnabledAfter;
import android.content.Context;
import android.os.Build;
+import android.os.Process;
import android.os.RemoteException;
import android.os.ServiceManager;
import android.os.UserHandle;
+import com.android.server.SystemConfig;
+
import java.util.List;
/**
* Updates OverlayManager state; gets information about installed overlay packages.
+ *
+ * <p>Users of this API must be actors of any overlays they desire to change the state of.</p>
+ *
+ * <p>An actor is a package responsible for managing the state of overlays targeting overlayables
+ * that specify the actor. For example, an actor may enable or disable an overlay or otherwise
+ * change its state.</p>
+ *
+ * <p>Actors are specified as part of the overlayable definition.
+ *
+ * <pre>{@code
+ * <overlayable name="OverlayableResourcesName" actor="overlay://namespace/actorName">
+ * }</pre></p>
+ *
+ * <p>Actors are defined through {@link SystemConfig}. Only system packages can be used.
+ * The namespace "android" is reserved for use by AOSP and any "android" definitions must
+ * have an implementation on device that fulfill their intended functionality.</p>
+ *
+ * <pre>{@code
+ * <named-actor
+ * namespace="namespace"
+ * name="actorName"
+ * package="com.example.pkg"
+ * />
+ * }</pre></p>
+ *
+ * <p>An actor can manipulate a particular overlay if any of the following is true:
+ * <ul>
+ * <li>its UID is {@link Process#ROOT_UID}, {@link Process#SYSTEM_UID}</li>
+ * <li>it is the target of the overlay package</li>
+ * <li>it has the CHANGE_OVERLAY_PACKAGES permission and the target does not specify an actor</li>
+ * <li>it is the actor specified by the overlayable</li>
+ * </ul></p>
+ *
* @hide
*/
@SystemApi
@@ -84,6 +120,8 @@ public class OverlayManager {
* If a set of overlay packages share the same category, single call to this method is
* equivalent to multiple calls to {@link #setEnabled(String, boolean, UserHandle)}.
*
+ * The caller must pass the actor requirements specified in the class comment.
+ *
* @param packageName the name of the overlay package to enable.
* @param user The user for which to change the overlay.
*
@@ -116,6 +154,8 @@ public class OverlayManager {
* While {@link #setEnabledExclusiveInCategory(String, UserHandle)} doesn't support disabling
* every overlay in a category, this method allows you to disable everything.
*
+ * The caller must pass the actor requirements specified in the class comment.
+ *
* @param packageName the name of the overlay package to enable.
* @param enable {@code false} if the overlay should be turned off.
* @param user The user for which to change the overlay.
diff --git a/core/java/android/content/pm/ActivityInfo.java b/core/java/android/content/pm/ActivityInfo.java
index 622588b63fef..0b2b5b1f0ec4 100644
--- a/core/java/android/content/pm/ActivityInfo.java
+++ b/core/java/android/content/pm/ActivityInfo.java
@@ -290,43 +290,6 @@ public class ActivityInfo extends ComponentInfo implements Parcelable {
public int colorMode = COLOR_MODE_DEFAULT;
/**
- * Value for {@link #preferMinimalPostProcessing} indicating that by default
- * minimal post processing is not preferred.
- *
- * @see android.R.attr#preferMinimalPostProcessing
- * @hide
- */
- public static final boolean MINIMAL_POST_PROCESSING_DEFAULT = false;
-
- /**
- * Indicates whether the activity wants the connected display to do minimal post processing on
- * the produced image or video frames. This will only be requested if this activity's main
- * window is visible on the screen.
- *
- * <p>This setting should be used when low latency has a higher priority than image enhancement
- * processing (e.g. for games or video conferencing).
- *
- * <p>If the Display sink is connected via HDMI, the device will begin to send infoframes with
- * Auto Low Latency Mode enabled and Game Content Type. This will switch the connected display
- * to a minimal image processing mode (if available), which reduces latency, improving the user
- * experience for gaming or video conferencing applications. For more information, see HDMI 2.1
- * specification.
- *
- * <p>If the Display sink has an internal connection or uses some other protocol than HDMI,
- * effects may be similar but implementation-defined.
- *
- * <p>The ability to switch to a mode with minimal post proessing may be disabled by a user
- * setting in the system settings menu. In that case, this field is ignored and the display will
- * remain in its current mode.
- *
- * <p>Set from attribute {@link android.R.attr#preferMinimalPostProcessing}.
- *
- * @see android.view.WindowManager.LayoutParams#preferMinimalPostProcessing
- * @see android.view.Display#isMinimalPostProcessingSupported
- */
- public boolean preferMinimalPostProcessing = MINIMAL_POST_PROCESSING_DEFAULT;
-
- /**
* Bit in {@link #flags} indicating whether this activity is able to
* run in multiple processes. If
* true, the system may instantiate it in the some process as the
@@ -506,6 +469,13 @@ public class ActivityInfo extends ComponentInfo implements Parcelable {
public static final int FLAG_TURN_SCREEN_ON = 0x1000000;
/**
+ * Bit in {@link #flags} indicating whether the display should preferably be switched to a
+ * minimal post processing mode.
+ * See {@link android.R.attr#preferMinimalPostProcessing}
+ */
+ public static final int FLAG_PREFER_MINIMAL_POST_PROCESSING = 0x2000000;
+
+ /**
* @hide Bit in {@link #flags}: If set, this component will only be seen
* by the system user. Only works with broadcast receivers. Set from the
* android.R.attr#systemUserOnly attribute.
@@ -1041,7 +1011,6 @@ public class ActivityInfo extends ComponentInfo implements Parcelable {
requestedVrComponent = orig.requestedVrComponent;
rotationAnimation = orig.rotationAnimation;
colorMode = orig.colorMode;
- preferMinimalPostProcessing = orig.preferMinimalPostProcessing;
maxAspectRatio = orig.maxAspectRatio;
minAspectRatio = orig.minAspectRatio;
}
@@ -1269,7 +1238,6 @@ public class ActivityInfo extends ComponentInfo implements Parcelable {
dest.writeInt(colorMode);
dest.writeFloat(maxAspectRatio);
dest.writeFloat(minAspectRatio);
- dest.writeBoolean(preferMinimalPostProcessing);
}
/**
@@ -1388,7 +1356,6 @@ public class ActivityInfo extends ComponentInfo implements Parcelable {
colorMode = source.readInt();
maxAspectRatio = source.readFloat();
minAspectRatio = source.readFloat();
- preferMinimalPostProcessing = source.readBoolean();
}
/**
diff --git a/core/java/android/content/pm/ApplicationInfo.java b/core/java/android/content/pm/ApplicationInfo.java
index 4c6fef2e1856..a15afe04201b 100644
--- a/core/java/android/content/pm/ApplicationInfo.java
+++ b/core/java/android/content/pm/ApplicationInfo.java
@@ -247,7 +247,11 @@ public class ApplicationInfo extends PackageItemInfo implements Parcelable {
* accommodate different screen densities. Corresponds to
* {@link android.R.styleable#AndroidManifestSupportsScreens_anyDensity
* android:anyDensity}.
+ *
+ * @deprecated Set by default when targeting API 4 or higher and apps
+ * should not set this to false.
*/
+ @Deprecated
public static final int FLAG_SUPPORTS_SCREEN_DENSITIES = 1<<13;
/**
diff --git a/core/java/android/content/pm/IPackageManager.aidl b/core/java/android/content/pm/IPackageManager.aidl
index e9cdbf28e9cb..8c3eef27dd58 100644
--- a/core/java/android/content/pm/IPackageManager.aidl
+++ b/core/java/android/content/pm/IPackageManager.aidl
@@ -748,5 +748,4 @@ interface IPackageManager {
void clearMimeGroup(String packageName, String group);
List<String> getMimeGroup(String packageName, String group);
-
}
diff --git a/core/java/android/content/pm/InstallationFile.java b/core/java/android/content/pm/InstallationFile.java
index edc04c9e7248..de761ad1a305 100644
--- a/core/java/android/content/pm/InstallationFile.java
+++ b/core/java/android/content/pm/InstallationFile.java
@@ -21,13 +21,25 @@ import android.annotation.Nullable;
import android.annotation.SystemApi;
/**
- * Defines the properties of a file in an installation session.
+ * Definition of a file in a streaming installation session.
+ * You can use this class to retrieve the information of such a file, such as its name, size and
+ * metadata. These file attributes will be consistent with those used in:
+ * {@code PackageInstaller.Session#addFile}, when the file was first added into the session.
+ *
+ * WARNING: This is a system API to aid internal development.
+ * Use at your own risk. It will change or be removed without warning.
+ *
+ * @see android.content.pm.PackageInstaller.Session#addFile
* @hide
*/
@SystemApi
public final class InstallationFile {
private final @NonNull InstallationFileParcel mParcel;
+ /**
+ * Constructor, internal use only
+ * @hide
+ */
public InstallationFile(@PackageInstaller.FileLocation int location, @NonNull String name,
long lengthBytes, @Nullable byte[] metadata, @Nullable byte[] signature) {
mParcel = new InstallationFileParcel();
@@ -38,22 +50,44 @@ public final class InstallationFile {
mParcel.signature = signature;
}
+ /**
+ * Installation Location of this file. Can be one of the following three locations:
+ * <ul>
+ * <li>(1) {@code PackageInstaller.LOCATION_DATA_APP}</li>
+ * <li>(2) {@code PackageInstaller.LOCATION_MEDIA_OBB}</li>
+ * <li>(3) {@code PackageInstaller.LOCATION_MEDIA_DATA}</li>
+ * </ul>
+ * @see android.content.pm.PackageInstaller
+ * @return Integer that denotes the installation location of the file.
+ */
public @PackageInstaller.FileLocation int getLocation() {
return mParcel.location;
}
+ /**
+ * @return Name of the file.
+ */
public @NonNull String getName() {
return mParcel.name;
}
+ /**
+ * @return File size in bytes.
+ */
public long getLengthBytes() {
return mParcel.size;
}
+ /**
+ * @return File metadata as a byte array
+ */
public @Nullable byte[] getMetadata() {
return mParcel.metadata;
}
+ /**
+ * @return File signature info as a byte array
+ */
public @Nullable byte[] getSignature() {
return mParcel.signature;
}
diff --git a/core/java/android/content/pm/PackageManager.java b/core/java/android/content/pm/PackageManager.java
index 9b28cb5e88ab..7600a08a256c 100644
--- a/core/java/android/content/pm/PackageManager.java
+++ b/core/java/android/content/pm/PackageManager.java
@@ -2227,6 +2227,9 @@ public abstract class PackageManager {
* <li>{@code VkPhysicalDeviceSamplerYcbcrConversionFeatures::samplerYcbcrConversion} is
* supported.</li>
* </ul>
+ * A subset of devices that support Vulkan 1.1 do so via software emulation. For more
+ * information, see
+ * <a href="{@docRoot}ndk/guides/graphics/design-notes">Vulkan Design Guidelines</a>.
*/
@SdkConstant(SdkConstantType.FEATURE)
public static final String FEATURE_VULKAN_HARDWARE_VERSION = "android.hardware.vulkan.version";
@@ -3400,29 +3403,12 @@ public abstract class PackageManager {
public static final int FLAG_PERMISSION_ONE_TIME = 1 << 16;
/**
- * Permission flag: The permission is whitelisted to not be auto-revoked when app goes unused.
- *
- * @hide
- */
- @SystemApi
- public static final int FLAG_PERMISSION_AUTO_REVOKE_IF_UNUSED = 1 << 17;
-
- /**
- * Permission flag: Whether {@link #FLAG_PERMISSION_AUTO_REVOKE_IF_UNUSED} state was set by
- * user.
- *
- * @hide
- */
- @SystemApi
- public static final int FLAG_PERMISSION_AUTO_REVOKE_USER_SET = 1 << 18;
-
- /**
* Permission flag: Whether permission was revoked by auto-revoke.
*
* @hide
*/
@SystemApi
- public static final int FLAG_PERMISSION_AUTO_REVOKED = 1 << 20;
+ public static final int FLAG_PERMISSION_AUTO_REVOKED = 1 << 17;
/**
* Permission flags: Reserved for use by the permission controller.
@@ -3476,8 +3462,6 @@ public abstract class PackageManager {
| FLAG_PERMISSION_GRANTED_BY_ROLE
| FLAG_PERMISSION_REVOKED_COMPAT
| FLAG_PERMISSION_ONE_TIME
- | FLAG_PERMISSION_AUTO_REVOKE_IF_UNUSED
- | FLAG_PERMISSION_AUTO_REVOKE_USER_SET
| FLAG_PERMISSION_AUTO_REVOKED;
/**
@@ -4302,8 +4286,6 @@ public abstract class PackageManager {
FLAG_PERMISSION_GRANTED_BY_ROLE,
FLAG_PERMISSION_REVOKED_COMPAT,
FLAG_PERMISSION_ONE_TIME,
- FLAG_PERMISSION_AUTO_REVOKE_IF_UNUSED,
- FLAG_PERMISSION_AUTO_REVOKE_USER_SET,
FLAG_PERMISSION_AUTO_REVOKED
})
@Retention(RetentionPolicy.SOURCE)
@@ -7471,8 +7453,6 @@ public abstract class PackageManager {
case FLAG_PERMISSION_GRANTED_BY_ROLE: return "GRANTED_BY_ROLE";
case FLAG_PERMISSION_REVOKED_COMPAT: return "REVOKED_COMPAT";
case FLAG_PERMISSION_ONE_TIME: return "ONE_TIME";
- case FLAG_PERMISSION_AUTO_REVOKE_IF_UNUSED: return "AUTO_REVOKE_IF_UNUSED";
- case FLAG_PERMISSION_AUTO_REVOKE_USER_SET: return "AUTO_REVOKE_USER_SET";
case FLAG_PERMISSION_AUTO_REVOKED: return "AUTO_REVOKED";
default: return Integer.toString(flag);
}
diff --git a/core/java/android/content/pm/PackageParser.java b/core/java/android/content/pm/PackageParser.java
index 64f73cf1a56c..c6875a4b3443 100644
--- a/core/java/android/content/pm/PackageParser.java
+++ b/core/java/android/content/pm/PackageParser.java
@@ -4180,7 +4180,6 @@ public class PackageParser {
a.info.directBootAware = false;
a.info.rotationAnimation = ROTATION_ANIMATION_UNSPECIFIED;
a.info.colorMode = ActivityInfo.COLOR_MODE_DEFAULT;
- a.info.preferMinimalPostProcessing = ActivityInfo.MINIMAL_POST_PROCESSING_DEFAULT;
if (hardwareAccelerated) {
a.info.flags |= ActivityInfo.FLAG_HARDWARE_ACCELERATED;
}
@@ -4395,9 +4394,10 @@ public class PackageParser {
a.info.colorMode = sa.getInt(R.styleable.AndroidManifestActivity_colorMode,
ActivityInfo.COLOR_MODE_DEFAULT);
- a.info.preferMinimalPostProcessing = sa.getBoolean(
- R.styleable.AndroidManifestActivity_preferMinimalPostProcessing,
- ActivityInfo.MINIMAL_POST_PROCESSING_DEFAULT);
+ if (sa.getBoolean(
+ R.styleable.AndroidManifestActivity_preferMinimalPostProcessing, false)) {
+ a.info.flags |= ActivityInfo.FLAG_PREFER_MINIMAL_POST_PROCESSING;
+ }
if (sa.getBoolean(R.styleable.AndroidManifestActivity_showWhenLocked, false)) {
a.info.flags |= ActivityInfo.FLAG_SHOW_WHEN_LOCKED;
diff --git a/core/java/android/content/pm/parsing/PackageInfoWithoutStateUtils.java b/core/java/android/content/pm/parsing/PackageInfoWithoutStateUtils.java
index f65b80ab2229..9a1f7c9e80c5 100644
--- a/core/java/android/content/pm/parsing/PackageInfoWithoutStateUtils.java
+++ b/core/java/android/content/pm/parsing/PackageInfoWithoutStateUtils.java
@@ -451,7 +451,6 @@ public class PackageInfoWithoutStateUtils {
ai.requestedVrComponent = a.getRequestedVrComponent();
ai.rotationAnimation = a.getRotationAnimation();
ai.colorMode = a.getColorMode();
- ai.preferMinimalPostProcessing = a.isPreferMinimalPostProcessing();
ai.windowLayout = a.getWindowLayout();
ai.metaData = a.getMetaData();
ai.applicationInfo = applicationInfo;
diff --git a/core/java/android/content/pm/parsing/component/ParsedActivity.java b/core/java/android/content/pm/parsing/component/ParsedActivity.java
index 7a46e3868f95..d32171dfe962 100644
--- a/core/java/android/content/pm/parsing/component/ParsedActivity.java
+++ b/core/java/android/content/pm/parsing/component/ParsedActivity.java
@@ -78,8 +78,6 @@ public class ParsedActivity extends ParsedMainComponent {
int rotationAnimation = -1;
int colorMode;
- boolean preferMinimalPostProcessing;
-
@Nullable
ActivityInfo.WindowLayout windowLayout;
@@ -135,7 +133,6 @@ public class ParsedActivity extends ParsedMainComponent {
activity.setDirectBootAware(false);
activity.rotationAnimation = ROTATION_ANIMATION_UNSPECIFIED;
activity.colorMode = ActivityInfo.COLOR_MODE_DEFAULT;
- activity.preferMinimalPostProcessing = ActivityInfo.MINIMAL_POST_PROCESSING_DEFAULT;
if (hardwareAccelerated) {
activity.setFlags(activity.getFlags() | ActivityInfo.FLAG_HARDWARE_ACCELERATED);
}
@@ -285,7 +282,6 @@ public class ParsedActivity extends ParsedMainComponent {
dest.writeString(this.requestedVrComponent);
dest.writeInt(this.rotationAnimation);
dest.writeInt(this.colorMode);
- dest.writeBoolean(this.preferMinimalPostProcessing);
dest.writeBundle(this.metaData);
if (windowLayout != null) {
@@ -328,7 +324,6 @@ public class ParsedActivity extends ParsedMainComponent {
this.requestedVrComponent = in.readString();
this.rotationAnimation = in.readInt();
this.colorMode = in.readInt();
- this.preferMinimalPostProcessing = in.readBoolean();
this.metaData = in.readBundle();
if (in.readBoolean()) {
windowLayout = new ActivityInfo.WindowLayout(in);
@@ -438,10 +433,6 @@ public class ParsedActivity extends ParsedMainComponent {
return colorMode;
}
- public boolean isPreferMinimalPostProcessing() {
- return preferMinimalPostProcessing;
- }
-
@Nullable
public ActivityInfo.WindowLayout getWindowLayout() {
return windowLayout;
diff --git a/core/java/android/content/pm/parsing/component/ParsedActivityUtils.java b/core/java/android/content/pm/parsing/component/ParsedActivityUtils.java
index 555cdd0bc8cb..1dcf262d46ba 100644
--- a/core/java/android/content/pm/parsing/component/ParsedActivityUtils.java
+++ b/core/java/android/content/pm/parsing/component/ParsedActivityUtils.java
@@ -129,12 +129,12 @@ public class ParsedActivityUtils {
| flag(ActivityInfo.FLAG_RESUME_WHILE_PAUSING, R.styleable.AndroidManifestActivity_resumeWhilePausing, sa)
| flag(ActivityInfo.FLAG_SHOW_WHEN_LOCKED, R.styleable.AndroidManifestActivity_showWhenLocked, sa)
| flag(ActivityInfo.FLAG_SUPPORTS_PICTURE_IN_PICTURE, R.styleable.AndroidManifestActivity_supportsPictureInPicture, sa)
- | flag(ActivityInfo.FLAG_TURN_SCREEN_ON, R.styleable.AndroidManifestActivity_turnScreenOn, sa);
+ | flag(ActivityInfo.FLAG_TURN_SCREEN_ON, R.styleable.AndroidManifestActivity_turnScreenOn, sa)
+ | flag(ActivityInfo.FLAG_PREFER_MINIMAL_POST_PROCESSING, R.styleable.AndroidManifestActivity_preferMinimalPostProcessing, sa);
activity.privateFlags |= flag(ActivityInfo.FLAG_INHERIT_SHOW_WHEN_LOCKED, R.styleable.AndroidManifestActivity_inheritShowWhenLocked, sa);
activity.colorMode = sa.getInt(R.styleable.AndroidManifestActivity_colorMode, ActivityInfo.COLOR_MODE_DEFAULT);
- activity.preferMinimalPostProcessing = sa.getBoolean(R.styleable.AndroidManifestActivity_preferMinimalPostProcessing, ActivityInfo.MINIMAL_POST_PROCESSING_DEFAULT);
activity.documentLaunchMode = sa.getInt(R.styleable.AndroidManifestActivity_documentLaunchMode, ActivityInfo.DOCUMENT_LAUNCH_NONE);
activity.launchMode = sa.getInt(R.styleable.AndroidManifestActivity_launchMode, ActivityInfo.LAUNCH_MULTIPLE);
activity.lockTaskLaunchMode = sa.getInt(R.styleable.AndroidManifestActivity_lockTaskMode, 0);
diff --git a/core/java/android/database/ContentObserver.java b/core/java/android/database/ContentObserver.java
index 69ca581e1559..ede264d042ce 100644
--- a/core/java/android/database/ContentObserver.java
+++ b/core/java/android/database/ContentObserver.java
@@ -16,11 +16,17 @@
package android.database;
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.annotation.UserIdInt;
import android.compat.annotation.UnsupportedAppUsage;
+import android.content.ContentResolver.NotifyFlags;
import android.net.Uri;
import android.os.Handler;
import android.os.UserHandle;
+import java.util.Arrays;
+
/**
* Receives call backs for changes to content.
* Must be implemented by objects which are added to a {@link ContentObservable}.
@@ -101,12 +107,10 @@ public abstract class ContentObserver {
* This method is called when a content change occurs.
* Includes the changed content Uri when available.
* <p>
- * Subclasses should override this method to handle content changes.
- * To ensure correct operation on older versions of the framework that
- * did not provide a Uri argument, applications should also implement
- * the {@link #onChange(boolean)} overload of this method whenever they
- * implement the {@link #onChange(boolean, Uri)} overload.
- * </p><p>
+ * Subclasses should override this method to handle content changes. To
+ * ensure correct operation on older versions of the framework that did not
+ * provide richer arguments, applications should implement all overloads.
+ * <p>
* Example implementation:
* <pre><code>
* // Implement the onChange(boolean) method to delegate the change notification to
@@ -126,38 +130,63 @@ public abstract class ContentObserver {
* </p>
*
* @param selfChange True if this is a self-change notification.
- * @param uri The Uri of the changed content, or null if unknown.
+ * @param uri The Uri of the changed content.
*/
- public void onChange(boolean selfChange, Uri uri) {
+ public void onChange(boolean selfChange, @Nullable Uri uri) {
onChange(selfChange);
}
/**
- * Dispatches a change notification to the observer. Includes the changed
- * content Uri when available and also the user whose content changed.
+ * This method is called when a content change occurs. Includes the changed
+ * content Uri when available.
+ * <p>
+ * Subclasses should override this method to handle content changes. To
+ * ensure correct operation on older versions of the framework that did not
+ * provide richer arguments, applications should implement all overloads.
*
* @param selfChange True if this is a self-change notification.
- * @param uri The Uri of the changed content, or null if unknown.
- * @param userId The user whose content changed. Can be either a specific
- * user or {@link UserHandle#USER_ALL}.
- *
- * @hide
+ * @param uri The Uri of the changed content.
+ * @param flags Flags indicating details about this change.
*/
- public void onChange(boolean selfChange, Uri uri, int userId) {
+ public void onChange(boolean selfChange, @Nullable Uri uri, @NotifyFlags int flags) {
onChange(selfChange, uri);
}
/**
- * Dispatches a change notification to the observer.
+ * This method is called when a content change occurs. Includes the changed
+ * content Uris when available.
* <p>
- * If a {@link Handler} was supplied to the {@link ContentObserver} constructor,
- * then a call to the {@link #onChange} method is posted to the handler's message queue.
- * Otherwise, the {@link #onChange} method is invoked immediately on this thread.
- * </p>
+ * Subclasses should override this method to handle content changes. To
+ * ensure correct operation on older versions of the framework that did not
+ * provide richer arguments, applications should implement all overloads.
*
* @param selfChange True if this is a self-change notification.
+ * @param uris The Uris of the changed content.
+ * @param flags Flags indicating details about this change.
+ */
+ public void onChange(boolean selfChange, @NonNull Iterable<Uri> uris, @NotifyFlags int flags) {
+ for (Uri uri : uris) {
+ onChange(selfChange, uri, flags);
+ }
+ }
+
+ /** @hide */
+ public void onChange(boolean selfChange, @NonNull Iterable<Uri> uris, @NotifyFlags int flags,
+ @UserIdInt int userId) {
+ onChange(selfChange, uris, flags);
+ }
+
+ /**
+ * Dispatches a change notification to the observer.
+ * <p>
+ * If a {@link Handler} was supplied to the {@link ContentObserver}
+ * constructor, then a call to the {@link #onChange} method is posted to the
+ * handler's message queue. Otherwise, the {@link #onChange} method is
+ * invoked immediately on this thread.
*
- * @deprecated Use {@link #dispatchChange(boolean, Uri)} instead.
+ * @deprecated Callers should migrate towards using a richer overload that
+ * provides more details about the change, such as
+ * {@link #dispatchChange(boolean, Iterable, int)}.
*/
@Deprecated
public final void dispatchChange(boolean selfChange) {
@@ -165,57 +194,66 @@ public abstract class ContentObserver {
}
/**
- * Dispatches a change notification to the observer.
- * Includes the changed content Uri when available.
+ * Dispatches a change notification to the observer. Includes the changed
+ * content Uri when available.
* <p>
- * If a {@link Handler} was supplied to the {@link ContentObserver} constructor,
- * then a call to the {@link #onChange} method is posted to the handler's message queue.
- * Otherwise, the {@link #onChange} method is invoked immediately on this thread.
- * </p>
+ * If a {@link Handler} was supplied to the {@link ContentObserver}
+ * constructor, then a call to the {@link #onChange} method is posted to the
+ * handler's message queue. Otherwise, the {@link #onChange} method is
+ * invoked immediately on this thread.
*
* @param selfChange True if this is a self-change notification.
- * @param uri The Uri of the changed content, or null if unknown.
+ * @param uri The Uri of the changed content.
*/
- public final void dispatchChange(boolean selfChange, Uri uri) {
- dispatchChange(selfChange, uri, UserHandle.getCallingUserId());
+ public final void dispatchChange(boolean selfChange, @Nullable Uri uri) {
+ dispatchChange(selfChange, Arrays.asList(uri), 0, UserHandle.getCallingUserId());
}
/**
* Dispatches a change notification to the observer. Includes the changed
- * content Uri when available and also the user whose content changed.
+ * content Uri when available.
* <p>
- * If a {@link Handler} was supplied to the {@link ContentObserver} constructor,
- * then a call to the {@link #onChange} method is posted to the handler's message queue.
- * Otherwise, the {@link #onChange} method is invoked immediately on this thread.
- * </p>
+ * If a {@link Handler} was supplied to the {@link ContentObserver}
+ * constructor, then a call to the {@link #onChange} method is posted to the
+ * handler's message queue. Otherwise, the {@link #onChange} method is
+ * invoked immediately on this thread.
*
* @param selfChange True if this is a self-change notification.
- * @param uri The Uri of the changed content, or null if unknown.
- * @param userId The user whose content changed.
+ * @param uri The Uri of the changed content.
+ * @param flags Flags indicating details about this change.
*/
- private void dispatchChange(boolean selfChange, Uri uri, int userId) {
- if (mHandler == null) {
- onChange(selfChange, uri, userId);
- } else {
- mHandler.post(new NotificationRunnable(selfChange, uri, userId));
- }
+ public final void dispatchChange(boolean selfChange, @Nullable Uri uri,
+ @NotifyFlags int flags) {
+ dispatchChange(selfChange, Arrays.asList(uri), flags, UserHandle.getCallingUserId());
}
+ /**
+ * Dispatches a change notification to the observer. Includes the changed
+ * content Uris when available.
+ * <p>
+ * If a {@link Handler} was supplied to the {@link ContentObserver}
+ * constructor, then a call to the {@link #onChange} method is posted to the
+ * handler's message queue. Otherwise, the {@link #onChange} method is
+ * invoked immediately on this thread.
+ *
+ * @param selfChange True if this is a self-change notification.
+ * @param uris The Uri of the changed content.
+ * @param flags Flags indicating details about this change.
+ */
+ public final void dispatchChange(boolean selfChange, @NonNull Iterable<Uri> uris,
+ @NotifyFlags int flags) {
+ dispatchChange(selfChange, uris, flags, UserHandle.getCallingUserId());
+ }
- private final class NotificationRunnable implements Runnable {
- private final boolean mSelfChange;
- private final Uri mUri;
- private final int mUserId;
-
- public NotificationRunnable(boolean selfChange, Uri uri, int userId) {
- mSelfChange = selfChange;
- mUri = uri;
- mUserId = userId;
- }
-
- @Override
- public void run() {
- ContentObserver.this.onChange(mSelfChange, mUri, mUserId);
+ /** @hide */
+ public final void dispatchChange(boolean selfChange, @NonNull Iterable<Uri> uris,
+ @NotifyFlags int flags, @UserIdInt int userId) {
+ if (mHandler == null) {
+ onChange(selfChange, uris, flags, userId);
+ } else {
+ mHandler.post(() -> {
+ onChange(selfChange, uris, flags, userId);
+ });
}
}
@@ -228,9 +266,16 @@ public abstract class ContentObserver {
@Override
public void onChange(boolean selfChange, Uri uri, int userId) {
+ // This is kept intact purely for apps using hidden APIs, to
+ // redirect to the updated implementation
+ onChangeEtc(selfChange, new Uri[] { uri }, 0, userId);
+ }
+
+ @Override
+ public void onChangeEtc(boolean selfChange, Uri[] uris, int flags, int userId) {
ContentObserver contentObserver = mContentObserver;
if (contentObserver != null) {
- contentObserver.dispatchChange(selfChange, uri, userId);
+ contentObserver.dispatchChange(selfChange, Arrays.asList(uris), flags, userId);
}
}
diff --git a/core/java/android/database/CursorToBulkCursorAdaptor.java b/core/java/android/database/CursorToBulkCursorAdaptor.java
index 02eddf239dca..1855dd254ad4 100644
--- a/core/java/android/database/CursorToBulkCursorAdaptor.java
+++ b/core/java/android/database/CursorToBulkCursorAdaptor.java
@@ -16,9 +16,14 @@
package android.database;
+import android.annotation.NonNull;
+import android.annotation.UserIdInt;
+import android.content.ContentResolver.NotifyFlags;
import android.net.Uri;
import android.os.*;
+import java.util.ArrayList;
+
/**
* Wraps a BulkCursor around an existing Cursor making it remotable.
@@ -76,9 +81,18 @@ public final class CursorToBulkCursorAdaptor extends BulkCursorNative
}
@Override
- public void onChange(boolean selfChange, Uri uri) {
+ public void onChange(boolean selfChange, @NonNull Iterable<Uri> uris,
+ @NotifyFlags int flags, @UserIdInt int userId) {
+ // Since we deliver changes from the most-specific to least-specific
+ // overloads, we only need to redirect from the most-specific local
+ // method to the most-specific remote method
+
+ final ArrayList<Uri> asList = new ArrayList<>();
+ uris.forEach(asList::add);
+ final Uri[] asArray = asList.toArray(new Uri[asList.size()]);
+
try {
- mRemote.onChange(selfChange, uri, android.os.Process.myUid());
+ mRemote.onChangeEtc(selfChange, asArray, flags, userId);
} catch (RemoteException ex) {
// Do nothing, the far side is dead
}
diff --git a/core/java/android/database/IContentObserver.aidl b/core/java/android/database/IContentObserver.aidl
index 623556695341..19284cf40617 100644
--- a/core/java/android/database/IContentObserver.aidl
+++ b/core/java/android/database/IContentObserver.aidl
@@ -22,8 +22,7 @@ import android.net.Uri;
/**
* @hide
*/
-interface IContentObserver
-{
+interface IContentObserver {
/**
* This method is called when an update occurs to the cursor that is being
* observed. selfUpdate is true if the update was caused by a call to
@@ -31,4 +30,11 @@ interface IContentObserver
*/
@UnsupportedAppUsage
oneway void onChange(boolean selfUpdate, in Uri uri, int userId);
+
+ /**
+ * This method is called when an update occurs to the cursor that is being
+ * observed. selfUpdate is true if the update was caused by a call to
+ * commit on the cursor that is being observed.
+ */
+ oneway void onChangeEtc(boolean selfUpdate, in Uri[] uri, int flags, int userId);
}
diff --git a/core/java/android/hardware/fingerprint/FingerprintManager.java b/core/java/android/hardware/fingerprint/FingerprintManager.java
index 2a71da83027d..91451427b45e 100644
--- a/core/java/android/hardware/fingerprint/FingerprintManager.java
+++ b/core/java/android/hardware/fingerprint/FingerprintManager.java
@@ -129,10 +129,6 @@ public class FingerprintManager implements BiometricAuthenticator, BiometricFing
super(mac);
}
- public CryptoObject(@NonNull IdentityCredential credential) {
- super(credential);
- }
-
/**
* Get {@link Signature} object.
* @return {@link Signature} object or null if this doesn't contain one.
@@ -160,8 +156,9 @@ public class FingerprintManager implements BiometricAuthenticator, BiometricFing
/**
* Get {@link IdentityCredential} object.
* @return {@link IdentityCredential} object or null if this doesn't contain one.
+ * @hide
*/
- public @Nullable IdentityCredential getIdentityCredential() {
+ public IdentityCredential getIdentityCredential() {
return super.getIdentityCredential();
}
}
diff --git a/core/java/android/inputmethodservice/InputMethodService.java b/core/java/android/inputmethodservice/InputMethodService.java
index 9e639346de73..1b6c1ee4f7e2 100644
--- a/core/java/android/inputmethodservice/InputMethodService.java
+++ b/core/java/android/inputmethodservice/InputMethodService.java
@@ -611,6 +611,10 @@ public class InputMethodService extends AbstractInputMethodService {
public void unbindInput() {
if (DEBUG) Log.v(TAG, "unbindInput(): binding=" + mInputBinding
+ " ic=" + mInputConnection);
+ // Unbind input is per process per display.
+ // TODO(b/150902448): free-up IME surface when target is changing.
+ // e.g. DisplayContent#setInputMethodTarget()
+ removeImeSurface();
onUnbindInput();
mInputBinding = null;
mInputConnection = null;
diff --git a/core/java/android/net/ConnectivityManager.java b/core/java/android/net/ConnectivityManager.java
index 38ef814561e6..fc6954fb4808 100644
--- a/core/java/android/net/ConnectivityManager.java
+++ b/core/java/android/net/ConnectivityManager.java
@@ -53,7 +53,6 @@ import android.os.RemoteException;
import android.os.ResultReceiver;
import android.os.ServiceManager;
import android.os.ServiceSpecificException;
-import android.os.SystemClock;
import android.provider.Settings;
import android.telephony.SubscriptionManager;
import android.telephony.TelephonyManager;
@@ -808,7 +807,7 @@ public class ConnectivityManager {
private INetworkManagementService mNMService;
private INetworkPolicyManager mNPManager;
- private TetheringManager mTetheringManager;
+ private final TetheringManager mTetheringManager;
/**
* Tests if a given integer represents a valid network type.
@@ -2274,6 +2273,7 @@ public class ConnectivityManager {
public ConnectivityManager(Context context, IConnectivityManager service) {
mContext = Preconditions.checkNotNull(context, "missing context");
mService = Preconditions.checkNotNull(service, "missing IConnectivityManager");
+ mTetheringManager = (TetheringManager) mContext.getSystemService(Context.TETHERING_SERVICE);
sInstance = this;
}
@@ -2347,28 +2347,6 @@ public class ConnectivityManager {
return getInstanceOrNull();
}
- private static final int TETHERING_TIMEOUT_MS = 60_000;
- private final Object mTetheringLock = new Object();
-
- private TetheringManager getTetheringManager() {
- synchronized (mTetheringLock) {
- if (mTetheringManager != null) {
- return mTetheringManager;
- }
- final long before = System.currentTimeMillis();
- while ((mTetheringManager = (TetheringManager) mContext.getSystemService(
- Context.TETHERING_SERVICE)) == null) {
- if (System.currentTimeMillis() - before > TETHERING_TIMEOUT_MS) {
- Log.e(TAG, "Timeout waiting tethering service not ready yet");
- throw new IllegalStateException("No tethering service yet");
- }
- SystemClock.sleep(100);
- }
-
- return mTetheringManager;
- }
- }
-
/**
* Get the set of tetherable, available interfaces. This list is limited by
* device configuration and current interface existence.
@@ -2382,7 +2360,7 @@ public class ConnectivityManager {
@UnsupportedAppUsage
@Deprecated
public String[] getTetherableIfaces() {
- return getTetheringManager().getTetherableIfaces();
+ return mTetheringManager.getTetherableIfaces();
}
/**
@@ -2397,7 +2375,7 @@ public class ConnectivityManager {
@UnsupportedAppUsage
@Deprecated
public String[] getTetheredIfaces() {
- return getTetheringManager().getTetheredIfaces();
+ return mTetheringManager.getTetheredIfaces();
}
/**
@@ -2418,7 +2396,7 @@ public class ConnectivityManager {
@UnsupportedAppUsage
@Deprecated
public String[] getTetheringErroredIfaces() {
- return getTetheringManager().getTetheringErroredIfaces();
+ return mTetheringManager.getTetheringErroredIfaces();
}
/**
@@ -2462,7 +2440,7 @@ public class ConnectivityManager {
@UnsupportedAppUsage
@Deprecated
public int tether(String iface) {
- return getTetheringManager().tether(iface);
+ return mTetheringManager.tether(iface);
}
/**
@@ -2486,7 +2464,7 @@ public class ConnectivityManager {
@UnsupportedAppUsage
@Deprecated
public int untether(String iface) {
- return getTetheringManager().untether(iface);
+ return mTetheringManager.untether(iface);
}
/**
@@ -2512,7 +2490,7 @@ public class ConnectivityManager {
@RequiresPermission(anyOf = {android.Manifest.permission.TETHER_PRIVILEGED,
android.Manifest.permission.WRITE_SETTINGS})
public boolean isTetheringSupported() {
- return getTetheringManager().isTetheringSupported();
+ return mTetheringManager.isTetheringSupported();
}
/**
@@ -2605,7 +2583,7 @@ public class ConnectivityManager {
final TetheringRequest request = new TetheringRequest.Builder(type)
.setSilentProvisioning(!showProvisioningUi).build();
- getTetheringManager().startTethering(request, executor, tetheringCallback);
+ mTetheringManager.startTethering(request, executor, tetheringCallback);
}
/**
@@ -2624,7 +2602,7 @@ public class ConnectivityManager {
@Deprecated
@RequiresPermission(android.Manifest.permission.TETHER_PRIVILEGED)
public void stopTethering(int type) {
- getTetheringManager().stopTethering(type);
+ mTetheringManager.stopTethering(type);
}
/**
@@ -2682,7 +2660,7 @@ public class ConnectivityManager {
synchronized (mTetheringEventCallbacks) {
mTetheringEventCallbacks.put(callback, tetherCallback);
- getTetheringManager().registerTetheringEventCallback(executor, tetherCallback);
+ mTetheringManager.registerTetheringEventCallback(executor, tetherCallback);
}
}
@@ -2704,7 +2682,7 @@ public class ConnectivityManager {
synchronized (mTetheringEventCallbacks) {
final TetheringEventCallback tetherCallback =
mTetheringEventCallbacks.remove(callback);
- getTetheringManager().unregisterTetheringEventCallback(tetherCallback);
+ mTetheringManager.unregisterTetheringEventCallback(tetherCallback);
}
}
@@ -2724,7 +2702,7 @@ public class ConnectivityManager {
@UnsupportedAppUsage
@Deprecated
public String[] getTetherableUsbRegexs() {
- return getTetheringManager().getTetherableUsbRegexs();
+ return mTetheringManager.getTetherableUsbRegexs();
}
/**
@@ -2742,7 +2720,7 @@ public class ConnectivityManager {
@UnsupportedAppUsage
@Deprecated
public String[] getTetherableWifiRegexs() {
- return getTetheringManager().getTetherableWifiRegexs();
+ return mTetheringManager.getTetherableWifiRegexs();
}
/**
@@ -2761,7 +2739,7 @@ public class ConnectivityManager {
@UnsupportedAppUsage
@Deprecated
public String[] getTetherableBluetoothRegexs() {
- return getTetheringManager().getTetherableBluetoothRegexs();
+ return mTetheringManager.getTetherableBluetoothRegexs();
}
/**
@@ -2785,7 +2763,7 @@ public class ConnectivityManager {
@UnsupportedAppUsage
@Deprecated
public int setUsbTethering(boolean enable) {
- return getTetheringManager().setUsbTethering(enable);
+ return mTetheringManager.setUsbTethering(enable);
}
/**
@@ -2902,7 +2880,7 @@ public class ConnectivityManager {
@UnsupportedAppUsage
@Deprecated
public int getLastTetherError(String iface) {
- return getTetheringManager().getLastTetherError(iface);
+ return mTetheringManager.getLastTetherError(iface);
}
/** @hide */
@@ -2973,7 +2951,7 @@ public class ConnectivityManager {
}
};
- getTetheringManager().requestLatestTetheringEntitlementResult(type, wrappedListener,
+ mTetheringManager.requestLatestTetheringEntitlementResult(type, wrappedListener,
showEntitlementUi);
}
@@ -4469,7 +4447,7 @@ public class ConnectivityManager {
public void factoryReset() {
try {
mService.factoryReset();
- getTetheringManager().stopAllTethering();
+ mTetheringManager.stopAllTethering();
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
diff --git a/core/java/android/net/EthernetManager.java b/core/java/android/net/EthernetManager.java
index a3899b705c1b..83b5f63576f2 100644
--- a/core/java/android/net/EthernetManager.java
+++ b/core/java/android/net/EthernetManager.java
@@ -17,6 +17,7 @@
package android.net;
import android.annotation.NonNull;
+import android.annotation.RequiresPermission;
import android.annotation.SystemApi;
import android.annotation.SystemService;
import android.annotation.TestApi;
@@ -28,6 +29,7 @@ import android.os.RemoteException;
import java.util.ArrayList;
import java.util.Objects;
+import java.util.concurrent.Executor;
/**
* A class representing the IP configuration of the Ethernet network.
@@ -247,19 +249,24 @@ public class EthernetManager {
* interface, the existing interface will be used.
* @param callback A callback to be called once the request has been fulfilled.
*/
+ @RequiresPermission(anyOf = {
+ android.Manifest.permission.NETWORK_STACK,
+ android.net.NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK
+ })
@NonNull
- public TetheredInterfaceRequest requestTetheredInterface(
- @NonNull TetheredInterfaceCallback callback) {
+ public TetheredInterfaceRequest requestTetheredInterface(@NonNull final Executor executor,
+ @NonNull final TetheredInterfaceCallback callback) {
Objects.requireNonNull(callback, "Callback must be non-null");
+ Objects.requireNonNull(executor, "Executor must be non-null");
final ITetheredInterfaceCallback cbInternal = new ITetheredInterfaceCallback.Stub() {
@Override
public void onAvailable(String iface) {
- callback.onAvailable(iface);
+ executor.execute(() -> callback.onAvailable(iface));
}
@Override
public void onUnavailable() {
- callback.onUnavailable();
+ executor.execute(() -> callback.onUnavailable());
}
};
diff --git a/core/java/android/net/NetworkAgent.java b/core/java/android/net/NetworkAgent.java
index 7cc569a42b0b..fef353f604dc 100644
--- a/core/java/android/net/NetworkAgent.java
+++ b/core/java/android/net/NetworkAgent.java
@@ -126,7 +126,7 @@ public abstract class NetworkAgent {
/**
* Sent by the NetworkAgent to ConnectivityService to pass the current
* network score.
- * obj = network score Integer
+ * arg1 = network score int
* @hide
*/
public static final int EVENT_NETWORK_SCORE_CHANGED = BASE + 4;
@@ -650,18 +650,7 @@ public abstract class NetworkAgent {
if (score < 0) {
throw new IllegalArgumentException("Score must be >= 0");
}
- final NetworkScore ns = new NetworkScore();
- ns.putIntExtension(NetworkScore.LEGACY_SCORE, score);
- updateScore(ns);
- }
-
- /**
- * Must be called by the agent when it has a new {@link NetworkScore} for this network.
- * @param ns the new score.
- * @hide TODO: unhide the NetworkScore class, and rename to sendNetworkScore.
- */
- public void updateScore(@NonNull NetworkScore ns) {
- queueOrSendMessage(EVENT_NETWORK_SCORE_CHANGED, new NetworkScore(ns));
+ queueOrSendMessage(EVENT_NETWORK_SCORE_CHANGED, score, 0);
}
/**
diff --git a/core/java/android/net/NetworkScore.java b/core/java/android/net/NetworkScore.java
deleted file mode 100644
index 13f2994110a1..000000000000
--- a/core/java/android/net/NetworkScore.java
+++ /dev/null
@@ -1,162 +0,0 @@
-/*
- * Copyright (C) 2019 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package android.net;
-
-import android.annotation.NonNull;
-import android.annotation.Nullable;
-import android.os.Bundle;
-import android.os.Parcel;
-import android.os.Parcelable;
-
-import java.util.Objects;
-
-/**
- * Object representing the quality of a network as perceived by the user.
- *
- * A NetworkScore object represents the characteristics of a network that affects how good the
- * network is considered for a particular use.
- * @hide
- */
-public final class NetworkScore implements Parcelable {
-
- // The key of bundle which is used to get the legacy network score of NetworkAgentInfo.
- // TODO: Remove this when the transition to NetworkScore is over.
- public static final String LEGACY_SCORE = "LEGACY_SCORE";
- @NonNull
- private final Bundle mExtensions;
-
- public NetworkScore() {
- mExtensions = new Bundle();
- }
-
- public NetworkScore(@NonNull NetworkScore source) {
- mExtensions = new Bundle(source.mExtensions);
- }
-
- /**
- * Put the value of parcelable inside the bundle by key.
- */
- public void putExtension(@Nullable String key, @Nullable Parcelable value) {
- mExtensions.putParcelable(key, value);
- }
-
- /**
- * Put the value of int inside the bundle by key.
- */
- public void putIntExtension(@Nullable String key, int value) {
- mExtensions.putInt(key, value);
- }
-
- /**
- * Get the value of non primitive type by key.
- */
- public <T extends Parcelable> T getExtension(@Nullable String key) {
- return mExtensions.getParcelable(key);
- }
-
- /**
- * Get the value of int by key.
- */
- public int getIntExtension(@Nullable String key) {
- return mExtensions.getInt(key);
- }
-
- /**
- * Remove the entry by given key.
- */
- public void removeExtension(@Nullable String key) {
- mExtensions.remove(key);
- }
-
- @Override
- public int describeContents() {
- return 0;
- }
-
- @Override
- public void writeToParcel(@NonNull Parcel dest, int flags) {
- synchronized (this) {
- dest.writeBundle(mExtensions);
- }
- }
-
- public static final @NonNull Creator<NetworkScore> CREATOR = new Creator<NetworkScore>() {
- @Override
- public NetworkScore createFromParcel(@NonNull Parcel in) {
- return new NetworkScore(in);
- }
-
- @Override
- public NetworkScore[] newArray(int size) {
- return new NetworkScore[size];
- }
- };
-
- private NetworkScore(@NonNull Parcel in) {
- mExtensions = in.readBundle();
- }
-
- // TODO: Modify this method once new fields are added into this class.
- @Override
- public boolean equals(@Nullable Object obj) {
- if (!(obj instanceof NetworkScore)) {
- return false;
- }
- final NetworkScore other = (NetworkScore) obj;
- return bundlesEqual(mExtensions, other.mExtensions);
- }
-
- @Override
- public int hashCode() {
- int result = 29;
- for (String key : mExtensions.keySet()) {
- final Object value = mExtensions.get(key);
- // The key may be null, so call Objects.hash() is safer.
- result += 31 * value.hashCode() + 37 * Objects.hash(key);
- }
- return result;
- }
-
- // mExtensions won't be null since the constructor will create it.
- private boolean bundlesEqual(@NonNull Bundle bundle1, @NonNull Bundle bundle2) {
- if (bundle1 == bundle2) {
- return true;
- }
-
- // This is unlikely but it's fine to add this clause here.
- if (null == bundle1 || null == bundle2) {
- return false;
- }
-
- if (bundle1.size() != bundle2.size()) {
- return false;
- }
-
- for (String key : bundle1.keySet()) {
- final Object value1 = bundle1.get(key);
- final Object value2 = bundle2.get(key);
- if (!Objects.equals(value1, value2)) {
- return false;
- }
- }
- return true;
- }
-
- /** Convert to a string */
- public String toString() {
- return "NetworkScore[" + mExtensions.toString() + "]";
- }
-}
diff --git a/core/java/android/os/BatteryStatsManager.java b/core/java/android/os/BatteryStatsManager.java
index f2e16b46422f..a9585c62866b 100644
--- a/core/java/android/os/BatteryStatsManager.java
+++ b/core/java/android/os/BatteryStatsManager.java
@@ -350,12 +350,13 @@ public final class BatteryStatsManager {
/**
* Indicates that an app has acquired the wifi multicast lock.
*
- * @param uid UID of the app that acquired the wifi lock (to be used for battery blaming).
+ * @param ws Worksource with the uid of the app that acquired the wifi lock (to be used for
+ * battery blaming).
*/
@RequiresPermission(android.Manifest.permission.UPDATE_DEVICE_STATS)
- public void reportWifiMulticastEnabled(int uid) {
+ public void reportWifiMulticastEnabled(@NonNull WorkSource ws) {
try {
- mBatteryStats.noteWifiMulticastEnabled(uid);
+ mBatteryStats.noteWifiMulticastEnabled(ws.getAttributionUid());
} catch (RemoteException e) {
e.rethrowFromSystemServer();
}
@@ -364,12 +365,13 @@ public final class BatteryStatsManager {
/**
* Indicates that an app has released the wifi multicast lock.
*
- * @param uid UID of the app that released the wifi lock (to be used for battery blaming).
+ * @param ws Worksource with the uid of the app that released the wifi lock (to be used for
+ * battery blaming).
*/
@RequiresPermission(android.Manifest.permission.UPDATE_DEVICE_STATS)
- public void reportWifiMulticastDisabled(int uid) {
+ public void reportWifiMulticastDisabled(@NonNull WorkSource ws) {
try {
- mBatteryStats.noteWifiMulticastDisabled(uid);
+ mBatteryStats.noteWifiMulticastDisabled(ws.getAttributionUid());
} catch (RemoteException e) {
e.rethrowFromSystemServer();
}
diff --git a/core/java/android/os/Binder.java b/core/java/android/os/Binder.java
index fe7c7c921b67..c889ee6307d1 100644
--- a/core/java/android/os/Binder.java
+++ b/core/java/android/os/Binder.java
@@ -248,6 +248,27 @@ public class Binder implements IBinder {
}
}
+ static ThreadLocal<Boolean> sWarnOnBlockingOnCurrentThread =
+ ThreadLocal.withInitial(() -> sWarnOnBlocking);
+
+ /**
+ * Allow blocking calls for the current thread. See {@link #allowBlocking}.
+ *
+ * @hide
+ */
+ public static void allowBlockingForCurrentThread() {
+ sWarnOnBlockingOnCurrentThread.set(false);
+ }
+
+ /**
+ * Reset the current thread to the default blocking behavior. See {@link #defaultBlocking}.
+ *
+ * @hide
+ */
+ public static void defaultBlockingForCurrentThread() {
+ sWarnOnBlockingOnCurrentThread.set(sWarnOnBlocking);
+ }
+
/**
* Raw native pointer to JavaBBinderHolder object. Owned by this Java object. Not null.
*/
diff --git a/core/java/android/os/BinderProxy.java b/core/java/android/os/BinderProxy.java
index be307ab4737d..20e5f243163f 100644
--- a/core/java/android/os/BinderProxy.java
+++ b/core/java/android/os/BinderProxy.java
@@ -479,16 +479,21 @@ public final class BinderProxy implements IBinder {
public boolean transact(int code, Parcel data, Parcel reply, int flags) throws RemoteException {
Binder.checkParcel(this, code, data, "Unreasonably large binder buffer");
- if (mWarnOnBlocking && ((flags & FLAG_ONEWAY) == 0)) {
+ if (mWarnOnBlocking && ((flags & FLAG_ONEWAY) == 0)
+ && Binder.sWarnOnBlockingOnCurrentThread.get()) {
+
// For now, avoid spamming the log by disabling after we've logged
// about this interface at least once
mWarnOnBlocking = false;
+
if (Build.IS_USERDEBUG) {
// Log this as a WTF on userdebug builds.
- Log.wtf(Binder.TAG, "Outgoing transactions from this process must be FLAG_ONEWAY",
+ Log.wtf(Binder.TAG,
+ "Outgoing transactions from this process must be FLAG_ONEWAY",
new Throwable());
} else {
- Log.w(Binder.TAG, "Outgoing transactions from this process must be FLAG_ONEWAY",
+ Log.w(Binder.TAG,
+ "Outgoing transactions from this process must be FLAG_ONEWAY",
new Throwable());
}
}
@@ -521,7 +526,7 @@ public final class BinderProxy implements IBinder {
final AppOpsManager.PausedNotedAppOpsCollection prevCollection =
AppOpsManager.pauseNotedAppOpsCollection();
- if ((flags & FLAG_ONEWAY) == 0 && AppOpsManager.isCollectingNotedAppOps()) {
+ if ((flags & FLAG_ONEWAY) == 0 && AppOpsManager.isListeningForOpNoted()) {
flags |= FLAG_COLLECT_NOTED_APP_OPS;
}
diff --git a/core/java/android/os/Environment.java b/core/java/android/os/Environment.java
index 21a1e0f0a108..f2fb5b246f39 100644
--- a/core/java/android/os/Environment.java
+++ b/core/java/android/os/Environment.java
@@ -39,6 +39,7 @@ import java.util.ArrayList;
import java.util.Collection;
import java.util.LinkedList;
import java.util.List;
+import java.util.Objects;
/**
* Provides access to environment variables.
@@ -1253,6 +1254,50 @@ public class Environment {
uid, context.getOpPackageName()) == AppOpsManager.MODE_ALLOWED;
}
+ /**
+ * Returns whether the calling app has All Files Access on the primary shared/external storage
+ * media.
+ * <p>Declaring the permission {@link android.Manifest.permission#MANAGE_EXTERNAL_STORAGE} isn't
+ * enough to gain the access.
+ * <p>To request access, use
+ * {@link android.provider.Settings#ACTION_MANAGE_APP_ALL_FILES_ACCESS_PERMISSION}.
+ */
+ public static boolean isExternalStorageManager() {
+ final File externalDir = sCurrentUser.getExternalDirs()[0];
+ return isExternalStorageManager(externalDir);
+ }
+
+ /**
+ * Returns whether the calling app has All Files Access at the given {@code path}
+ * <p>Declaring the permission {@link android.Manifest.permission#MANAGE_EXTERNAL_STORAGE} isn't
+ * enough to gain the access.
+ * <p>To request access, use
+ * {@link android.provider.Settings#ACTION_MANAGE_APP_ALL_FILES_ACCESS_PERMISSION}.
+ */
+ public static boolean isExternalStorageManager(@NonNull File path) {
+ final Context context = Objects.requireNonNull(AppGlobals.getInitialApplication());
+ String packageName = Objects.requireNonNull(context.getPackageName());
+ int uid = context.getApplicationInfo().uid;
+
+ final AppOpsManager appOps = context.getSystemService(AppOpsManager.class);
+ final int opMode =
+ appOps.checkOpNoThrow(AppOpsManager.OP_MANAGE_EXTERNAL_STORAGE, uid, packageName);
+
+ switch (opMode) {
+ case AppOpsManager.MODE_DEFAULT:
+ return PackageManager.PERMISSION_GRANTED
+ == context.checkPermission(
+ Manifest.permission.MANAGE_EXTERNAL_STORAGE, Process.myPid(), uid);
+ case AppOpsManager.MODE_ALLOWED:
+ return true;
+ case AppOpsManager.MODE_ERRORED:
+ case AppOpsManager.MODE_IGNORED:
+ return false;
+ default:
+ throw new IllegalStateException("Unknown AppOpsManager mode " + opMode);
+ }
+ }
+
static File getDirectory(String variableName, String defaultPath) {
String path = System.getenv(variableName);
return path == null ? new File(defaultPath) : new File(path);
diff --git a/core/java/android/os/IPowerManager.aidl b/core/java/android/os/IPowerManager.aidl
index 1cefbd9afa80..c44a0bd11cf7 100644
--- a/core/java/android/os/IPowerManager.aidl
+++ b/core/java/android/os/IPowerManager.aidl
@@ -38,6 +38,8 @@ interface IPowerManager
void releaseWakeLock(IBinder lock, int flags);
void updateWakeLockUids(IBinder lock, in int[] uids);
oneway void powerHint(int hintId, int data);
+ oneway void setPowerBoost(int boost, int durationMs);
+ oneway void setPowerMode(int mode, boolean enabled);
void updateWakeLockWorkSource(IBinder lock, in WorkSource ws, String historyTag);
boolean isWakeLockLevelSupported(int level);
diff --git a/core/java/android/os/ParcelFileDescriptor.java b/core/java/android/os/ParcelFileDescriptor.java
index 89ddf8cbd96a..c0847872a45a 100644
--- a/core/java/android/os/ParcelFileDescriptor.java
+++ b/core/java/android/os/ParcelFileDescriptor.java
@@ -282,9 +282,7 @@ public class ParcelFileDescriptor implements Parcelable, Closeable {
* @param listener to be invoked when the returned descriptor has been
* closed.
* @return a new ParcelFileDescriptor pointing to the given file.
- * @hide
*/
- @SystemApi
// We can't accept a generic Executor here, since we need to use
// MessageQueue.addOnFileDescriptorEventListener()
@SuppressLint("ExecutorRegistration")
diff --git a/core/java/android/os/PowerManagerInternal.java b/core/java/android/os/PowerManagerInternal.java
index 9661a08464dd..51f01cac8138 100644
--- a/core/java/android/os/PowerManagerInternal.java
+++ b/core/java/android/os/PowerManagerInternal.java
@@ -201,6 +201,119 @@ public abstract class PowerManagerInternal {
*/
public abstract void powerHint(int hintId, int data);
+ /**
+ * Boost: It is sent when user interacting with the device, for example,
+ * touchscreen events are incoming.
+ * Defined in hardware/interfaces/power/aidl/android/hardware/power/Boost.aidl
+ */
+ public static final int BOOST_INTERACTION = 0;
+
+ /**
+ * Boost: It indicates that the framework is likely to provide a new display
+ * frame soon. This implies that the device should ensure that the display
+ * processing path is powered up and ready to receive that update.
+ * Defined in hardware/interfaces/power/aidl/android/hardware/power/Boost.aidl
+ */
+ public static final int BOOST_DISPLAY_UPDATE_IMMINENT = 1;
+
+ /**
+ * SetPowerBoost() indicates the device may need to boost some resources, as
+ * the load is likely to increase before the kernel governors can react.
+ * Depending on the boost, it may be appropriate to raise the frequencies of
+ * CPU, GPU, memory subsystem, or stop CPU from going into deep sleep state.
+ *
+ * @param boost Boost which is to be set with a timeout.
+ * @param durationMs The expected duration of the user's interaction, if
+ * known, or 0 if the expected duration is unknown.
+ * a negative value indicates canceling previous boost.
+ * A given platform can choose to boost some time based on durationMs,
+ * and may also pick an appropriate timeout for 0 case.
+ */
+ public abstract void setPowerBoost(int boost, int durationMs);
+
+ /**
+ * Mode: It indicates that the device is to allow wake up when the screen
+ * is tapped twice.
+ * Defined in hardware/interfaces/power/aidl/android/hardware/power/Mode.aidl
+ */
+ public static final int MODE_DOUBLE_TAP_TO_WAKE = 0;
+
+ /**
+ * Mode: It indicates Low power mode is activated or not. Low power mode
+ * is intended to save battery at the cost of performance.
+ * Defined in hardware/interfaces/power/aidl/android/hardware/power/Mode.aidl
+ */
+ public static final int MODE_LOW_POWER = 1;
+
+ /**
+ * Mode: It indicates Sustained Performance mode is activated or not.
+ * Sustained performance mode is intended to provide a consistent level of
+ * performance for a prolonged amount of time.
+ * Defined in hardware/interfaces/power/aidl/android/hardware/power/Mode.aidl
+ */
+ public static final int MODE_SUSTAINED_PERFORMANCE = 2;
+
+ /**
+ * Mode: It sets the device to a fixed performance level which can be sustained
+ * under normal indoor conditions for at least 10 minutes.
+ * Fixed performance mode puts both upper and lower bounds on performance such
+ * that any workload run while in a fixed performance mode should complete in
+ * a repeatable amount of time.
+ * Defined in hardware/interfaces/power/aidl/android/hardware/power/Mode.aidl
+ */
+ public static final int MODE_FIXED_PERFORMANCE = 3;
+
+ /**
+ * Mode: It indicates VR Mode is activated or not. VR mode is intended to
+ * provide minimum guarantee for performance for the amount of time the device
+ * can sustain it.
+ * Defined in hardware/interfaces/power/aidl/android/hardware/power/Mode.aidl
+ */
+ public static final int MODE_VR = 4;
+
+ /**
+ * Mode: It indicates that an application has been launched.
+ * Defined in hardware/interfaces/power/aidl/android/hardware/power/Mode.aidl
+ */
+ public static final int MODE_LAUNCH = 5;
+
+ /**
+ * Mode: It indicates that the device is about to enter a period of expensive
+ * rendering.
+ * Defined in hardware/interfaces/power/aidl/android/hardware/power/Mode.aidl
+ */
+ public static final int MODE_EXPENSIVE_RENDERING = 6;
+
+ /**
+ * Mode: It indicates that the device is about entering/leaving interactive
+ * state or on-interactive state.
+ * Defined in hardware/interfaces/power/aidl/android/hardware/power/Mode.aidl
+ */
+ public static final int MODE_INTERACTIVE = 7;
+
+ /**
+ * Mode: It indicates the device is in device idle, externally known as doze.
+ * Defined in hardware/interfaces/power/aidl/android/hardware/power/Mode.aidl
+ */
+ public static final int MODE_DEVICE_IDLE = 8;
+
+ /**
+ * Mode: It indicates that display is either off or still on but is optimized
+ * for low power.
+ * Defined in hardware/interfaces/power/aidl/android/hardware/power/Mode.aidl
+ */
+ public static final int MODE_DISPLAY_INACTIVE = 9;
+
+ /**
+ * SetPowerMode() is called to enable/disable specific hint mode, which
+ * may result in adjustment of power/performance parameters of the
+ * cpufreq governor and other controls on device side.
+ *
+ * @param mode Mode which is to be enable/disable.
+ * @param enabled true to enable, false to disable the mode.
+ */
+ public abstract void setPowerMode(int mode, boolean enabled);
+
/** Returns whether there hasn't been a user activity event for the given number of ms. */
public abstract boolean wasDeviceIdleFor(long ms);
diff --git a/core/java/android/os/UpdateEngine.java b/core/java/android/os/UpdateEngine.java
index 223f92054f79..de274c082c80 100644
--- a/core/java/android/os/UpdateEngine.java
+++ b/core/java/android/os/UpdateEngine.java
@@ -559,6 +559,37 @@ public class UpdateEngine {
}
}
+ private static class CleanupAppliedPayloadCallback extends IUpdateEngineCallback.Stub {
+ private int mErrorCode = ErrorCodeConstants.ERROR;
+ private boolean mCompleted = false;
+ private Object mLock = new Object();
+ private int getResult() {
+ synchronized (mLock) {
+ while (!mCompleted) {
+ try {
+ mLock.wait();
+ } catch (InterruptedException ex) {
+ // do nothing, just wait again.
+ }
+ }
+ return mErrorCode;
+ }
+ }
+
+ @Override
+ public void onStatusUpdate(int status, float percent) {
+ }
+
+ @Override
+ public void onPayloadApplicationComplete(int errorCode) {
+ synchronized (mLock) {
+ mErrorCode = errorCode;
+ mCompleted = true;
+ mLock.notifyAll();
+ }
+ }
+ }
+
/**
* Cleanup files used by the previous update and free up space after the
* device has been booted successfully into the new build.
@@ -590,8 +621,10 @@ public class UpdateEngine {
@WorkerThread
@ErrorCode
public int cleanupAppliedPayload() {
+ CleanupAppliedPayloadCallback callback = new CleanupAppliedPayloadCallback();
try {
- return mUpdateEngine.cleanupSuccessfulUpdate();
+ mUpdateEngine.cleanupSuccessfulUpdate(callback);
+ return callback.getResult();
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
diff --git a/core/java/android/os/connectivity/WifiBatteryStats.java b/core/java/android/os/connectivity/WifiBatteryStats.java
index 3c30f6343405..7e6ebcfc61db 100644
--- a/core/java/android/os/connectivity/WifiBatteryStats.java
+++ b/core/java/android/os/connectivity/WifiBatteryStats.java
@@ -215,7 +215,7 @@ public final class WifiBatteryStats implements Parcelable {
* Returns the number of bytes transmitted over wifi within
* {@link #getLoggingDurationMillis()}.
*
- * @return Number of packets received.
+ * @return Number of bytes transmitted.
*/
public long getNumBytesTx() {
return mNumBytesTx;
@@ -225,7 +225,7 @@ public final class WifiBatteryStats implements Parcelable {
* Returns the number of packets received over wifi within
* {@link #getLoggingDurationMillis()}.
*
- * @return Number of bytes transmitted.
+ * @return Number of packets received.
*/
public long getNumPacketsRx() {
return mNumPacketsRx;
diff --git a/core/java/android/os/incremental/IIncrementalManager.aidl b/core/java/android/os/incremental/IIncrementalManager.aidl
deleted file mode 100644
index be83aaedd773..000000000000
--- a/core/java/android/os/incremental/IIncrementalManager.aidl
+++ /dev/null
@@ -1,36 +0,0 @@
-/*
- * Copyright (C) 2019 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.os.incremental;
-
-import android.content.pm.FileSystemControlParcel;
-import android.content.pm.DataLoaderParamsParcel;
-import android.content.pm.IDataLoaderStatusListener;
-
-/**
- * Binder service to receive calls from native Incremental Service and handle Java tasks such as
- * looking up data loader service package names, binding and talking to the data loader service.
- * @hide
- */
-interface IIncrementalManager {
- boolean prepareDataLoader(int mountId,
- in FileSystemControlParcel control,
- in DataLoaderParamsParcel params,
- in IDataLoaderStatusListener listener);
- boolean startDataLoader(int mountId);
- void showHealthBlockedUI(int mountId);
- void destroyDataLoader(int mountId);
-}
diff --git a/core/java/android/permission/PermissionControllerService.java b/core/java/android/permission/PermissionControllerService.java
index 5d4561c21e55..263b2c7a4ac7 100644
--- a/core/java/android/permission/PermissionControllerService.java
+++ b/core/java/android/permission/PermissionControllerService.java
@@ -202,7 +202,8 @@ public abstract class PermissionControllerService extends Service {
/**
* Grant or upgrade runtime permissions. The upgrade could be performed
* based on whether the device upgraded, whether the permission database
- * version is old, or because the permission policy changed.
+ * version is old, because the permission policy changed, or because the
+ * permission controller has updated.
*
* @param callback Callback waiting for operation to be complete
*
diff --git a/core/java/android/provider/DeviceConfig.java b/core/java/android/provider/DeviceConfig.java
index 505d4ca4b399..aa511cc46de9 100644
--- a/core/java/android/provider/DeviceConfig.java
+++ b/core/java/android/provider/DeviceConfig.java
@@ -111,6 +111,14 @@ public final class DeviceConfig {
public static final String NAMESPACE_AUTOFILL = "autofill";
/**
+ * Namespace for blobstore feature that allows apps to share data blobs.
+ *
+ * @hide
+ */
+ @SystemApi
+ public static final String NAMESPACE_BLOBSTORE = "blobstore";
+
+ /**
* Namespace for all networking connectivity related features.
*
* @hide
diff --git a/core/java/android/provider/DocumentsContract.java b/core/java/android/provider/DocumentsContract.java
index 47f24615d60a..a10a456bd6a6 100644
--- a/core/java/android/provider/DocumentsContract.java
+++ b/core/java/android/provider/DocumentsContract.java
@@ -22,6 +22,7 @@ import static com.android.internal.util.Preconditions.checkCollectionNotEmpty;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.annotation.SystemApi;
+import android.annotation.TestApi;
import android.compat.annotation.UnsupportedAppUsage;
import android.content.ContentInterface;
import android.content.ContentProvider;
@@ -1303,6 +1304,7 @@ public final class DocumentsContract {
* {@hide}
*/
@SystemApi
+ @TestApi
public static @NonNull Uri setManageMode(@NonNull Uri uri) {
Preconditions.checkNotNull(uri, "uri can not be null");
return uri.buildUpon().appendQueryParameter(PARAM_MANAGE, "true").build();
@@ -1314,6 +1316,7 @@ public final class DocumentsContract {
* {@hide}
*/
@SystemApi
+ @TestApi
public static boolean isManageMode(@NonNull Uri uri) {
Preconditions.checkNotNull(uri, "uri can not be null");
return uri.getBooleanQueryParameter(PARAM_MANAGE, false);
diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java
index 4216cf387380..641de4a71142 100644
--- a/core/java/android/provider/Settings.java
+++ b/core/java/android/provider/Settings.java
@@ -703,13 +703,18 @@ public final class Settings {
* Weak or above, as defined by the CDD. Only biometrics that meet or exceed Strong, as defined
* in the CDD are allowed to participate in Keystore operations.
* <p>
- * Input: extras {@link #EXTRA_BIOMETRIC_MINIMUM_STRENGTH_REQUIRED} as an integer, with
+ * Input: extras {@link #EXTRA_BIOMETRIC_AUTHENTICATORS_ALLOWED} as an integer, with
* constants defined in {@link android.hardware.biometrics.BiometricManager.Authenticators},
* e.g. {@link android.hardware.biometrics.BiometricManager.Authenticators#BIOMETRIC_STRONG}.
* If not specified, the default behavior is
* {@link android.hardware.biometrics.BiometricManager.Authenticators#BIOMETRIC_WEAK}.
* <p>
- * Output: Nothing.
+ * Output: Returns {@link android.app.Activity#RESULT_CANCELED} if the user already has an
+ * authenticator that meets the requirements, or if the device cannot fulfill the request
+ * (e.g. does not have biometric hardware). Returns {@link android.app.Activity#RESULT_OK}
+ * otherwise. Note that callers should still check
+ * {@link android.hardware.biometrics.BiometricManager#canAuthenticate(int)}
+ * afterwards to ensure that the user actually completed enrollment.
*/
@SdkConstant(SdkConstantType.ACTIVITY_INTENT_ACTION)
public static final String ACTION_BIOMETRIC_ENROLL =
@@ -719,12 +724,12 @@ public final class Settings {
* Activity Extra: The minimum strength to request enrollment for.
* <p>
* This can be passed as an extra field to the {@link #ACTION_BIOMETRIC_ENROLL} intent to
- * indicate that only enrollment for sensors that meet this strength should be shown. The
- * value should be one of the biometric strength constants defined in
+ * indicate that only enrollment for sensors that meet these requirements should be shown. The
+ * value should be a combination of the constants defined in
* {@link android.hardware.biometrics.BiometricManager.Authenticators}.
*/
- public static final String EXTRA_BIOMETRIC_MINIMUM_STRENGTH_REQUIRED =
- "android.provider.extra.BIOMETRIC_MINIMUM_STRENGTH_REQUIRED";
+ public static final String EXTRA_BIOMETRIC_AUTHENTICATORS_ALLOWED =
+ "android.provider.extra.BIOMETRIC_AUTHENTICATORS_ALLOWED";
/**
* Activity Action: Show settings to allow configuration of cast endpoints.
@@ -6608,6 +6613,18 @@ public final class Settings {
"accessibility_button_target_component";
/**
+ * Setting specifying the accessibility services, accessibility shortcut targets,
+ * or features to be toggled via the long press accessibility button in the navigation bar.
+ *
+ * <p> This is a colon-separated string list which contains the flattened
+ * {@link ComponentName} and the class name of a system class implementing a supported
+ * accessibility feature.
+ * @hide
+ */
+ public static final String ACCESSIBILITY_BUTTON_LONG_PRESS_TARGETS =
+ "accessibility_button_long_press_targets";
+
+ /**
* The system class name of magnification controller which is a target to be toggled via
* accessibility shortcut or accessibility button.
*
diff --git a/core/java/android/provider/Telephony.java b/core/java/android/provider/Telephony.java
index 97f7533c3209..629dc8b53265 100644
--- a/core/java/android/provider/Telephony.java
+++ b/core/java/android/provider/Telephony.java
@@ -25,6 +25,7 @@ import android.annotation.SdkConstant.SdkConstantType;
import android.annotation.SystemApi;
import android.annotation.TestApi;
import android.compat.annotation.ChangeId;
+import android.compat.annotation.EnabledAfter;
import android.compat.annotation.UnsupportedAppUsage;
import android.content.ComponentName;
import android.content.ContentResolver;
@@ -4036,6 +4037,7 @@ public final class Telephony {
* @hide
*/
@ChangeId
+ @EnabledAfter(targetSdkVersion = android.os.Build.VERSION_CODES.Q)
public static final long APN_READING_PERMISSION_CHANGE_ID = 124107808L;
}
diff --git a/core/java/android/service/autofill/FillResponse.java b/core/java/android/service/autofill/FillResponse.java
index e8e1223a29d0..06b5fa07a554 100644
--- a/core/java/android/service/autofill/FillResponse.java
+++ b/core/java/android/service/autofill/FillResponse.java
@@ -89,7 +89,7 @@ public final class FillResponse implements Parcelable {
private final @Nullable int[] mCancelIds;
private final boolean mSupportsInlineSuggestions;
// TODO(b/149240554): revert back to use ParceledListSlice after the bug is resolved.
- private final @Nullable ArrayList<InlinePresentation> mInlineActions;
+ private final @Nullable ArrayList<InlineAction> mInlineActions;
private FillResponse(@NonNull Builder builder) {
mDatasets = (builder.mDatasets != null) ? new ParceledListSlice<>(builder.mDatasets) : null;
@@ -213,7 +213,7 @@ public final class FillResponse implements Parcelable {
}
/** @hide */
- public @Nullable List<InlinePresentation> getInlineActions() {
+ public @Nullable List<InlineAction> getInlineActions() {
return mInlineActions;
}
@@ -239,7 +239,7 @@ public final class FillResponse implements Parcelable {
private UserData mUserData;
private int[] mCancelIds;
private boolean mSupportsInlineSuggestions;
- private ArrayList<InlinePresentation> mInlineActions;
+ private ArrayList<InlineAction> mInlineActions;
/**
* Triggers a custom UI before before autofilling the screen with any data set in this
@@ -656,15 +656,12 @@ public final class FillResponse implements Parcelable {
}
/**
- * Adds a new {@link InlinePresentation} to this response representing an action UI.
- *
- * <p> For example, the UI can be associated with an intent which can open an activity for
- * the user to manage the Autofill provider settings.
+ * Adds a new {@link InlineAction} to this response representing an action UI.
*
* @return This builder.
*/
@NonNull
- public Builder addInlineAction(@NonNull InlinePresentation inlineAction) {
+ public Builder addInlineAction(@NonNull InlineAction inlineAction) {
throwIfDestroyed();
throwIfAuthenticationCalled();
if (mInlineActions == null) {
@@ -881,10 +878,10 @@ public final class FillResponse implements Parcelable {
final int[] cancelIds = parcel.createIntArray();
builder.setPresentationCancelIds(cancelIds);
- final List<InlinePresentation> inlineActions = parcel.createTypedArrayList(
- InlinePresentation.CREATOR);
+ final List<InlineAction> inlineActions = parcel.createTypedArrayList(
+ InlineAction.CREATOR);
if (inlineActions != null) {
- for (InlinePresentation inlineAction : inlineActions) {
+ for (InlineAction inlineAction : inlineActions) {
builder.addInlineAction(inlineAction);
}
}
diff --git a/core/java/android/service/autofill/InlineAction.aidl b/core/java/android/service/autofill/InlineAction.aidl
new file mode 100644
index 000000000000..7f8511825d73
--- /dev/null
+++ b/core/java/android/service/autofill/InlineAction.aidl
@@ -0,0 +1,19 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.service.autofill;
+
+parcelable InlineAction;
diff --git a/core/java/android/service/autofill/InlineAction.java b/core/java/android/service/autofill/InlineAction.java
new file mode 100644
index 000000000000..17c4b33ba96b
--- /dev/null
+++ b/core/java/android/service/autofill/InlineAction.java
@@ -0,0 +1,205 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.service.autofill;
+
+import android.annotation.NonNull;
+import android.content.IntentSender;
+import android.os.Parcelable;
+
+import com.android.internal.util.DataClass;
+
+/**
+ * Represents an inline action as part of the autofill/augmented autofill response.
+ *
+ * <p> It includes both the action intent and the UI presentation. For example, the UI can be
+ * associated with an intent which can open an activity for the user to manage the Autofill provider
+ * settings.
+ */
+@DataClass(
+ genToString = true,
+ genHiddenConstDefs = true,
+ genEqualsHashCode = true)
+public final class InlineAction implements Parcelable {
+
+ /**
+ * Representation of the inline action.
+ */
+ private final @NonNull InlinePresentation mInlinePresentation;
+
+ /**
+ * The associated intent which will be triggered when the action is selected. It will only be
+ * called by the OS.
+ */
+ private final @NonNull IntentSender mAction;
+
+
+
+ // Code below generated by codegen v1.0.15.
+ //
+ // DO NOT MODIFY!
+ // CHECKSTYLE:OFF Generated code
+ //
+ // To regenerate run:
+ // $ codegen $ANDROID_BUILD_TOP/frameworks/base/core/java/android/service/autofill/InlineAction.java
+ //
+ // To exclude the generated code from IntelliJ auto-formatting enable (one-time):
+ // Settings > Editor > Code Style > Formatter Control
+ //@formatter:off
+
+
+ /**
+ * Creates a new InlineAction.
+ *
+ * @param inlinePresentation
+ * Representation of the inline action.
+ * @param action
+ * The associated intent which will be triggered when the action is selected. It will only be
+ * invoked by the OS.
+ */
+ @DataClass.Generated.Member
+ public InlineAction(
+ @NonNull InlinePresentation inlinePresentation,
+ @NonNull IntentSender action) {
+ this.mInlinePresentation = inlinePresentation;
+ com.android.internal.util.AnnotationValidations.validate(
+ NonNull.class, null, mInlinePresentation);
+ this.mAction = action;
+ com.android.internal.util.AnnotationValidations.validate(
+ NonNull.class, null, mAction);
+
+ // onConstructed(); // You can define this method to get a callback
+ }
+
+ /**
+ * Representation of the inline action.
+ */
+ @DataClass.Generated.Member
+ public @NonNull InlinePresentation getInlinePresentation() {
+ return mInlinePresentation;
+ }
+
+ /**
+ * The associated intent which will be triggered when the action is selected. It will only be
+ * invoked by the OS.
+ */
+ @DataClass.Generated.Member
+ public @NonNull IntentSender getAction() {
+ return mAction;
+ }
+
+ @Override
+ @DataClass.Generated.Member
+ public String toString() {
+ // You can override field toString logic by defining methods like:
+ // String fieldNameToString() { ... }
+
+ return "InlineAction { " +
+ "inlinePresentation = " + mInlinePresentation + ", " +
+ "action = " + mAction +
+ " }";
+ }
+
+ @Override
+ @DataClass.Generated.Member
+ public boolean equals(@android.annotation.Nullable Object o) {
+ // You can override field equality logic by defining either of the methods like:
+ // boolean fieldNameEquals(InlineAction other) { ... }
+ // boolean fieldNameEquals(FieldType otherValue) { ... }
+
+ if (this == o) return true;
+ if (o == null || getClass() != o.getClass()) return false;
+ @SuppressWarnings("unchecked")
+ InlineAction that = (InlineAction) o;
+ //noinspection PointlessBooleanExpression
+ return true
+ && java.util.Objects.equals(mInlinePresentation, that.mInlinePresentation)
+ && java.util.Objects.equals(mAction, that.mAction);
+ }
+
+ @Override
+ @DataClass.Generated.Member
+ public int hashCode() {
+ // You can override field hashCode logic by defining methods like:
+ // int fieldNameHashCode() { ... }
+
+ int _hash = 1;
+ _hash = 31 * _hash + java.util.Objects.hashCode(mInlinePresentation);
+ _hash = 31 * _hash + java.util.Objects.hashCode(mAction);
+ return _hash;
+ }
+
+ @Override
+ @DataClass.Generated.Member
+ public void writeToParcel(@NonNull android.os.Parcel dest, int flags) {
+ // You can override field parcelling by defining methods like:
+ // void parcelFieldName(Parcel dest, int flags) { ... }
+
+ dest.writeTypedObject(mInlinePresentation, flags);
+ dest.writeTypedObject(mAction, flags);
+ }
+
+ @Override
+ @DataClass.Generated.Member
+ public int describeContents() { return 0; }
+
+ /** @hide */
+ @SuppressWarnings({"unchecked", "RedundantCast"})
+ @DataClass.Generated.Member
+ /* package-private */ InlineAction(@NonNull android.os.Parcel in) {
+ // You can override field unparcelling by defining methods like:
+ // static FieldType unparcelFieldName(Parcel in) { ... }
+
+ InlinePresentation inlinePresentation = (InlinePresentation) in.readTypedObject(InlinePresentation.CREATOR);
+ IntentSender action = (IntentSender) in.readTypedObject(IntentSender.CREATOR);
+
+ this.mInlinePresentation = inlinePresentation;
+ com.android.internal.util.AnnotationValidations.validate(
+ NonNull.class, null, mInlinePresentation);
+ this.mAction = action;
+ com.android.internal.util.AnnotationValidations.validate(
+ NonNull.class, null, mAction);
+
+ // onConstructed(); // You can define this method to get a callback
+ }
+
+ @DataClass.Generated.Member
+ public static final @NonNull Parcelable.Creator<InlineAction> CREATOR
+ = new Parcelable.Creator<InlineAction>() {
+ @Override
+ public InlineAction[] newArray(int size) {
+ return new InlineAction[size];
+ }
+
+ @Override
+ public InlineAction createFromParcel(@NonNull android.os.Parcel in) {
+ return new InlineAction(in);
+ }
+ };
+
+ @DataClass.Generated(
+ time = 1583798182424L,
+ codegenVersion = "1.0.15",
+ sourceFile = "frameworks/base/core/java/android/service/autofill/InlineAction.java",
+ inputSignatures = "private final @android.annotation.NonNull android.service.autofill.InlinePresentation mInlinePresentation\nprivate final @android.annotation.NonNull android.content.IntentSender mAction\nclass InlineAction extends java.lang.Object implements [android.os.Parcelable]\n@com.android.internal.util.DataClass(genToString=true, genHiddenConstDefs=true, genEqualsHashCode=true)")
+ @Deprecated
+ private void __metadata() {}
+
+
+ //@formatter:on
+ // End of generated code
+
+}
diff --git a/core/java/android/service/autofill/augmented/AugmentedAutofillService.java b/core/java/android/service/autofill/augmented/AugmentedAutofillService.java
index fe792b1efd9f..ed27dd568823 100644
--- a/core/java/android/service/autofill/augmented/AugmentedAutofillService.java
+++ b/core/java/android/service/autofill/augmented/AugmentedAutofillService.java
@@ -40,7 +40,7 @@ import android.os.RemoteException;
import android.os.SystemClock;
import android.service.autofill.Dataset;
import android.service.autofill.FillEventHistory;
-import android.service.autofill.InlinePresentation;
+import android.service.autofill.InlineAction;
import android.service.autofill.augmented.PresentationParams.SystemPopupPresentationParams;
import android.util.Log;
import android.util.Pair;
@@ -559,7 +559,7 @@ public abstract class AugmentedAutofillService extends Service {
}
void reportResult(@Nullable List<Dataset> inlineSuggestionsData,
- @Nullable List<InlinePresentation> inlineActions) {
+ @Nullable List<InlineAction> inlineActions) {
try {
mCallback.onSuccess(inlineSuggestionsData, inlineActions);
} catch (RemoteException e) {
diff --git a/core/java/android/service/autofill/augmented/FillResponse.java b/core/java/android/service/autofill/augmented/FillResponse.java
index b7fdf5ab337f..f564b3ba616a 100644
--- a/core/java/android/service/autofill/augmented/FillResponse.java
+++ b/core/java/android/service/autofill/augmented/FillResponse.java
@@ -21,7 +21,7 @@ import android.annotation.SystemApi;
import android.annotation.TestApi;
import android.os.Bundle;
import android.service.autofill.Dataset;
-import android.service.autofill.InlinePresentation;
+import android.service.autofill.InlineAction;
import com.android.internal.util.DataClass;
@@ -53,11 +53,10 @@ public final class FillResponse {
private @Nullable List<Dataset> mInlineSuggestions;
/**
- * The {@link InlinePresentation}s representing the inline actions. Defaults to null if no
- * inline actions are provided.
+ * Defaults to null if no inline actions are provided.
*/
@DataClass.PluralOf("inlineAction")
- private @Nullable List<InlinePresentation> mInlineActions;
+ private @Nullable List<InlineAction> mInlineActions;
/**
* The client state that {@link AugmentedAutofillService} implementation can put anything in to
@@ -74,7 +73,7 @@ public final class FillResponse {
return null;
}
- private static List<InlinePresentation> defaultInlineActions() {
+ private static List<InlineAction> defaultInlineActions() {
return null;
}
@@ -86,12 +85,12 @@ public final class FillResponse {
/** @hide */
abstract static class BaseBuilder {
abstract FillResponse.Builder addInlineSuggestion(@NonNull Dataset value);
- abstract FillResponse.Builder addInlineAction(@NonNull InlinePresentation value);
+ abstract FillResponse.Builder addInlineAction(@NonNull InlineAction value);
}
- // Code below generated by codegen v1.0.14.
+ // Code below generated by codegen v1.0.15.
//
// DO NOT MODIFY!
// CHECKSTYLE:OFF Generated code
@@ -108,7 +107,7 @@ public final class FillResponse {
/* package-private */ FillResponse(
@Nullable FillWindow fillWindow,
@Nullable List<Dataset> inlineSuggestions,
- @Nullable List<InlinePresentation> inlineActions,
+ @Nullable List<InlineAction> inlineActions,
@Nullable Bundle clientState) {
this.mFillWindow = fillWindow;
this.mInlineSuggestions = inlineSuggestions;
@@ -140,13 +139,12 @@ public final class FillResponse {
}
/**
- * The {@link InlinePresentation}s representing the inline actions. Defaults to null if no
- * inline actions are provided.
+ * Defaults to null if no inline actions are provided.
*
* @hide
*/
@DataClass.Generated.Member
- public @Nullable List<InlinePresentation> getInlineActions() {
+ public @Nullable List<InlineAction> getInlineActions() {
return mInlineActions;
}
@@ -171,7 +169,7 @@ public final class FillResponse {
private @Nullable FillWindow mFillWindow;
private @Nullable List<Dataset> mInlineSuggestions;
- private @Nullable List<InlinePresentation> mInlineActions;
+ private @Nullable List<InlineAction> mInlineActions;
private @Nullable Bundle mClientState;
private long mBuilderFieldsSet = 0L;
@@ -183,7 +181,7 @@ public final class FillResponse {
* The {@link FillWindow} used to display the Autofill UI.
*/
@DataClass.Generated.Member
- public @NonNull Builder setFillWindow(@Nullable FillWindow value) {
+ public @NonNull Builder setFillWindow(@NonNull FillWindow value) {
checkNotUsed();
mBuilderFieldsSet |= 0x1;
mFillWindow = value;
@@ -195,7 +193,7 @@ public final class FillResponse {
* inline suggestions are available from the service.
*/
@DataClass.Generated.Member
- public @NonNull Builder setInlineSuggestions(@Nullable List<Dataset> value) {
+ public @NonNull Builder setInlineSuggestions(@NonNull List<Dataset> value) {
checkNotUsed();
mBuilderFieldsSet |= 0x2;
mInlineSuggestions = value;
@@ -212,11 +210,10 @@ public final class FillResponse {
}
/**
- * The {@link InlinePresentation}s representing the inline actions. Defaults to null if no
- * inline actions are provided.
+ * Defaults to null if no inline actions are provided.
*/
@DataClass.Generated.Member
- public @NonNull Builder setInlineActions(@Nullable List<InlinePresentation> value) {
+ public @NonNull Builder setInlineActions(@NonNull List<InlineAction> value) {
checkNotUsed();
mBuilderFieldsSet |= 0x4;
mInlineActions = value;
@@ -226,7 +223,7 @@ public final class FillResponse {
/** @see #setInlineActions */
@DataClass.Generated.Member
@Override
- @NonNull FillResponse.Builder addInlineAction(@NonNull InlinePresentation value) {
+ @NonNull FillResponse.Builder addInlineAction(@NonNull InlineAction value) {
if (mInlineActions == null) setInlineActions(new ArrayList<>());
mInlineActions.add(value);
return this;
@@ -238,7 +235,7 @@ public final class FillResponse {
* {@link AugmentedAutofillService#getFillEventHistory()}.
*/
@DataClass.Generated.Member
- public @NonNull Builder setClientState(@Nullable Bundle value) {
+ public @NonNull Builder setClientState(@NonNull Bundle value) {
checkNotUsed();
mBuilderFieldsSet |= 0x8;
mClientState = value;
@@ -279,10 +276,10 @@ public final class FillResponse {
}
@DataClass.Generated(
- time = 1582682935951L,
- codegenVersion = "1.0.14",
+ time = 1583793032373L,
+ codegenVersion = "1.0.15",
sourceFile = "frameworks/base/core/java/android/service/autofill/augmented/FillResponse.java",
- inputSignatures = "private @android.annotation.Nullable android.service.autofill.augmented.FillWindow mFillWindow\nprivate @com.android.internal.util.DataClass.PluralOf(\"inlineSuggestion\") @android.annotation.Nullable java.util.List<android.service.autofill.Dataset> mInlineSuggestions\nprivate @com.android.internal.util.DataClass.PluralOf(\"inlineAction\") @android.annotation.Nullable java.util.List<android.service.autofill.InlinePresentation> mInlineActions\nprivate @android.annotation.Nullable android.os.Bundle mClientState\nprivate static android.service.autofill.augmented.FillWindow defaultFillWindow()\nprivate static java.util.List<android.service.autofill.Dataset> defaultInlineSuggestions()\nprivate static java.util.List<android.service.autofill.InlinePresentation> defaultInlineActions()\nprivate static android.os.Bundle defaultClientState()\nclass FillResponse extends java.lang.Object implements []\n@com.android.internal.util.DataClass(genBuilder=true, genHiddenGetters=true)\nabstract android.service.autofill.augmented.FillResponse.Builder addInlineSuggestion(android.service.autofill.Dataset)\nabstract android.service.autofill.augmented.FillResponse.Builder addInlineAction(android.service.autofill.InlinePresentation)\nclass BaseBuilder extends java.lang.Object implements []")
+ inputSignatures = "private @android.annotation.Nullable android.service.autofill.augmented.FillWindow mFillWindow\nprivate @com.android.internal.util.DataClass.PluralOf(\"inlineSuggestion\") @android.annotation.Nullable java.util.List<android.service.autofill.Dataset> mInlineSuggestions\nprivate @com.android.internal.util.DataClass.PluralOf(\"inlineAction\") @android.annotation.Nullable java.util.List<android.service.autofill.InlineAction> mInlineActions\nprivate @android.annotation.Nullable android.os.Bundle mClientState\nprivate static android.service.autofill.augmented.FillWindow defaultFillWindow()\nprivate static java.util.List<android.service.autofill.Dataset> defaultInlineSuggestions()\nprivate static java.util.List<android.service.autofill.InlineAction> defaultInlineActions()\nprivate static android.os.Bundle defaultClientState()\nclass FillResponse extends java.lang.Object implements []\n@com.android.internal.util.DataClass(genBuilder=true, genHiddenGetters=true)\nabstract android.service.autofill.augmented.FillResponse.Builder addInlineSuggestion(android.service.autofill.Dataset)\nabstract android.service.autofill.augmented.FillResponse.Builder addInlineAction(android.service.autofill.InlineAction)\nclass BaseBuilder extends java.lang.Object implements []")
@Deprecated
private void __metadata() {}
diff --git a/core/java/android/service/autofill/augmented/IFillCallback.aidl b/core/java/android/service/autofill/augmented/IFillCallback.aidl
index bf0adcd54ab1..545dab284067 100644
--- a/core/java/android/service/autofill/augmented/IFillCallback.aidl
+++ b/core/java/android/service/autofill/augmented/IFillCallback.aidl
@@ -20,7 +20,7 @@ import android.os.Bundle;
import android.os.ICancellationSignal;
import android.service.autofill.Dataset;
-import android.service.autofill.InlinePresentation;
+import android.service.autofill.InlineAction;
import java.util.List;
@@ -32,7 +32,7 @@ import java.util.List;
interface IFillCallback {
void onCancellable(in ICancellationSignal cancellation);
void onSuccess(in @nullable List<Dataset> inlineSuggestionsData,
- in @nullable List<InlinePresentation> inlineActions);
+ in @nullable List<InlineAction> inlineActions);
boolean isCompleted();
void cancel();
}
diff --git a/core/java/android/service/contentcapture/DataShareReadAdapter.java b/core/java/android/service/contentcapture/DataShareReadAdapter.java
index a481ec8382ed..8cd9eea1e6e0 100644
--- a/core/java/android/service/contentcapture/DataShareReadAdapter.java
+++ b/core/java/android/service/contentcapture/DataShareReadAdapter.java
@@ -20,6 +20,7 @@ import android.annotation.NonNull;
import android.annotation.SystemApi;
import android.annotation.TestApi;
import android.os.ParcelFileDescriptor;
+import android.view.contentcapture.ContentCaptureManager.DataShareError;
/**
* Adapter class to be used for the Content Capture Service app to propagate the status of the
@@ -46,5 +47,5 @@ public interface DataShareReadAdapter {
* these 2 events is not defined, and it's important that the service treats end of stream
* correctly in this situation.
**/
- void onError(int errorCode);
+ void onError(@DataShareError int errorCode);
}
diff --git a/core/java/android/service/controls/Control.java b/core/java/android/service/controls/Control.java
index dabd9773ec92..d01bc2524332 100644
--- a/core/java/android/service/controls/Control.java
+++ b/core/java/android/service/controls/Control.java
@@ -395,7 +395,7 @@ public final class Control implements Parcelable {
* {@link ControlsProviderService#createPublisherForAllAvailable}:
* <ul>
* <li> Status: {@link Status#STATUS_UNKNOWN}
- * <li> Control template: {@link ControlTemplate#NO_TEMPLATE}
+ * <li> Control template: {@link ControlTemplate#getNoTemplateObject}
* <li> Status text: {@code ""}
* </ul>
*/
@@ -593,7 +593,7 @@ public final class Control implements Parcelable {
* <li> Title: {@code ""}
* <li> Subtitle: {@code ""}
* <li> Status: {@link Status#STATUS_UNKNOWN}
- * <li> Control template: {@link ControlTemplate#NO_TEMPLATE}
+ * <li> Control template: {@link ControlTemplate#getNoTemplateObject}
* <li> Status text: {@code ""}
* </ul>
*/
diff --git a/core/java/android/service/controls/ControlsProviderService.java b/core/java/android/service/controls/ControlsProviderService.java
index 9debb37bd0bc..9accf5b0abf5 100644
--- a/core/java/android/service/controls/ControlsProviderService.java
+++ b/core/java/android/service/controls/ControlsProviderService.java
@@ -239,7 +239,8 @@ public abstract class ControlsProviderService extends Service {
private static boolean isStatelessControl(Control control) {
return (control.getStatus() == Control.STATUS_UNKNOWN
- && control.getControlTemplate().getTemplateType() == ControlTemplate.TYPE_NONE
+ && control.getControlTemplate().getTemplateType()
+ == ControlTemplate.TYPE_NO_TEMPLATE
&& TextUtils.isEmpty(control.getStatusText()));
}
diff --git a/core/java/android/service/controls/DeviceTypes.java b/core/java/android/service/controls/DeviceTypes.java
index 6594d2cf4ba2..f97361097bbc 100644
--- a/core/java/android/service/controls/DeviceTypes.java
+++ b/core/java/android/service/controls/DeviceTypes.java
@@ -23,11 +23,23 @@ import java.lang.annotation.RetentionPolicy;
/**
* Device types for {@link Control}.
+ *
+ * Each {@link Control} declares a type for the device they represent. This type will be used to
+ * determine icons and colors.
+ * <p>
+ * The type of the device may change on status updates of the {@link Control}. For example, a
+ * device of {@link #TYPE_OUTLET} could be determined by the {@link ControlsProviderService} to be
+ * a {@link #TYPE_COFFEE_MAKER} and change the type for that {@link Control}, therefore possibly
+ * changing icon and color.
+ * <p>
+ * In case the device type is not know by the application but the basic function is, or there is no
+ * provided type, one of the generic types (those starting with {@code TYPE_GENERIC}) can be used.
+ * These will provide an identifiable icon based on the basic function of the device.
*/
public class DeviceTypes {
// Update this when adding new concrete types. Does not count TYPE_UNKNOWN
- private static final int NUM_CONCRETE_TYPES = 51;
+ private static final int NUM_CONCRETE_TYPES = 52;
public static final @DeviceType int TYPE_UNKNOWN = 0;
public static final @DeviceType int TYPE_AC_HEATER = 1;
@@ -87,6 +99,11 @@ public class DeviceTypes {
public static final @DeviceType int TYPE_CAMERA = 50;
public static final @DeviceType int TYPE_DOORBELL = 51;
+ /*
+ * Also known as macros, routines can aggregate a series of actions across multiple devices
+ */
+ public static final @DeviceType int TYPE_ROUTINE = 52;
+
// Update this when adding new generic types.
private static final int NUM_GENERIC_TYPES = 7;
public static final @DeviceType int TYPE_GENERIC_ON_OFF = -1;
@@ -165,7 +182,8 @@ public class DeviceTypes {
TYPE_REFRIGERATOR,
TYPE_THERMOSTAT,
TYPE_CAMERA,
- TYPE_DOORBELL
+ TYPE_DOORBELL,
+ TYPE_ROUTINE
})
public @interface DeviceType {}
diff --git a/core/java/android/service/controls/TokenProvider.aidl b/core/java/android/service/controls/TokenProvider.aidl
deleted file mode 100644
index 8f4b7953f659..000000000000
--- a/core/java/android/service/controls/TokenProvider.aidl
+++ /dev/null
@@ -1,7 +0,0 @@
-package android.service.controls;
-
-/** @hide */
-interface TokenProvider {
- void setAuthToken(String token);
- String getAccountName();
-} \ No newline at end of file
diff --git a/core/java/android/service/controls/actions/ControlAction.java b/core/java/android/service/controls/actions/ControlAction.java
index 45e63d772d73..37a75f0e9e5a 100644
--- a/core/java/android/service/controls/actions/ControlAction.java
+++ b/core/java/android/service/controls/actions/ControlAction.java
@@ -22,7 +22,7 @@ import android.annotation.NonNull;
import android.annotation.Nullable;
import android.os.Bundle;
import android.service.controls.Control;
-import android.service.controls.IControlsActionCallback;
+import android.service.controls.ControlsProviderService;
import android.service.controls.templates.ControlTemplate;
import android.util.Log;
@@ -34,8 +34,15 @@ import java.lang.annotation.RetentionPolicy;
/**
* An abstract action indicating a user interaction with a {@link Control}.
*
- * The action may have a value to authenticate the input, when the provider has requested it to
- * complete the action.
+ * In some cases, an action needs to be validated by the user, using a password, PIN or simple
+ * acknowledgment. For those cases, an optional (nullable) parameter can be passed to send the user
+ * input. This <b>challenge value</b> will be requested from the user and sent as part
+ * of a {@link ControlAction} only if the service has responded to an action with one of:
+ * <ul>
+ * <li> {@link #RESPONSE_CHALLENGE_ACK}
+ * <li> {@link #RESPONSE_CHALLENGE_PIN}
+ * <li> {@link #RESPONSE_CHALLENGE_PASSPHRASE}
+ * </ul>
*/
public abstract class ControlAction {
@@ -53,7 +60,6 @@ public abstract class ControlAction {
TYPE_ERROR,
TYPE_BOOLEAN,
TYPE_FLOAT,
- TYPE_MULTI_FLOAT,
TYPE_MODE,
TYPE_COMMAND
})
@@ -61,6 +67,7 @@ public abstract class ControlAction {
/**
* Object returned when there is an unparcelling error.
+ * @hide
*/
public static final @NonNull ControlAction ERROR_ACTION = new ControlAction() {
@Override
@@ -70,7 +77,7 @@ public abstract class ControlAction {
};
/**
- * The identifier of {@link #ERROR_ACTION}
+ * The identifier of the action returned by {@link #getErrorAction}.
*/
public static final @ActionType int TYPE_ERROR = -1;
@@ -85,11 +92,6 @@ public abstract class ControlAction {
public static final @ActionType int TYPE_FLOAT = 2;
/**
- * The identifier of {@link MultiFloatAction}.
- */
- public static final @ActionType int TYPE_MULTI_FLOAT = 3;
-
- /**
* The identifier of {@link ModeAction}.
*/
public static final @ActionType int TYPE_MODE = 4;
@@ -121,28 +123,32 @@ public abstract class ControlAction {
public static final @ResponseResult int RESPONSE_UNKNOWN = 0;
/**
- * Response code for {@link IControlsActionCallback#accept} indicating that
- * the action has been performed. The action may still fail later and the state may not change.
+ * Response code for the {@code consumer} in
+ * {@link ControlsProviderService#performControlAction} indicating that the action has been
+ * performed. The action may still fail later and the state may not change.
*/
public static final @ResponseResult int RESPONSE_OK = 1;
/**
- * Response code for {@link IControlsActionCallback#accept} indicating that
- * the action has failed.
+ * Response code for the {@code consumer} in
+ * {@link ControlsProviderService#performControlAction} indicating that the action has failed.
*/
public static final @ResponseResult int RESPONSE_FAIL = 2;
/**
- * Response code for {@link IControlsActionCallback#accept} indicating that
- * in order for the action to be performed, acknowledgment from the user is required.
+ * Response code for the {@code consumer} in
+ * {@link ControlsProviderService#performControlAction} indicating that in order for the action
+ * to be performed, acknowledgment from the user is required.
*/
public static final @ResponseResult int RESPONSE_CHALLENGE_ACK = 3;
/**
- * Response code for {@link IControlsActionCallback#accept} indicating that
- * in order for the action to be performed, a PIN is required.
+ * Response code for the {@code consumer} in
+ * {@link ControlsProviderService#performControlAction} indicating that in order for the action
+ * to be performed, a PIN is required.
*/
public static final @ResponseResult int RESPONSE_CHALLENGE_PIN = 4;
/**
- * Response code for {@link IControlsActionCallback#accept} indicating that
- * in order for the action to be performed, an alphanumeric passphrase is required.
+ * Response code for the {@code consumer} in
+ * {@link ControlsProviderService#performControlAction} indicating that in order for the action
+ * to be performed, an alphanumeric passphrase is required.
*/
public static final @ResponseResult int RESPONSE_CHALLENGE_PASSPHRASE = 5;
@@ -228,8 +234,6 @@ public abstract class ControlAction {
return new BooleanAction(bundle);
case TYPE_FLOAT:
return new FloatAction(bundle);
- case TYPE_MULTI_FLOAT:
- return new MultiFloatAction(bundle);
case TYPE_MODE:
return new ModeAction(bundle);
case TYPE_COMMAND:
@@ -243,4 +247,12 @@ public abstract class ControlAction {
return ERROR_ACTION;
}
}
+
+ /**
+ * Returns a singleton {@link ControlAction} used for indicating an error in unparceling.
+ */
+ @NonNull
+ public static ControlAction getErrorAction() {
+ return ERROR_ACTION;
+ }
}
diff --git a/core/java/android/service/controls/actions/MultiFloatAction.java b/core/java/android/service/controls/actions/MultiFloatAction.java
deleted file mode 100644
index e5740795ab90..000000000000
--- a/core/java/android/service/controls/actions/MultiFloatAction.java
+++ /dev/null
@@ -1,82 +0,0 @@
-/*
- * Copyright (C) 2019 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.service.controls.actions;
-
-import android.annotation.NonNull;
-import android.annotation.Nullable;
-import android.os.Bundle;
-import android.util.Log;
-
-import com.android.internal.util.Preconditions;
-
-public final class MultiFloatAction extends ControlAction {
-
- private static final String TAG = "MultiFloatAction";
- private static final @ActionType int TYPE = TYPE_MULTI_FLOAT;
- private static final String KEY_VALUES = "key_values";
-
- private final @NonNull float[] mNewValues;
-
- @Override
- public int getActionType() {
- return TYPE;
- }
-
- public MultiFloatAction(@NonNull String templateId,
- @NonNull float[] newValues,
- @Nullable String challengeValue) {
- super(templateId, challengeValue);
- Preconditions.checkNotNull(newValues);
- if (newValues.length == 0) {
- throw new IllegalArgumentException("newValues array length 0");
- }
- if (newValues.length == 1) {
- Log.w(TAG, "newValues array length 1");
- }
- mNewValues = newValues.clone();
- }
-
- public MultiFloatAction(@NonNull String templateId, @NonNull float[] newValues) {
- this(templateId, newValues, null);
- }
-
- /**
- * @param b
- * @hide
- */
- MultiFloatAction(Bundle b) {
- super(b);
- mNewValues = b.getFloatArray(KEY_VALUES);
- }
-
- @NonNull
- public float[] getNewValues() {
- return mNewValues.clone();
- }
-
- /**
- * @return
- * @hide
- */
- @Override
- @NonNull
- Bundle getDataBundle() {
- Bundle b = super.getDataBundle();
- b.putFloatArray(KEY_VALUES, mNewValues);
- return b;
- }
-}
diff --git a/core/java/android/service/controls/templates/ControlTemplate.java b/core/java/android/service/controls/templates/ControlTemplate.java
index 30efd80db106..1e16273c455b 100644
--- a/core/java/android/service/controls/templates/ControlTemplate.java
+++ b/core/java/android/service/controls/templates/ControlTemplate.java
@@ -49,18 +49,20 @@ public abstract class ControlTemplate {
/**
* Singleton representing a {@link Control} with no input.
+ * @hide
*/
public static final @NonNull ControlTemplate NO_TEMPLATE = new ControlTemplate("") {
@Override
public int getTemplateType() {
- return TYPE_NONE;
+ return TYPE_NO_TEMPLATE;
}
};
/**
* Object returned when there is an unparcelling error.
+ * @hide
*/
- public static final @NonNull ControlTemplate ERROR_TEMPLATE = new ControlTemplate("") {
+ private static final @NonNull ControlTemplate ERROR_TEMPLATE = new ControlTemplate("") {
@Override
public int getTemplateType() {
return TYPE_ERROR;
@@ -73,10 +75,9 @@ public abstract class ControlTemplate {
@Retention(RetentionPolicy.SOURCE)
@IntDef({
TYPE_ERROR,
- TYPE_NONE,
+ TYPE_NO_TEMPLATE,
TYPE_TOGGLE,
TYPE_RANGE,
- TYPE_THUMBNAIL,
TYPE_TOGGLE_RANGE,
TYPE_TEMPERATURE,
TYPE_STATELESS
@@ -84,14 +85,14 @@ public abstract class ControlTemplate {
public @interface TemplateType {}
/**
- * Type identifier of {@link #ERROR_TEMPLATE}.
+ * Type identifier of the template returned by {@link #getErrorTemplate()}.
*/
public static final @TemplateType int TYPE_ERROR = -1;
/**
- * Type identifier of {@link ControlTemplate#NO_TEMPLATE}.
+ * Type identifier of {@link ControlTemplate#getNoTemplateObject}.
*/
- public static final @TemplateType int TYPE_NONE = 0;
+ public static final @TemplateType int TYPE_NO_TEMPLATE = 0;
/**
* Type identifier of {@link ToggleTemplate}.
@@ -104,11 +105,6 @@ public abstract class ControlTemplate {
public static final @TemplateType int TYPE_RANGE = 2;
/**
- * Type identifier of {@link ThumbnailTemplate}.
- */
- public static final @TemplateType int TYPE_THUMBNAIL = 3;
-
- /**
* Type identifier of {@link ToggleRangeTemplate}.
*/
public static final @TemplateType int TYPE_TOGGLE_RANGE = 6;
@@ -191,15 +187,13 @@ public abstract class ControlTemplate {
return new ToggleTemplate(bundle);
case TYPE_RANGE:
return new RangeTemplate(bundle);
- case TYPE_THUMBNAIL:
- return new ThumbnailTemplate(bundle);
case TYPE_TOGGLE_RANGE:
return new ToggleRangeTemplate(bundle);
case TYPE_TEMPERATURE:
return new TemperatureControlTemplate(bundle);
case TYPE_STATELESS:
return new StatelessTemplate(bundle);
- case TYPE_NONE:
+ case TYPE_NO_TEMPLATE:
return NO_TEMPLATE;
case TYPE_ERROR:
default:
@@ -210,4 +204,27 @@ public abstract class ControlTemplate {
return ERROR_TEMPLATE;
}
}
+
+ /**
+ * @return a singleton {@link ControlTemplate} used for indicating an error in unparceling.
+ */
+ @NonNull
+ public static ControlTemplate getErrorTemplate() {
+ return ERROR_TEMPLATE;
+ }
+
+ /**
+ * Get a singleton {@link ControlTemplate} that has no features.
+ *
+ * This template has no distinctive field, not even an identifier. Used for a {@link Control}
+ * that accepts no type of input, or when there is no known state.
+ *
+ * @return a singleton {@link ControlTemplate} to indicate no specific template is used by
+ * this {@link Control}
+ */
+ @NonNull
+ public static ControlTemplate getNoTemplateObject() {
+ return NO_TEMPLATE;
+ }
+
}
diff --git a/core/java/android/service/controls/templates/TemperatureControlTemplate.java b/core/java/android/service/controls/templates/TemperatureControlTemplate.java
index 0818c7e4fb82..96be97a5f3ee 100644
--- a/core/java/android/service/controls/templates/TemperatureControlTemplate.java
+++ b/core/java/android/service/controls/templates/TemperatureControlTemplate.java
@@ -60,16 +60,34 @@ public final class TemperatureControlTemplate extends ControlTemplate {
private static final int NUM_MODES = 6;
+ /**
+ * Use when the current or active mode of the device is not known
+ */
public static final @Mode int MODE_UNKNOWN = 0;
+ /**
+ * Indicates that the current or active mode of the device is off.
+ */
public static final @Mode int MODE_OFF = 1;
+ /**
+ * Indicates that the current or active mode of the device is set to heat.
+ */
public static final @Mode int MODE_HEAT = 2;
+ /**
+ * Indicates that the current or active mode of the device is set to cool.
+ */
public static final @Mode int MODE_COOL = 3;
+ /**
+ * Indicates that the current or active mode of the device is set to heat-cool.
+ */
public static final @Mode int MODE_HEAT_COOL = 4;
+ /**
+ * Indicates that the current or active mode of the device is set to eco.
+ */
public static final @Mode int MODE_ECO = 5;
/**
@@ -85,10 +103,29 @@ public final class TemperatureControlTemplate extends ControlTemplate {
})
public @interface ModeFlag {}
+ /**
+ * Flag to indicate that the device supports off mode.
+ */
public static final int FLAG_MODE_OFF = 1 << MODE_OFF;
+
+ /**
+ * Flag to indicate that the device supports heat mode.
+ */
public static final int FLAG_MODE_HEAT = 1 << MODE_HEAT;
+
+ /**
+ * Flag to indicate that the device supports cool mode.
+ */
public static final int FLAG_MODE_COOL = 1 << MODE_COOL;
+
+ /**
+ * Flag to indicate that the device supports heat-cool mode.
+ */
public static final int FLAG_MODE_HEAT_COOL = 1 << MODE_HEAT_COOL;
+
+ /**
+ * Flag to indicate that the device supports eco mode.
+ */
public static final int FLAG_MODE_ECO = 1 << MODE_ECO;
private static final int ALL_FLAGS =
FLAG_MODE_OFF |
diff --git a/core/java/android/service/controls/templates/ThumbnailTemplate.java b/core/java/android/service/controls/templates/ThumbnailTemplate.java
deleted file mode 100644
index 72179f4edc5e..000000000000
--- a/core/java/android/service/controls/templates/ThumbnailTemplate.java
+++ /dev/null
@@ -1,98 +0,0 @@
-/*
- * Copyright (C) 2019 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.service.controls.templates;
-
-import android.annotation.NonNull;
-import android.graphics.drawable.Icon;
-import android.os.Bundle;
-import android.service.controls.Control;
-
-import com.android.internal.util.Preconditions;
-
-/**
- * A template for a {@link Control} that displays an image.
- */
-public final class ThumbnailTemplate extends ControlTemplate {
-
- private static final @TemplateType int TYPE = TYPE_THUMBNAIL;
- private static final String KEY_ICON = "key_icon";
- private static final String KEY_CONTENT_DESCRIPTION = "key_content_description";
-
- private final @NonNull Icon mThumbnail;
- private final @NonNull CharSequence mContentDescription;
-
- /**
- * @param templateId the identifier for this template object
- * @param thumbnail an image to display on the {@link Control}
- * @param contentDescription a description of the image for accessibility.
- */
- public ThumbnailTemplate(@NonNull String templateId, @NonNull Icon thumbnail,
- @NonNull CharSequence contentDescription) {
- super(templateId);
- Preconditions.checkNotNull(thumbnail);
- Preconditions.checkNotNull(contentDescription);
- mThumbnail = thumbnail;
- mContentDescription = contentDescription;
- }
-
- /**
- * @param b
- * @hide
- */
- ThumbnailTemplate(Bundle b) {
- super(b);
- mThumbnail = b.getParcelable(KEY_ICON);
- mContentDescription = b.getCharSequence(KEY_CONTENT_DESCRIPTION, "");
- }
-
- /**
- * The {@link Icon} (image) displayed by this template.
- */
- @NonNull
- public Icon getThumbnail() {
- return mThumbnail;
- }
-
- /**
- * The description of the image returned by {@link ThumbnailTemplate#getThumbnail()}
- */
- @NonNull
- public CharSequence getContentDescription() {
- return mContentDescription;
- }
-
- /**
- * @return {@link ControlTemplate#TYPE_THUMBNAIL}
- */
- @Override
- public int getTemplateType() {
- return TYPE;
- }
-
- /**
- * @return
- * @hide
- */
- @Override
- @NonNull
- Bundle getDataBundle() {
- Bundle b = super.getDataBundle();
- b.putObject(KEY_ICON, mThumbnail);
- b.putObject(KEY_CONTENT_DESCRIPTION, mContentDescription);
- return b;
- }
-}
diff --git a/core/java/android/service/dataloader/DataLoaderService.java b/core/java/android/service/dataloader/DataLoaderService.java
index 5bf1975a44ff..0b9a8aff26e8 100644
--- a/core/java/android/service/dataloader/DataLoaderService.java
+++ b/core/java/android/service/dataloader/DataLoaderService.java
@@ -172,7 +172,7 @@ public abstract class DataLoaderService extends Service {
@Override
public void prepareImage(InstallationFileParcel[] addedFiles, String[] removedFiles) {
if (!nativePrepareImage(mId, addedFiles, removedFiles)) {
- Slog.w(TAG, "Failed to destroy loader: " + mId);
+ Slog.w(TAG, "Failed to prepare image for data loader: " + mId);
}
}
}
diff --git a/core/java/android/service/notification/StatusBarNotification.java b/core/java/android/service/notification/StatusBarNotification.java
index 74b913645ad4..1beeb6554ee1 100644
--- a/core/java/android/service/notification/StatusBarNotification.java
+++ b/core/java/android/service/notification/StatusBarNotification.java
@@ -237,16 +237,24 @@ public class StatusBarNotification implements Parcelable {
public StatusBarNotification cloneLight() {
final Notification no = new Notification();
this.notification.cloneInto(no, false); // light copy
- return new StatusBarNotification(this.pkg, this.opPkg,
- this.id, this.tag, this.uid, this.initialPid,
- no, this.user, this.overrideGroupKey, this.postTime);
+ return cloneShallow(no);
}
@Override
public StatusBarNotification clone() {
- return new StatusBarNotification(this.pkg, this.opPkg,
+ return cloneShallow(this.notification.clone());
+ }
+
+ /**
+ * @param notification Some kind of clone of this.notification.
+ * @return A shallow copy of self, with notification in place of this.notification.
+ */
+ StatusBarNotification cloneShallow(Notification notification) {
+ StatusBarNotification result = new StatusBarNotification(this.pkg, this.opPkg,
this.id, this.tag, this.uid, this.initialPid,
- this.notification.clone(), this.user, this.overrideGroupKey, this.postTime);
+ notification, this.user, this.overrideGroupKey, this.postTime);
+ result.setInstanceId(this.mInstanceId);
+ return result;
}
@Override
diff --git a/core/java/android/timezone/CountryTimeZones.java b/core/java/android/timezone/CountryTimeZones.java
index ee3a8a79d5d7..a8db50e51782 100644
--- a/core/java/android/timezone/CountryTimeZones.java
+++ b/core/java/android/timezone/CountryTimeZones.java
@@ -140,7 +140,7 @@ public final class CountryTimeZones {
@Override
public String toString() {
return "OffsetResult{"
- + "mTimeZone=" + mTimeZone
+ + "mTimeZone(ID)=" + mTimeZone.getID()
+ ", mIsOnlyMatch=" + mIsOnlyMatch
+ '}';
}
diff --git a/core/java/android/util/FeatureFlagUtils.java b/core/java/android/util/FeatureFlagUtils.java
index cfbe393bfcc8..6b87a10643fd 100644
--- a/core/java/android/util/FeatureFlagUtils.java
+++ b/core/java/android/util/FeatureFlagUtils.java
@@ -71,7 +71,7 @@ public class FeatureFlagUtils {
// introduced in R and will be removed in the next release (b/148367230).
DEFAULT_FLAGS.put(SETTINGS_DO_NOT_RESTORE_PRESERVED, "false");
- DEFAULT_FLAGS.put("settings_tether_all_in_one", "false");
+ DEFAULT_FLAGS.put("settings_tether_all_in_one", "true");
DEFAULT_FLAGS.put(SETTINGS_SCHEDULES_FLAG, "false");
DEFAULT_FLAGS.put("settings_contextual_home2", "false");
}
diff --git a/core/java/android/view/IWindowManager.aidl b/core/java/android/view/IWindowManager.aidl
index 73601d968040..84ac90bae258 100644
--- a/core/java/android/view/IWindowManager.aidl
+++ b/core/java/android/view/IWindowManager.aidl
@@ -724,11 +724,12 @@ interface IWindowManager
/**
* Called to get the expected window insets.
- * TODO(window-context): Remove when new insets flag is available.
+ *
+ * @return {@code true} if system bars are always comsumed.
*/
- void getWindowInsets(in WindowManager.LayoutParams attrs, int displayId,
+ boolean getWindowInsets(in WindowManager.LayoutParams attrs, int displayId,
out Rect outContentInsets, out Rect outStableInsets,
- out DisplayCutout.ParcelableWrapper displayCutout);
+ out DisplayCutout.ParcelableWrapper outDisplayCutout, out InsetsState outInsetsState);
/**
* Called to show global actions.
diff --git a/core/java/android/view/InsetsAnimationControlImpl.java b/core/java/android/view/InsetsAnimationControlImpl.java
index 42a6175c0b27..ae509f3a82c4 100644
--- a/core/java/android/view/InsetsAnimationControlImpl.java
+++ b/core/java/android/view/InsetsAnimationControlImpl.java
@@ -166,18 +166,17 @@ public class InsetsAnimationControlImpl implements WindowInsetsAnimationControll
return false;
}
final Insets offset = Insets.subtract(mShownInsets, mPendingInsets);
- final Float alphaOffset = 1 - mPendingAlpha;
ArrayList<SurfaceParams> params = new ArrayList<>();
updateLeashesForSide(ISIDE_LEFT, offset.left, mShownInsets.left, mPendingInsets.left,
- params, state, alphaOffset);
+ params, state, mPendingAlpha);
updateLeashesForSide(ISIDE_TOP, offset.top, mShownInsets.top, mPendingInsets.top, params,
- state, alphaOffset);
+ state, mPendingAlpha);
updateLeashesForSide(ISIDE_RIGHT, offset.right, mShownInsets.right, mPendingInsets.right,
- params, state, alphaOffset);
+ params, state, mPendingAlpha);
updateLeashesForSide(ISIDE_BOTTOM, offset.bottom, mShownInsets.bottom,
- mPendingInsets.bottom, params, state, alphaOffset);
+ mPendingInsets.bottom, params, state, mPendingAlpha);
updateLeashesForSide(ISIDE_FLOATING, 0 /* offset */, 0 /* inset */, 0 /* maxInset */,
- params, state, alphaOffset);
+ params, state, mPendingAlpha);
mController.applySurfaceParams(params.toArray(new SurfaceParams[params.size()]));
mCurrentInsets = mPendingInsets;
diff --git a/core/java/android/view/InsetsController.java b/core/java/android/view/InsetsController.java
index 573d8fc65c84..302d4f3f79c8 100644
--- a/core/java/android/view/InsetsController.java
+++ b/core/java/android/view/InsetsController.java
@@ -724,12 +724,13 @@ public class InsetsController implements WindowInsetsController, InsetsAnimation
mApplier = new SyncRtSurfaceTransactionApplier(mViewRoot.mView);
}
if (mViewRoot.mView.isHardwareAccelerated()) {
- mApplier.scheduleApply(params);
+ mApplier.scheduleApply(false /* earlyWakeup */, params);
} else {
// Window doesn't support hardware acceleration, no synchronization for now.
// TODO(b/149342281): use mViewRoot.mSurface.getNextFrameNumber() to sync on every
// frame instead.
- mApplier.applyParams(new Transaction(), -1 /* frame */, params);
+ mApplier.applyParams(new Transaction(), -1 /* frame */, false /* earlyWakeup */,
+ params);
}
}
@@ -992,4 +993,23 @@ public class InsetsController implements WindowInsetsController, InsetsAnimation
}
return mViewRoot.mWindowAttributes.insetsFlags.behavior;
}
+
+ /**
+ * At the time we receive new leashes (e.g. InsetsSourceConsumer is processing
+ * setControl) we need to release the old leash. But we may have already scheduled
+ * a SyncRtSurfaceTransaction applier to use it from the RenderThread. To avoid
+ * synchronization issues we also release from the RenderThread so this release
+ * happens after any existing items on the work queue.
+ */
+ public void releaseSurfaceControlFromRt(SurfaceControl sc) {
+ if (mViewRoot.mView != null && mViewRoot.mView.isHardwareAccelerated()) {
+ mViewRoot.registerRtFrameCallback(frame -> {
+ sc.release();
+ });
+ // Make sure a frame gets scheduled.
+ mViewRoot.mView.invalidate();
+ } else {
+ sc.release();
+ }
+ }
}
diff --git a/core/java/android/view/InsetsSourceConsumer.java b/core/java/android/view/InsetsSourceConsumer.java
index 92ac4259c349..252fc0c82cf7 100644
--- a/core/java/android/view/InsetsSourceConsumer.java
+++ b/core/java/android/view/InsetsSourceConsumer.java
@@ -87,6 +87,7 @@ public class InsetsSourceConsumer {
if (mSourceControl == control) {
return;
}
+ final InsetsSourceControl lastControl = mSourceControl;
mSourceControl = control;
// We are loosing control
@@ -97,25 +98,27 @@ public class InsetsSourceConsumer {
mState.getSource(getType()).setVisible(
mController.getLastDispatchedState().getSource(getType()).isVisible());
applyLocalVisibilityOverride();
- return;
- }
-
- // We are gaining control, and need to run an animation since previous state didn't match
- if (mRequestedVisible != mState.getSource(mType).isVisible()) {
- if (mRequestedVisible) {
- showTypes[0] |= toPublicType(getType());
+ } else {
+ // We are gaining control, and need to run an animation since previous state
+ // didn't match
+ if (mRequestedVisible != mState.getSource(mType).isVisible()) {
+ if (mRequestedVisible) {
+ showTypes[0] |= toPublicType(getType());
+ } else {
+ hideTypes[0] |= toPublicType(getType());
+ }
} else {
- hideTypes[0] |= toPublicType(getType());
+ // We are gaining control, but don't need to run an animation.
+ // However make sure that the leash visibility is still up to date.
+ if (applyLocalVisibilityOverride()) {
+ mController.notifyVisibilityChanged();
+ }
+ applyHiddenToControl();
}
- return;
}
-
- // We are gaining control, but don't need to run an animation. However make sure that the
- // leash visibility is still up to date.
- if (applyLocalVisibilityOverride()) {
- mController.notifyVisibilityChanged();
+ if (lastControl != null) {
+ lastControl.release(mController);
}
- applyHiddenToControl();
}
@VisibleForTesting
diff --git a/core/java/android/view/InsetsSourceControl.java b/core/java/android/view/InsetsSourceControl.java
index 7be3e6a42475..75f6eab798ce 100644
--- a/core/java/android/view/InsetsSourceControl.java
+++ b/core/java/android/view/InsetsSourceControl.java
@@ -94,6 +94,12 @@ public class InsetsSourceControl implements Parcelable {
dest.writeParcelable(mSurfacePosition, 0 /* flags*/);
}
+ public void release(InsetsController controller) {
+ if (mLeash != null) {
+ controller.releaseSurfaceControlFromRt(mLeash);
+ }
+ }
+
public static final @android.annotation.NonNull Creator<InsetsSourceControl> CREATOR
= new Creator<InsetsSourceControl>() {
public InsetsSourceControl createFromParcel(Parcel in) {
diff --git a/core/java/android/view/InsetsState.java b/core/java/android/view/InsetsState.java
index b740c58ec15f..c2ad74a566e9 100644
--- a/core/java/android/view/InsetsState.java
+++ b/core/java/android/view/InsetsState.java
@@ -80,6 +80,12 @@ public class InsetsState implements Parcelable {
})
public @interface InternalInsetsType {}
+ /**
+ * Special value to be used to by methods returning an {@link InternalInsetsType} to indicate
+ * that the objects/parameters aren't associated with an {@link InternalInsetsType}
+ */
+ public static final int ITYPE_INVALID = -1;
+
static final int FIRST_TYPE = 0;
public static final int ITYPE_STATUS_BAR = FIRST_TYPE;
@@ -342,6 +348,20 @@ public class InsetsState implements Parcelable {
}
}
+ /**
+ * A shortcut for setting the visibility of the source.
+ *
+ * @param type The {@link InternalInsetsType} of the source to set the visibility
+ * @param referenceState The {@link InsetsState} for reference
+ */
+ public void setSourceVisible(@InternalInsetsType int type, InsetsState referenceState) {
+ InsetsSource source = mSources.get(type);
+ InsetsSource referenceSource = referenceState.mSources.get(type);
+ if (source != null && referenceSource != null) {
+ source.setVisible(referenceSource.isVisible());
+ }
+ }
+
public void set(InsetsState other) {
set(other, false /* copySources */);
}
diff --git a/core/java/android/view/RemoteAnimationTarget.java b/core/java/android/view/RemoteAnimationTarget.java
index b04372a1ce19..3c22ed80cb86 100644
--- a/core/java/android/view/RemoteAnimationTarget.java
+++ b/core/java/android/view/RemoteAnimationTarget.java
@@ -20,9 +20,11 @@ import static android.view.RemoteAnimationTargetProto.CLIP_RECT;
import static android.view.RemoteAnimationTargetProto.CONTENT_INSETS;
import static android.view.RemoteAnimationTargetProto.IS_TRANSLUCENT;
import static android.view.RemoteAnimationTargetProto.LEASH;
+import static android.view.RemoteAnimationTargetProto.LOCAL_BOUNDS;
import static android.view.RemoteAnimationTargetProto.MODE;
import static android.view.RemoteAnimationTargetProto.POSITION;
import static android.view.RemoteAnimationTargetProto.PREFIX_ORDER_INDEX;
+import static android.view.RemoteAnimationTargetProto.SCREEN_SPACE_BOUNDS;
import static android.view.RemoteAnimationTargetProto.SOURCE_CONTAINER_BOUNDS;
import static android.view.RemoteAnimationTargetProto.START_BOUNDS;
import static android.view.RemoteAnimationTargetProto.START_LEASH;
@@ -130,19 +132,38 @@ public class RemoteAnimationTarget implements Parcelable {
* The source position of the app, in screen spaces coordinates. If the position of the leash
* is modified from the controlling app, any animation transform needs to be offset by this
* amount.
+ * @deprecated Use {@link #localBounds} instead.
*/
+ @Deprecated
@UnsupportedAppUsage
public final Point position;
/**
+ * Bounds of the target relative to its parent.
+ * When the app target animating on its parent, we need to use the local coordinates relative to
+ * its parent with {@code localBounds.left} & {@code localBounds.top} rather than using
+ * {@code position} in screen coordinates.
+ */
+ public final Rect localBounds;
+
+ /**
* The bounds of the source container the app lives in, in screen space coordinates. If the crop
* of the leash is modified from the controlling app, it needs to take the source container
* bounds into account when calculating the crop.
+ * @deprecated Renamed to {@link #screenSpaceBounds}
*/
+ @Deprecated
@UnsupportedAppUsage
public final Rect sourceContainerBounds;
/**
+ * Bounds of the target relative to the screen. If the crop of the leash is modified from the
+ * controlling app, it needs to take the screen space bounds into account when calculating the
+ * crop.
+ */
+ public final Rect screenSpaceBounds;
+
+ /**
* The starting bounds of the source container in screen space coordinates. This is {@code null}
* if the animation target isn't MODE_CHANGING. Since this is the starting bounds, it's size
* should be equivalent to the size of the starting thumbnail. Note that sourceContainerBounds
@@ -165,7 +186,8 @@ public class RemoteAnimationTarget implements Parcelable {
public RemoteAnimationTarget(int taskId, int mode, SurfaceControl leash, boolean isTranslucent,
Rect clipRect, Rect contentInsets, int prefixOrderIndex, Point position,
- Rect sourceContainerBounds, WindowConfiguration windowConfig, boolean isNotInRecents,
+ Rect localBounds, Rect screenSpaceBounds,
+ WindowConfiguration windowConfig, boolean isNotInRecents,
SurfaceControl startLeash, Rect startBounds) {
this.mode = mode;
this.taskId = taskId;
@@ -175,7 +197,9 @@ public class RemoteAnimationTarget implements Parcelable {
this.contentInsets = new Rect(contentInsets);
this.prefixOrderIndex = prefixOrderIndex;
this.position = new Point(position);
- this.sourceContainerBounds = new Rect(sourceContainerBounds);
+ this.localBounds = new Rect(localBounds);
+ this.sourceContainerBounds = new Rect(screenSpaceBounds);
+ this.screenSpaceBounds = new Rect(screenSpaceBounds);
this.windowConfiguration = windowConfig;
this.isNotInRecents = isNotInRecents;
this.startLeash = startLeash;
@@ -191,7 +215,9 @@ public class RemoteAnimationTarget implements Parcelable {
contentInsets = in.readParcelable(null);
prefixOrderIndex = in.readInt();
position = in.readParcelable(null);
+ localBounds = in.readParcelable(null);
sourceContainerBounds = in.readParcelable(null);
+ screenSpaceBounds = in.readParcelable(null);
windowConfiguration = in.readParcelable(null);
isNotInRecents = in.readBoolean();
startLeash = in.readParcelable(null);
@@ -213,7 +239,9 @@ public class RemoteAnimationTarget implements Parcelable {
dest.writeParcelable(contentInsets, 0 /* flags */);
dest.writeInt(prefixOrderIndex);
dest.writeParcelable(position, 0 /* flags */);
+ dest.writeParcelable(localBounds, 0 /* flags */);
dest.writeParcelable(sourceContainerBounds, 0 /* flags */);
+ dest.writeParcelable(screenSpaceBounds, 0 /* flags */);
dest.writeParcelable(windowConfiguration, 0 /* flags */);
dest.writeBoolean(isNotInRecents);
dest.writeParcelable(startLeash, 0 /* flags */);
@@ -229,6 +257,8 @@ public class RemoteAnimationTarget implements Parcelable {
pw.print(" prefixOrderIndex="); pw.print(prefixOrderIndex);
pw.print(" position="); position.printShortString(pw);
pw.print(" sourceContainerBounds="); sourceContainerBounds.printShortString(pw);
+ pw.print(" screenSpaceBounds="); screenSpaceBounds.printShortString(pw);
+ pw.print(" localBounds="); localBounds.printShortString(pw);
pw.println();
pw.print(prefix); pw.print("windowConfiguration="); pw.println(windowConfiguration);
pw.print(prefix); pw.print("leash="); pw.println(leash);
@@ -245,6 +275,8 @@ public class RemoteAnimationTarget implements Parcelable {
proto.write(PREFIX_ORDER_INDEX, prefixOrderIndex);
position.dumpDebug(proto, POSITION);
sourceContainerBounds.dumpDebug(proto, SOURCE_CONTAINER_BOUNDS);
+ screenSpaceBounds.dumpDebug(proto, SCREEN_SPACE_BOUNDS);
+ localBounds.dumpDebug(proto, LOCAL_BOUNDS);
windowConfiguration.dumpDebug(proto, WINDOW_CONFIGURATION);
if (startLeash != null) {
startLeash.dumpDebug(proto, START_LEASH);
diff --git a/core/java/android/view/SurfaceView.java b/core/java/android/view/SurfaceView.java
index fb7c04afeab0..1f7c3504560f 100644
--- a/core/java/android/view/SurfaceView.java
+++ b/core/java/android/view/SurfaceView.java
@@ -605,7 +605,7 @@ public class SurfaceView extends View implements ViewRootImpl.SurfaceChangedCall
mTmpRect.set(0, 0, mSurfaceWidth, mSurfaceHeight);
}
SyncRtSurfaceTransactionApplier applier = new SyncRtSurfaceTransactionApplier(this);
- applier.scheduleApply(
+ applier.scheduleApply(false /* earlyWakeup */,
new SyncRtSurfaceTransactionApplier.SurfaceParams.Builder(mSurfaceControl)
.withWindowCrop(mTmpRect)
.build());
diff --git a/core/java/android/view/SyncRtSurfaceTransactionApplier.java b/core/java/android/view/SyncRtSurfaceTransactionApplier.java
index 206e4f936edf..9c97f3e5b503 100644
--- a/core/java/android/view/SyncRtSurfaceTransactionApplier.java
+++ b/core/java/android/view/SyncRtSurfaceTransactionApplier.java
@@ -53,10 +53,11 @@ public class SyncRtSurfaceTransactionApplier {
/**
* Schedules applying surface parameters on the next frame.
*
+ * @param earlyWakeup Whether to set {@link Transaction#setEarlyWakeup()} on transaction.
* @param params The surface parameters to apply. DO NOT MODIFY the list after passing into
* this method to avoid synchronization issues.
*/
- public void scheduleApply(final SurfaceParams... params) {
+ public void scheduleApply(boolean earlyWakeup, final SurfaceParams... params) {
if (mTargetViewRootImpl == null) {
return;
}
@@ -66,7 +67,7 @@ public class SyncRtSurfaceTransactionApplier {
return;
}
Transaction t = new Transaction();
- applyParams(t, frame, params);
+ applyParams(t, frame, earlyWakeup, params);
});
// Make sure a frame gets scheduled.
@@ -77,10 +78,12 @@ public class SyncRtSurfaceTransactionApplier {
* Applies surface parameters on the next frame.
* @param t transaction to apply all parameters in.
* @param frame frame to synchronize to. Set -1 when sync is not required.
+ * @param earlyWakeup Whether to set {@link Transaction#setEarlyWakeup()} on transaction.
* @param params The surface parameters to apply. DO NOT MODIFY the list after passing into
* this method to avoid synchronization issues.
*/
- void applyParams(Transaction t, long frame, final SurfaceParams... params) {
+ void applyParams(Transaction t, long frame, boolean earlyWakeup,
+ final SurfaceParams... params) {
for (int i = params.length - 1; i >= 0; i--) {
SurfaceParams surfaceParams = params[i];
SurfaceControl surface = surfaceParams.surface;
@@ -89,7 +92,9 @@ public class SyncRtSurfaceTransactionApplier {
}
applyParams(t, surfaceParams, mTmpFloat9);
}
- t.setEarlyWakeup();
+ if (earlyWakeup) {
+ t.setEarlyWakeup();
+ }
t.apply();
}
diff --git a/core/java/android/view/ViewGroup.java b/core/java/android/view/ViewGroup.java
index b6c46be66761..7d4ec3dcf2e7 100644
--- a/core/java/android/view/ViewGroup.java
+++ b/core/java/android/view/ViewGroup.java
@@ -3714,7 +3714,7 @@ public abstract class ViewGroup extends View implements ViewParent, ViewManager
if (extraDataKey.equals(AccessibilityNodeInfo.EXTRA_DATA_RENDERING_INFO_KEY)) {
final AccessibilityNodeInfo.ExtraRenderingInfo extraRenderingInfo =
AccessibilityNodeInfo.ExtraRenderingInfo.obtain();
- extraRenderingInfo.setLayoutParams(getLayoutParams().width, getLayoutParams().height);
+ extraRenderingInfo.setLayoutSize(getLayoutParams().width, getLayoutParams().height);
info.setExtraRenderingInfo(extraRenderingInfo);
}
}
diff --git a/core/java/android/view/ViewRootImpl.java b/core/java/android/view/ViewRootImpl.java
index 8d3cffc512c3..9228fbdf82c8 100644
--- a/core/java/android/view/ViewRootImpl.java
+++ b/core/java/android/view/ViewRootImpl.java
@@ -1735,7 +1735,7 @@ public final class ViewRootImpl implements ViewParent,
mBoundsLayer = new SurfaceControl.Builder(mSurfaceSession)
.setContainerLayer()
.setName("Bounds for - " + getTitle().toString())
- .setParent(mSurfaceControl)
+ .setParent(getRenderSurfaceControl())
.build();
setBoundsLayerCrop();
mTransaction.show(mBoundsLayer).apply();
diff --git a/core/java/android/view/Window.java b/core/java/android/view/Window.java
index 000fd8069292..0c5c18316e61 100644
--- a/core/java/android/view/Window.java
+++ b/core/java/android/view/Window.java
@@ -1255,7 +1255,7 @@ public abstract class Window {
* <p>The ability to switch to a mode with minimal post proessing may be disabled by a user
* setting in the system settings menu. In that case, this method does nothing.
*
- * @see android.content.pm.ActivityInfo#preferMinimalPostProcessing
+ * @see android.content.pm.ActivityInfo#FLAG_PREFER_MINIMAL_POST_PROCESSING
* @see android.view.Display#isMinimalPostProcessingSupported
* @see android.view.WindowManager.LayoutParams#preferMinimalPostProcessing
*
diff --git a/core/java/android/view/WindowContainerTransaction.java b/core/java/android/view/WindowContainerTransaction.java
index f406be9ebac7..e05c3743565c 100644
--- a/core/java/android/view/WindowContainerTransaction.java
+++ b/core/java/android/view/WindowContainerTransaction.java
@@ -72,6 +72,33 @@ public class WindowContainerTransaction implements Parcelable {
}
/**
+ * Resize a container's app bounds. This is the bounds used to report appWidth/Height to an
+ * app's DisplayInfo. It is derived by subtracting the overlapping portion of the navbar from
+ * the full bounds.
+ */
+ public WindowContainerTransaction setAppBounds(IWindowContainer container, Rect appBounds) {
+ Change chg = getOrCreateChange(container.asBinder());
+ chg.mConfiguration.windowConfiguration.setAppBounds(appBounds);
+ chg.mConfigSetMask |= ActivityInfo.CONFIG_WINDOW_CONFIGURATION;
+ chg.mWindowSetMask |= WindowConfiguration.WINDOW_CONFIG_APP_BOUNDS;
+ return this;
+ }
+
+ /**
+ * Resize a container's configuration size. The configuration size is what gets reported to the
+ * app via screenWidth/HeightDp and influences which resources get loaded. This size is
+ * derived by subtracting the overlapping portions of both the statusbar and the navbar from
+ * the full bounds.
+ */
+ public WindowContainerTransaction setScreenSizeDp(IWindowContainer container, int w, int h) {
+ Change chg = getOrCreateChange(container.asBinder());
+ chg.mConfiguration.screenWidthDp = w;
+ chg.mConfiguration.screenHeightDp = h;
+ chg.mConfigSetMask |= ActivityInfo.CONFIG_SCREEN_SIZE;
+ return this;
+ }
+
+ /**
* Notify activies within the hiearchy of a container that they have entered picture-in-picture
* mode with the given bounds.
*/
@@ -161,7 +188,8 @@ public class WindowContainerTransaction implements Parcelable {
@Override
public String toString() {
- return "WindowContainerTransaction { changes = " + mChanges + " }";
+ return "WindowContainerTransaction { changes = " + mChanges + " hops = " + mHierarchyOps
+ + " }";
}
@Override
@@ -269,6 +297,11 @@ public class WindowContainerTransaction implements Parcelable {
(mConfigSetMask & ActivityInfo.CONFIG_WINDOW_CONFIGURATION) != 0
&& ((mWindowSetMask & WindowConfiguration.WINDOW_CONFIG_BOUNDS)
!= 0);
+ final boolean changesAppBounds =
+ (mConfigSetMask & ActivityInfo.CONFIG_WINDOW_CONFIGURATION) != 0
+ && ((mWindowSetMask & WindowConfiguration.WINDOW_CONFIG_APP_BOUNDS)
+ != 0);
+ final boolean changesSs = (mConfigSetMask & ActivityInfo.CONFIG_SCREEN_SIZE) != 0;
final boolean changesSss =
(mConfigSetMask & ActivityInfo.CONFIG_SMALLEST_SCREEN_SIZE) != 0;
StringBuilder sb = new StringBuilder();
@@ -276,9 +309,16 @@ public class WindowContainerTransaction implements Parcelable {
if (changesBounds) {
sb.append("bounds:" + mConfiguration.windowConfiguration.getBounds() + ",");
}
+ if (changesAppBounds) {
+ sb.append("appbounds:" + mConfiguration.windowConfiguration.getAppBounds() + ",");
+ }
if (changesSss) {
sb.append("ssw:" + mConfiguration.smallestScreenWidthDp + ",");
}
+ if (changesSs) {
+ sb.append("sw/h:" + mConfiguration.screenWidthDp + "x"
+ + mConfiguration.screenHeightDp + ",");
+ }
if ((mChangeMask & CHANGE_FOCUSABLE) != 0) {
sb.append("focusable:" + mFocusable + ",");
}
diff --git a/core/java/android/view/WindowManager.java b/core/java/android/view/WindowManager.java
index 67bf0f1c04d2..867b648cfb10 100644
--- a/core/java/android/view/WindowManager.java
+++ b/core/java/android/view/WindowManager.java
@@ -1587,7 +1587,7 @@ public interface WindowManager extends ViewManager {
*
* {@sample development/samples/ApiDemos/res/layout/overscan_activity.xml complete}
*
- * @deprecated Overscan areas aren't set by any Android product anymore.
+ * @deprecated Overscan areas aren't set by any Android product anymore as of Android 11.
*/
@Deprecated
public static final int FLAG_LAYOUT_IN_OVERSCAN = 0x02000000;
@@ -2777,7 +2777,7 @@ public interface WindowManager extends ViewManager {
* setting in the system settings menu. In that case, this field is ignored and the display
* will remain in its current mode.
*
- * @see android.content.pm.ActivityInfo#preferMinimalPostProcessing
+ * @see android.content.pm.ActivityInfo#FLAG_PREFER_MINIMAL_POST_PROCESSING
* @see android.view.Display#isMinimalPostProcessingSupported
* @see android.view.Window#setPreferMinimalPostProcessing
*/
diff --git a/core/java/android/view/WindowManagerImpl.java b/core/java/android/view/WindowManagerImpl.java
index 6435b42efca0..4050da1b5cb1 100644
--- a/core/java/android/view/WindowManagerImpl.java
+++ b/core/java/android/view/WindowManagerImpl.java
@@ -18,8 +18,11 @@ package android.view;
import static android.view.View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN;
import static android.view.View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION;
+import static android.view.View.SYSTEM_UI_FLAG_VISIBLE;
+import static android.view.ViewRootImpl.NEW_INSETS_MODE_FULL;
import static android.view.WindowManager.LayoutParams.FLAG_LAYOUT_INSET_DECOR;
import static android.view.WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN;
+import static android.view.WindowManager.LayoutParams.SOFT_INPUT_ADJUST_NOTHING;
import android.annotation.NonNull;
import android.app.ResourcesManager;
@@ -215,9 +218,9 @@ public final class WindowManagerImpl implements WindowManager {
@Override
public WindowMetrics getCurrentWindowMetrics() {
final Context context = mParentWindow != null ? mParentWindow.getContext() : mContext;
- final Rect bound = getCurrentBounds(context);
+ final Rect bounds = getCurrentBounds(context);
- return new WindowMetrics(toSize(bound), computeWindowInsets());
+ return new WindowMetrics(toSize(bounds), computeWindowInsets(bounds));
}
private static Rect getCurrentBounds(Context context) {
@@ -228,7 +231,8 @@ public final class WindowManagerImpl implements WindowManager {
@Override
public WindowMetrics getMaximumWindowMetrics() {
- return new WindowMetrics(toSize(getMaximumBounds()), computeWindowInsets());
+ final Rect maxBounds = getMaximumBounds();
+ return new WindowMetrics(toSize(maxBounds), computeWindowInsets(maxBounds));
}
private Size toSize(Rect frame) {
@@ -244,9 +248,8 @@ public final class WindowManagerImpl implements WindowManager {
return new Rect(0, 0, displaySize.x, displaySize.y);
}
- private WindowInsets computeWindowInsets() {
- // TODO(b/118118435): This can only be properly implemented
- // once we flip the new insets mode flag.
+ // TODO(b/150095967): Set window type to LayoutParams
+ private WindowInsets computeWindowInsets(Rect bounds) {
// Initialize params which used for obtaining all system insets.
final WindowManager.LayoutParams params = new WindowManager.LayoutParams();
params.flags = FLAG_LAYOUT_IN_SCREEN | FLAG_LAYOUT_INSET_DECOR;
@@ -257,21 +260,34 @@ public final class WindowManagerImpl implements WindowManager {
params.setFitInsetsTypes(0);
params.setFitInsetsSides(0);
- return getWindowInsetsFromServer(params);
+ return getWindowInsetsFromServer(params, bounds);
}
- private WindowInsets getWindowInsetsFromServer(WindowManager.LayoutParams attrs) {
+ private WindowInsets getWindowInsetsFromServer(WindowManager.LayoutParams attrs, Rect bounds) {
try {
final Rect systemWindowInsets = new Rect();
final Rect stableInsets = new Rect();
final DisplayCutout.ParcelableWrapper displayCutout =
new DisplayCutout.ParcelableWrapper();
- WindowManagerGlobal.getWindowManagerService().getWindowInsets(attrs,
- mContext.getDisplayId(), systemWindowInsets, stableInsets, displayCutout);
- return new WindowInsets.Builder()
- .setSystemWindowInsets(Insets.of(systemWindowInsets))
- .setStableInsets(Insets.of(stableInsets))
- .setDisplayCutout(displayCutout.get()).build();
+ final InsetsState insetsState = new InsetsState();
+ final boolean alwaysConsumeSystemBars = WindowManagerGlobal.getWindowManagerService()
+ .getWindowInsets(attrs, mContext.getDisplayId(), systemWindowInsets,
+ stableInsets, displayCutout, insetsState);
+ final boolean isScreenRound =
+ mContext.getResources().getConfiguration().isScreenRound();
+ if (ViewRootImpl.sNewInsetsMode == NEW_INSETS_MODE_FULL) {
+ return insetsState.calculateInsets(bounds, null /* ignoringVisibilityState*/,
+ isScreenRound, alwaysConsumeSystemBars, displayCutout.get(),
+ systemWindowInsets, stableInsets, SOFT_INPUT_ADJUST_NOTHING,
+ SYSTEM_UI_FLAG_VISIBLE, null /* typeSideMap */);
+ } else {
+ return new WindowInsets.Builder()
+ .setAlwaysConsumeSystemBars(alwaysConsumeSystemBars)
+ .setRound(isScreenRound)
+ .setSystemWindowInsets(Insets.of(systemWindowInsets))
+ .setStableInsets(Insets.of(stableInsets))
+ .setDisplayCutout(displayCutout.get()).build();
+ }
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
diff --git a/core/java/android/view/accessibility/AccessibilityNodeInfo.java b/core/java/android/view/accessibility/AccessibilityNodeInfo.java
index 454953cce33c..5fccf4031008 100644
--- a/core/java/android/view/accessibility/AccessibilityNodeInfo.java
+++ b/core/java/android/view/accessibility/AccessibilityNodeInfo.java
@@ -52,6 +52,7 @@ import android.util.LongArray;
import android.util.Pools.SynchronizedPool;
import android.util.Size;
import android.util.TypedValue;
+import android.view.SurfaceView;
import android.view.TouchDelegate;
import android.view.View;
import android.view.ViewGroup;
@@ -558,14 +559,6 @@ public class AccessibilityNodeInfo implements Parcelable {
public static final String ACTION_ARGUMENT_PRESS_AND_HOLD_DURATION_MILLIS_INT =
"android.view.accessibility.action.ARGUMENT_PRESS_AND_HOLD_DURATION_MILLIS_INT";
- /**
- * Argument to represent the IME action Id to press the returning key on a node.
- * For use with R.id.accessibilityActionImeEnter
- * @hide
- */
- public static final String ACTION_ARGUMENT_IME_ACTION_ID_INT =
- "android.view.accessibility.action.ARGUMENT_IME_ACTION_ID_INT";
-
// Focus types
/**
@@ -648,7 +641,7 @@ public class AccessibilityNodeInfo implements Parcelable {
* argument.
* <p>
* The data can be retrieved from the {@link ExtraRenderingInfo} returned by
- * {@link #getExtraRenderingInfo()} using {@link ExtraRenderingInfo#getLayoutParams},
+ * {@link #getExtraRenderingInfo()} using {@link ExtraRenderingInfo#getLayoutSize},
* {@link ExtraRenderingInfo#getTextSizeInPx()} and
* {@link ExtraRenderingInfo#getTextSizeUnit()}. For layout params, it is supported by both
* {@link TextView} and {@link ViewGroup}. For text size and unit, it is only supported by
@@ -656,7 +649,6 @@ public class AccessibilityNodeInfo implements Parcelable {
*
* @see #refreshWithExtraData(String, Bundle)
*/
-
public static final String EXTRA_DATA_RENDERING_INFO_KEY =
"android.view.accessibility.extra.DATA_RENDERING_INFO_KEY";
@@ -916,6 +908,15 @@ public class AccessibilityNodeInfo implements Parcelable {
* Find the view that has the specified focus type. The search starts from
* the view represented by this node info.
*
+ * <p>
+ * <strong>Note:</strong> If this view hierarchy has a {@link SurfaceView} embedding another
+ * view hierarchy via {@link SurfaceView#setChildSurfacePackage}, there is a limitation that
+ * this API won't be able to find the node for the view on the embedded view hierarchy. It's
+ * because views don't know about the embedded hierarchies. Instead, you could traverse all
+ * the children to find the node. Or, use {@link AccessibilityService#findFocus(int)} for
+ * {@link #FOCUS_ACCESSIBILITY} only since it has no such limitation.
+ * </p>
+ *
* @param focus The focus to find. One of {@link #FOCUS_INPUT} or
* {@link #FOCUS_ACCESSIBILITY}.
* @return The node info of the focused view or null.
@@ -937,6 +938,14 @@ public class AccessibilityNodeInfo implements Parcelable {
* Searches for the nearest view in the specified direction that can take
* the input focus.
*
+ * <p>
+ * <strong>Note:</strong> If this view hierarchy has a {@link SurfaceView} embedding another
+ * view hierarchy via {@link SurfaceView#setChildSurfacePackage}, there is a limitation that
+ * this API won't be able to find the node for the view in the specified direction on the
+ * embedded view hierarchy. It's because views don't know about the embedded hierarchies.
+ * Instead, you could traverse all the children to find the node.
+ * </p>
+ *
* @param direction The direction. Can be one of:
* {@link View#FOCUS_DOWN},
* {@link View#FOCUS_UP},
@@ -1020,8 +1029,8 @@ public class AccessibilityNodeInfo implements Parcelable {
* with this mechanism is generally expensive to retrieve, so should only be
* requested when needed. See
* {@link #EXTRA_DATA_RENDERING_INFO_KEY},
- * {@link #EXTRA_DATA_TEXT_CHARACTER_LOCATION_KEY} and
- * {@link #getAvailableExtraData()}.
+ * {@link #EXTRA_DATA_TEXT_CHARACTER_LOCATION_KEY},
+ * {@link #getAvailableExtraData()} and {@link #getExtraRenderingInfo()}.
* @param args A bundle of arguments for the request. These depend on the particular request.
*
* @return {@code true} if the refresh succeeded. {@code false} if the {@link View} represented
@@ -1723,6 +1732,13 @@ public class AccessibilityNodeInfo implements Parcelable {
* received info by calling {@link AccessibilityNodeInfo#recycle()}
* to avoid creating of multiple instances.
* </p>
+ * <p>
+ * <strong>Note:</strong> If this view hierarchy has a {@link SurfaceView} embedding another
+ * view hierarchy via {@link SurfaceView#setChildSurfacePackage}, there is a limitation that
+ * this API won't be able to find the node for the view on the embedded view hierarchy. It's
+ * because views don't know about the embedded hierarchies. Instead, you could traverse all
+ * the children to find the node.
+ * </p>
*
* @param text The searched text.
* @return A list of node info.
@@ -1754,6 +1770,13 @@ public class AccessibilityNodeInfo implements Parcelable {
* the client has to set the {@link AccessibilityServiceInfo#FLAG_REPORT_VIEW_IDS}
* flag when configuring his {@link android.accessibilityservice.AccessibilityService}.
* </p>
+ * <p>
+ * <strong>Note:</strong> If this view hierarchy has a {@link SurfaceView} embedding another
+ * view hierarchy via {@link SurfaceView#setChildSurfacePackage}, there is a limitation that
+ * this API won't be able to find the node for the view on the embedded view hierarchy. It's
+ * because views don't know about the embedded hierarchies. Instead, you could traverse all
+ * the children to find the node.
+ * </p>
*
* @param viewId The fully qualified resource name of the view id to find.
* @return A list of node info.
@@ -2405,9 +2428,13 @@ public class AccessibilityNodeInfo implements Parcelable {
}
/**
- * Gets the conformance info if the node is meant to be refreshed with extra data.
+ * Gets the {@link ExtraRenderingInfo extra rendering info} if the node is meant to be
+ * refreshed with extra data to examine rendering related accessibility issues.
+ *
+ * @return The {@link ExtraRenderingInfo extra rendering info}.
*
- * @return The conformance info.
+ * @see #EXTRA_DATA_RENDERING_INFO_KEY
+ * @see #refreshWithExtraData(String, Bundle)
*/
@Nullable
public ExtraRenderingInfo getExtraRenderingInfo() {
@@ -2415,14 +2442,15 @@ public class AccessibilityNodeInfo implements Parcelable {
}
/**
- * Sets the conformance info if the node is meant to be refreshed with extra data.
+ * Sets the extra rendering info, <code>extraRenderingInfo<code/>, if the node is meant to be
+ * refreshed with extra data.
* <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 extraRenderingInfo The conformance info.
+ * @param extraRenderingInfo The {@link ExtraRenderingInfo extra rendering info}.
* @hide
*/
public void setExtraRenderingInfo(@NonNull ExtraRenderingInfo extraRenderingInfo) {
@@ -3893,7 +3921,7 @@ public class AccessibilityNodeInfo implements Parcelable {
}
if (isBitSet(nonDefaultFields, fieldIndex++)) {
- parcel.writeValue(mExtraRenderingInfo.getLayoutParams());
+ parcel.writeValue(mExtraRenderingInfo.getLayoutSize());
parcel.writeFloat(mExtraRenderingInfo.getTextSizeInPx());
parcel.writeInt(mExtraRenderingInfo.getTextSizeUnit());
}
@@ -4157,7 +4185,7 @@ public class AccessibilityNodeInfo implements Parcelable {
if (isBitSet(nonDefaultFields, fieldIndex++)) {
if (mExtraRenderingInfo != null) mExtraRenderingInfo.recycle();
mExtraRenderingInfo = ExtraRenderingInfo.obtain();
- mExtraRenderingInfo.mLayoutParams = (Size) parcel.readValue(null);
+ mExtraRenderingInfo.mLayoutSize = (Size) parcel.readValue(null);
mExtraRenderingInfo.mTextSizeInPx = parcel.readFloat();
mExtraRenderingInfo.mTextSizeUnit = parcel.readInt();
}
@@ -4937,10 +4965,11 @@ public class AccessibilityNodeInfo implements Parcelable {
new AccessibilityAction(R.id.accessibilityActionPressAndHold);
/**
- * Action to send an ime action which is from
- * {@link android.view.inputmethod.EditorInfo#actionId}. This action would be
+ * Action to send an ime actionId which is from
+ * {@link android.view.inputmethod.EditorInfo#actionId}. This ime actionId sets by
+ * {@link TextView#setImeActionLabel(CharSequence, int)}, or it would be
* {@link android.view.inputmethod.EditorInfo#IME_ACTION_UNSPECIFIED} if no specific
- * actionId defined. A node should expose this action only for views that are currently
+ * actionId has set. A node should expose this action only for views that are currently
* with input focus and editable.
*/
@NonNull public static final AccessibilityAction ACTION_IME_ENTER =
@@ -5776,7 +5805,7 @@ public class AccessibilityNodeInfo implements Parcelable {
private static final SynchronizedPool<ExtraRenderingInfo> sPool =
new SynchronizedPool<>(MAX_POOL_SIZE);
- private Size mLayoutParams;
+ private Size mLayoutSize;
private float mTextSizeInPx = UNDEFINED_VALUE;
private int mTextSizeUnit = UNDEFINED_VALUE;
@@ -5796,32 +5825,36 @@ public class AccessibilityNodeInfo implements Parcelable {
/** Obtains a pooled instance that is a clone of another one. */
private static ExtraRenderingInfo obtain(ExtraRenderingInfo other) {
ExtraRenderingInfo extraRenderingInfo = ExtraRenderingInfo.obtain();
- extraRenderingInfo.mLayoutParams = other.mLayoutParams;
+ extraRenderingInfo.mLayoutSize = other.mLayoutSize;
extraRenderingInfo.mTextSizeInPx = other.mTextSizeInPx;
extraRenderingInfo.mTextSizeUnit = other.mTextSizeUnit;
return extraRenderingInfo;
}
/**
- * Creates a new conformance info of a view, and this new instance is initialized from
+ * Creates a new rendering info of a view, and this new instance is initialized from
* the given <code>other</code>.
*
* @param other The instance to clone.
*/
private ExtraRenderingInfo(@Nullable ExtraRenderingInfo other) {
if (other != null) {
- mLayoutParams = other.mLayoutParams;
+ mLayoutSize = other.mLayoutSize;
mTextSizeInPx = other.mTextSizeInPx;
mTextSizeUnit = other.mTextSizeUnit;
}
}
/**
+ * Gets the size object containing the height and the width of layout params if the node is
+ * a {@link ViewGroup} or a {@link TextView}, or null otherwise. Useful for accessibility
+ * scanning tool to understand whether the text is scalable and fits the view or not.
+ *
* @return a {@link Size} stores layout height and layout width of the view,
* or null otherwise.
*/
- public @Nullable Size getLayoutParams() {
- return mLayoutParams;
+ public @Nullable Size getLayoutSize() {
+ return mLayoutSize;
}
/**
@@ -5831,11 +5864,15 @@ public class AccessibilityNodeInfo implements Parcelable {
* @param height The layout height.
* @hide
*/
- public void setLayoutParams(int width, int height) {
- mLayoutParams = new Size(width, height);
+ public void setLayoutSize(int width, int height) {
+ mLayoutSize = new Size(width, height);
}
/**
+ * Gets the text size if the node is a {@link TextView}, or -1 otherwise. Useful for
+ * accessibility scanning tool to understand whether the text is scalable and fits the view
+ * or not.
+ *
* @return the text size of a {@code TextView}, or -1 otherwise.
*/
public float getTextSizeInPx() {
@@ -5853,6 +5890,11 @@ public class AccessibilityNodeInfo implements Parcelable {
}
/**
+ * Gets the text size unit if the node is a {@link TextView}, or -1 otherwise.
+ * Text size returned from {@link #getTextSizeInPx} in raw pixels may scale by factors and
+ * convert from other units. Useful for accessibility scanning tool to understand whether
+ * the text is scalable and fits the view or not.
+ *
* @return the text size unit which type is {@link TypedValue#TYPE_DIMENSION} of a
* {@code TextView}, or -1 otherwise.
*
@@ -5883,7 +5925,7 @@ public class AccessibilityNodeInfo implements Parcelable {
}
private void clear() {
- mLayoutParams = null;
+ mLayoutSize = null;
mTextSizeInPx = UNDEFINED_VALUE;
mTextSizeUnit = UNDEFINED_VALUE;
}
diff --git a/core/java/android/view/contentcapture/ContentCaptureManager.java b/core/java/android/view/contentcapture/ContentCaptureManager.java
index b7b54c8c74b9..b9889276ae0b 100644
--- a/core/java/android/view/contentcapture/ContentCaptureManager.java
+++ b/core/java/android/view/contentcapture/ContentCaptureManager.java
@@ -217,6 +217,15 @@ public final class ContentCaptureManager {
public static final int DATA_SHARE_ERROR_TIMEOUT_INTERRUPTED = 3;
/** @hide */
+ @IntDef(flag = false, value = {
+ DATA_SHARE_ERROR_UNKNOWN,
+ DATA_SHARE_ERROR_CONCURRENT_REQUEST,
+ DATA_SHARE_ERROR_TIMEOUT_INTERRUPTED
+ })
+ @Retention(RetentionPolicy.SOURCE)
+ public @interface DataShareError {}
+
+ /** @hide */
public static final int RESULT_CODE_OK = 0;
/** @hide */
public static final int RESULT_CODE_TRUE = 1;
diff --git a/core/java/android/view/contentcapture/DataShareWriteAdapter.java b/core/java/android/view/contentcapture/DataShareWriteAdapter.java
index 2beaededf8b1..3b5b756553d9 100644
--- a/core/java/android/view/contentcapture/DataShareWriteAdapter.java
+++ b/core/java/android/view/contentcapture/DataShareWriteAdapter.java
@@ -18,6 +18,7 @@ package android.view.contentcapture;
import android.annotation.NonNull;
import android.os.ParcelFileDescriptor;
+import android.view.contentcapture.ContentCaptureManager.DataShareError;
/** Adapter class used by apps to share data with the Content Capture service. */
public interface DataShareWriteAdapter {
@@ -42,7 +43,7 @@ public interface DataShareWriteAdapter {
*
* @param errorCode the error code corresponding to an ERROR_* value.
*/
- default void onError(int errorCode) {
+ default void onError(@DataShareError int errorCode) {
/* do nothing - stub */
}
}
diff --git a/core/java/android/widget/Editor.java b/core/java/android/widget/Editor.java
index 13c1f67ef85b..816612f1dcc7 100644
--- a/core/java/android/widget/Editor.java
+++ b/core/java/android/widget/Editor.java
@@ -4587,7 +4587,8 @@ public class Editor {
protected int mHorizontalGravity;
// Offsets the hotspot point up, so that cursor is not hidden by the finger when moving up
private float mTouchOffsetY;
- // Where the touch position should be on the handle to ensure a maximum cursor visibility
+ // Where the touch position should be on the handle to ensure a maximum cursor visibility.
+ // This is the distance in pixels from the top of the handle view.
private float mIdealVerticalOffset;
// Parent's (TextView) previous position in window
private int mLastParentX, mLastParentY;
@@ -4612,6 +4613,11 @@ public class Editor {
// when magnifier is used.
private float mTextViewScaleX;
private float mTextViewScaleY;
+ /**
+ * The vertical distance in pixels from finger to the cursor Y while dragging.
+ * See {@link Editor.InsertionPointCursorController#getLineDuringDrag}.
+ */
+ private final int mIdealFingerToCursorOffset;
private HandleView(Drawable drawableLtr, Drawable drawableRtl, final int id) {
super(mTextView.getContext());
@@ -4633,12 +4639,17 @@ public class Editor {
final int handleHeight = getPreferredHeight();
mTouchOffsetY = -0.3f * handleHeight;
mIdealVerticalOffset = 0.7f * handleHeight;
+ mIdealFingerToCursorOffset = (int)(mIdealVerticalOffset - mTouchOffsetY);
}
public float getIdealVerticalOffset() {
return mIdealVerticalOffset;
}
+ final int getIdealFingerToCursorOffset() {
+ return mIdealFingerToCursorOffset;
+ }
+
void setDrawables(final Drawable drawableLtr, final Drawable drawableRtl) {
mDrawableLtr = drawableLtr;
mDrawableRtl = drawableRtl;
@@ -6123,36 +6134,34 @@ public class Editor {
*/
private int getLineDuringDrag(MotionEvent event) {
final Layout layout = mTextView.getLayout();
- if (mTouchState.isOnHandle()) {
- // The drag was initiated from the handle, so no need to apply the snap logic. See
- // InsertionHandleView.touchThrough().
+ if (mPrevLineDuringDrag == UNSET_LINE) {
return getCurrentLineAdjustedForSlop(layout, mPrevLineDuringDrag, event.getY());
}
+ // In case of touch through on handle (when isOnHandle() returns true), event.getY()
+ // returns the midpoint of the cursor vertical bar, while event.getRawY() returns the
+ // finger location on the screen. See {@link InsertionHandleView#touchThrough}.
+ final float fingerY = mTouchState.isOnHandle()
+ ? event.getRawY() - mTextView.getLocationOnScreen()[1]
+ : event.getY();
+ final float cursorY = fingerY - getHandle().getIdealFingerToCursorOffset();
+ int line = getCurrentLineAdjustedForSlop(layout, mPrevLineDuringDrag, cursorY);
if (mIsTouchSnappedToHandleDuringDrag) {
- float cursorY = event.getY() - getHandle().getIdealVerticalOffset();
- return getCurrentLineAdjustedForSlop(layout, mPrevLineDuringDrag, cursorY);
- }
- int line = getCurrentLineAdjustedForSlop(layout, mPrevLineDuringDrag, event.getY());
- if (mPrevLineDuringDrag == UNSET_LINE || line <= mPrevLineDuringDrag) {
- // User's finger is on the same line or moving up; continue positioning the cursor
- // directly at the touch location.
+ // Just returns the line hit by cursor Y when already snapped.
return line;
}
- // User's finger is moving downwards; delay jumping to the lower line to allow the
- // touch to move to the handle.
- float cursorY = event.getY() - getHandle().getIdealVerticalOffset();
- line = getCurrentLineAdjustedForSlop(layout, mPrevLineDuringDrag, cursorY);
if (line < mPrevLineDuringDrag) {
- return mPrevLineDuringDrag;
+ // The cursor Y aims too high & not yet snapped, check the finger Y.
+ // If finger Y is moving downwards, don't jump to lower line (until snap).
+ // If finger Y is moving upwards, can jump to upper line.
+ return Math.min(mPrevLineDuringDrag,
+ getCurrentLineAdjustedForSlop(layout, mPrevLineDuringDrag, fingerY));
}
- // User's finger is now over the handle, at the ideal offset from the cursor. From now
- // on, position the cursor higher up from the actual touch location so that the user's
- // finger stays "snapped" to the handle. This provides better visibility of the text.
+ // The cursor Y aims not too high, so snap!
mIsTouchSnappedToHandleDuringDrag = true;
if (TextView.DEBUG_CURSOR) {
logCursor("InsertionPointCursorController",
- "snapped touch to handle: eventY=%d, cursorY=%d, mLastLine=%d, line=%d",
- (int) event.getY(), (int) cursorY, mPrevLineDuringDrag, line);
+ "snapped touch to handle: fingerY=%d, cursorY=%d, mLastLine=%d, line=%d",
+ (int) fingerY, (int) cursorY, mPrevLineDuringDrag, line);
}
return line;
}
@@ -6252,7 +6261,7 @@ public class Editor {
}
}
- private InsertionHandleView getHandle() {
+ public InsertionHandleView getHandle() {
if (mHandle == null) {
loadHandleDrawables(false /* overwrite */);
mHandle = new InsertionHandleView(mSelectHandleCenter);
diff --git a/core/java/android/widget/TextView.java b/core/java/android/widget/TextView.java
index f3243aaf5b7d..0d820654377c 100644
--- a/core/java/android/widget/TextView.java
+++ b/core/java/android/widget/TextView.java
@@ -11763,13 +11763,8 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
if (isTextEditable() && isFocused()) {
CharSequence imeActionLabel = mContext.getResources().getString(
com.android.internal.R.string.keyboardview_keycode_enter);
- if (getImeActionId() != 0 && getImeActionLabel() != null) {
+ if (getImeActionLabel() != null) {
imeActionLabel = getImeActionLabel();
- final int imeActionId = getImeActionId();
- // put ime action id into the extra data with ACTION_ARGUMENT_IME_ACTION_ID_INT.
- final Bundle argument = info.getExtras();
- argument.putInt(AccessibilityNodeInfo.ACTION_ARGUMENT_IME_ACTION_ID_INT,
- imeActionId);
}
AccessibilityNodeInfo.AccessibilityAction action =
new AccessibilityNodeInfo.AccessibilityAction(
@@ -11881,7 +11876,7 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
if (extraDataKey.equals(AccessibilityNodeInfo.EXTRA_DATA_RENDERING_INFO_KEY)) {
final AccessibilityNodeInfo.ExtraRenderingInfo extraRenderingInfo =
AccessibilityNodeInfo.ExtraRenderingInfo.obtain();
- extraRenderingInfo.setLayoutParams(getLayoutParams().width, getLayoutParams().height);
+ extraRenderingInfo.setLayoutSize(getLayoutParams().width, getLayoutParams().height);
extraRenderingInfo.setTextSizeInPx(getTextSize());
extraRenderingInfo.setTextSizeUnit(getTextSizeUnit());
info.setExtraRenderingInfo(extraRenderingInfo);
@@ -12100,13 +12095,7 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
} return true;
case R.id.accessibilityActionImeEnter: {
if (isFocused() && isTextEditable()) {
- final int imeActionId = (arguments != null) ? arguments.getInt(
- AccessibilityNodeInfo.ACTION_ARGUMENT_IME_ACTION_ID_INT,
- EditorInfo.IME_ACTION_UNSPECIFIED)
- : EditorInfo.IME_ACTION_UNSPECIFIED;
- if (imeActionId == getImeActionId()) {
- onEditorAction(imeActionId);
- }
+ onEditorAction(getImeActionId());
}
} return true;
default: {
diff --git a/core/java/com/android/internal/accessibility/common/ShortcutConstants.java b/core/java/com/android/internal/accessibility/common/ShortcutConstants.java
new file mode 100644
index 000000000000..79b34c05bf87
--- /dev/null
+++ b/core/java/com/android/internal/accessibility/common/ShortcutConstants.java
@@ -0,0 +1,136 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.internal.accessibility.common;
+
+import android.annotation.IntDef;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+
+/**
+ * Collection of common constants for accessibility shortcut.
+ */
+public final class ShortcutConstants {
+ private ShortcutConstants() {}
+
+ public static final char SERVICES_SEPARATOR = ':';
+
+ /**
+ * Annotation for different user shortcut type UI type.
+ *
+ * {@code DEFAULT} for displaying default value.
+ * {@code SOFTWARE} for displaying specifying the accessibility services or features which
+ * choose accessibility button in the navigation bar as preferred shortcut.
+ * {@code HARDWARE} for displaying specifying the accessibility services or features which
+ * choose accessibility shortcut as preferred shortcut.
+ * {@code TRIPLETAP} for displaying specifying magnification to be toggled via quickly
+ * tapping screen 3 times as preferred shortcut.
+ */
+ @Retention(RetentionPolicy.SOURCE)
+ @IntDef({
+ UserShortcutType.DEFAULT,
+ UserShortcutType.SOFTWARE,
+ UserShortcutType.HARDWARE,
+ UserShortcutType.TRIPLETAP,
+ })
+ public @interface UserShortcutType {
+ int DEFAULT = 0;
+ int SOFTWARE = 1; // 1 << 0
+ int HARDWARE = 2; // 1 << 1
+ int TRIPLETAP = 4; // 1 << 2
+ }
+
+ /**
+ * Annotation for different accessibilityService fragment UI type.
+ *
+ * {@code LEGACY} for displaying appearance aligned with sdk version Q accessibility service
+ * page, but only hardware shortcut allowed and under service in version Q or early.
+ * {@code INVISIBLE} for displaying appearance without switch bar.
+ * {@code INTUITIVE} for displaying appearance with version R accessibility design.
+ * {@code BOUNCE} for displaying appearance with pop-up action.
+ */
+ @Retention(RetentionPolicy.SOURCE)
+ @IntDef({
+ AccessibilityServiceFragmentType.LEGACY,
+ AccessibilityServiceFragmentType.INVISIBLE,
+ AccessibilityServiceFragmentType.INTUITIVE,
+ AccessibilityServiceFragmentType.BOUNCE,
+ })
+ public @interface AccessibilityServiceFragmentType {
+ int LEGACY = 0;
+ int INVISIBLE = 1;
+ int INTUITIVE = 2;
+ int BOUNCE = 3;
+ }
+
+ /**
+ * Annotation for different shortcut target.
+ */
+ @Retention(RetentionPolicy.SOURCE)
+ @IntDef({
+ TargetType.ACCESSIBILITY_SERVICE,
+ TargetType.ACCESSIBILITY_ACTIVITY,
+ TargetType.WHITE_LISTING,
+ })
+ public @interface TargetType {
+ int ACCESSIBILITY_SERVICE = 0;
+ int ACCESSIBILITY_ACTIVITY = 1;
+ int WHITE_LISTING = 2;
+ }
+
+ /**
+ * Annotation for different shortcut menu mode.
+ *
+ * {@code LAUNCH} for clicking list item to trigger the service callback.
+ * {@code EDIT} for clicking list item and save button to disable the service.
+ */
+ @Retention(RetentionPolicy.SOURCE)
+ @IntDef({
+ ShortcutMenuMode.LAUNCH,
+ ShortcutMenuMode.EDIT,
+ })
+ public @interface ShortcutMenuMode {
+ int LAUNCH = 0;
+ int EDIT = 1;
+ }
+
+ /**
+ * Annotation for align the element index of white listing feature
+ * {@code WHITE_LISTING_FEATURES}.
+ *
+ * {@code COMPONENT_ID} is to get the service component name.
+ * {@code LABEL_ID} is to get the service label text.
+ * {@code ICON_ID} is to get the service icon.
+ * {@code FRAGMENT_TYPE} is to get the service fragment type.
+ * {@code SETTINGS_KEY} is to get the service settings key.
+ */
+ @Retention(RetentionPolicy.SOURCE)
+ @IntDef({
+ WhiteListingFeatureElementIndex.COMPONENT_ID,
+ WhiteListingFeatureElementIndex.LABEL_ID,
+ WhiteListingFeatureElementIndex.ICON_ID,
+ WhiteListingFeatureElementIndex.FRAGMENT_TYPE,
+ WhiteListingFeatureElementIndex.SETTINGS_KEY,
+ })
+ public @interface WhiteListingFeatureElementIndex {
+ int COMPONENT_ID = 0;
+ int LABEL_ID = 1;
+ int ICON_ID = 2;
+ int FRAGMENT_TYPE = 3;
+ int SETTINGS_KEY = 4;
+ }
+}
diff --git a/core/java/com/android/internal/accessibility/util/AccessibilityUtils.java b/core/java/com/android/internal/accessibility/util/AccessibilityUtils.java
new file mode 100644
index 000000000000..d0ead5e3b6ce
--- /dev/null
+++ b/core/java/com/android/internal/accessibility/util/AccessibilityUtils.java
@@ -0,0 +1,131 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.internal.accessibility.util;
+import static com.android.internal.accessibility.common.ShortcutConstants.AccessibilityServiceFragmentType;
+import static com.android.internal.accessibility.common.ShortcutConstants.SERVICES_SEPARATOR;
+
+import android.accessibilityservice.AccessibilityServiceInfo;
+import android.content.ComponentName;
+import android.content.Context;
+import android.os.Build;
+import android.os.UserHandle;
+import android.provider.Settings;
+import android.text.TextUtils;
+import android.util.ArraySet;
+
+import java.util.Collections;
+import java.util.HashSet;
+import java.util.Set;
+
+/**
+ * Collection of utilities for accessibility service.
+ */
+public final class AccessibilityUtils {
+ private AccessibilityUtils() {}
+
+ /**
+ * Returns the set of enabled accessibility services for userId. If there are no
+ * services, it returns the unmodifiable {@link Collections#emptySet()}.
+ */
+ public static Set<ComponentName> getEnabledServicesFromSettings(Context context, int userId) {
+ final String enabledServicesSetting = Settings.Secure.getStringForUser(
+ context.getContentResolver(), Settings.Secure.ENABLED_ACCESSIBILITY_SERVICES,
+ userId);
+ if (TextUtils.isEmpty(enabledServicesSetting)) {
+ return Collections.emptySet();
+ }
+
+ final Set<ComponentName> enabledServices = new HashSet<>();
+ final TextUtils.StringSplitter colonSplitter =
+ new TextUtils.SimpleStringSplitter(SERVICES_SEPARATOR);
+ colonSplitter.setString(enabledServicesSetting);
+
+ for (String componentNameString : colonSplitter) {
+ final ComponentName enabledService = ComponentName.unflattenFromString(
+ componentNameString);
+ if (enabledService != null) {
+ enabledServices.add(enabledService);
+ }
+ }
+
+ return enabledServices;
+ }
+
+ /**
+ * Changes an accessibility component's state.
+ */
+ public static void setAccessibilityServiceState(Context context, ComponentName componentName,
+ boolean enabled) {
+ setAccessibilityServiceState(context, componentName, enabled, UserHandle.myUserId());
+ }
+
+ /**
+ * Changes an accessibility component's state for {@param userId}.
+ */
+ public static void setAccessibilityServiceState(Context context, ComponentName componentName,
+ boolean enabled, int userId) {
+ Set<ComponentName> enabledServices = getEnabledServicesFromSettings(
+ context, userId);
+
+ if (enabledServices.isEmpty()) {
+ enabledServices = new ArraySet<>(/* capacity= */ 1);
+ }
+
+ if (enabled) {
+ enabledServices.add(componentName);
+ } else {
+ enabledServices.remove(componentName);
+ }
+
+ final StringBuilder enabledServicesBuilder = new StringBuilder();
+ for (ComponentName enabledService : enabledServices) {
+ enabledServicesBuilder.append(enabledService.flattenToString());
+ enabledServicesBuilder.append(
+ SERVICES_SEPARATOR);
+ }
+
+ final int enabledServicesBuilderLength = enabledServicesBuilder.length();
+ if (enabledServicesBuilderLength > 0) {
+ enabledServicesBuilder.deleteCharAt(enabledServicesBuilderLength - 1);
+ }
+
+ Settings.Secure.putStringForUser(context.getContentResolver(),
+ Settings.Secure.ENABLED_ACCESSIBILITY_SERVICES,
+ enabledServicesBuilder.toString(), userId);
+ }
+
+ /**
+ * Gets the corresponding fragment type of a given accessibility service.
+ *
+ * @param accessibilityServiceInfo The accessibilityService's info.
+ * @return int from {@link AccessibilityServiceFragmentType}.
+ */
+ public static @AccessibilityServiceFragmentType int getAccessibilityServiceFragmentType(
+ AccessibilityServiceInfo accessibilityServiceInfo) {
+ final int targetSdk = accessibilityServiceInfo.getResolveInfo()
+ .serviceInfo.applicationInfo.targetSdkVersion;
+ final boolean requestA11yButton = (accessibilityServiceInfo.flags
+ & AccessibilityServiceInfo.FLAG_REQUEST_ACCESSIBILITY_BUTTON) != 0;
+
+ if (targetSdk <= Build.VERSION_CODES.Q) {
+ return AccessibilityServiceFragmentType.LEGACY;
+ }
+ return requestA11yButton
+ ? AccessibilityServiceFragmentType.INVISIBLE
+ : AccessibilityServiceFragmentType.INTUITIVE;
+ }
+}
diff --git a/core/java/com/android/internal/accessibility/util/ShortcutUtils.java b/core/java/com/android/internal/accessibility/util/ShortcutUtils.java
new file mode 100644
index 000000000000..717e78078b1c
--- /dev/null
+++ b/core/java/com/android/internal/accessibility/util/ShortcutUtils.java
@@ -0,0 +1,185 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.internal.accessibility.util;
+import static android.view.accessibility.AccessibilityManager.ACCESSIBILITY_BUTTON;
+import static android.view.accessibility.AccessibilityManager.ACCESSIBILITY_SHORTCUT_KEY;
+
+import static com.android.internal.accessibility.common.ShortcutConstants.SERVICES_SEPARATOR;
+import static com.android.internal.accessibility.common.ShortcutConstants.UserShortcutType;
+
+import android.annotation.NonNull;
+import android.content.Context;
+import android.provider.Settings;
+import android.text.TextUtils;
+import android.view.accessibility.AccessibilityManager.ShortcutType;
+
+import java.util.StringJoiner;
+
+/**
+ * Collection of utilities for accessibility shortcut.
+ */
+public final class ShortcutUtils {
+ private ShortcutUtils() {}
+
+ private static final TextUtils.SimpleStringSplitter sStringColonSplitter =
+ new TextUtils.SimpleStringSplitter(SERVICES_SEPARATOR);
+
+ /**
+ * Opts in component name into colon-separated {@link UserShortcutType}
+ * key's string in Settings.
+ *
+ * @param context The current context.
+ * @param shortcutType The preferred shortcut type user selected.
+ * @param componentId The component id that need to be opted out from Settings.
+ */
+ public static void optInValueToSettings(Context context, @UserShortcutType int shortcutType,
+ String componentId) {
+ final StringJoiner joiner = new StringJoiner(String.valueOf(SERVICES_SEPARATOR));
+ final String targetKey = convertToKey(shortcutType);
+ final String targetString = Settings.Secure.getString(context.getContentResolver(),
+ targetKey);
+
+ if (hasValueInSettings(context, shortcutType, componentId)) {
+ return;
+ }
+
+ if (!TextUtils.isEmpty(targetString)) {
+ joiner.add(targetString);
+ }
+ joiner.add(componentId);
+
+ Settings.Secure.putString(context.getContentResolver(), targetKey, joiner.toString());
+ }
+
+ /**
+ * Opts out component name into colon-separated {@code shortcutType} key's string in Settings.
+ *
+ * @param context The current context.
+ * @param shortcutType The preferred shortcut type user selected.
+ * @param componentId The component id that need to be opted out from Settings.
+ */
+ public static void optOutValueFromSettings(
+ Context context, @UserShortcutType int shortcutType, String componentId) {
+ final StringJoiner joiner = new StringJoiner(String.valueOf(SERVICES_SEPARATOR));
+ final String targetsKey = convertToKey(shortcutType);
+ final String targetsValue = Settings.Secure.getString(context.getContentResolver(),
+ targetsKey);
+
+ if (TextUtils.isEmpty(targetsValue)) {
+ return;
+ }
+
+ sStringColonSplitter.setString(targetsValue);
+ while (sStringColonSplitter.hasNext()) {
+ final String id = sStringColonSplitter.next();
+ if (TextUtils.isEmpty(id) || componentId.equals(id)) {
+ continue;
+ }
+ joiner.add(id);
+ }
+
+ Settings.Secure.putString(context.getContentResolver(), targetsKey, joiner.toString());
+ }
+
+ /**
+ * Returns if component name existed in one of {@code shortcutTypes} string in Settings.
+ *
+ * @param context The current context.
+ * @param shortcutTypes A combination of {@link UserShortcutType}.
+ * @param componentId The component name that need to be checked existed in Settings.
+ * @return {@code true} if componentName existed in Settings.
+ */
+ public static boolean hasValuesInSettings(Context context, int shortcutTypes,
+ @NonNull String componentId) {
+ boolean exist = false;
+ if ((shortcutTypes & UserShortcutType.SOFTWARE) == UserShortcutType.SOFTWARE) {
+ exist = hasValueInSettings(context, UserShortcutType.SOFTWARE, componentId);
+ }
+ if (((shortcutTypes & UserShortcutType.HARDWARE) == UserShortcutType.HARDWARE)) {
+ exist |= hasValueInSettings(context, UserShortcutType.HARDWARE, componentId);
+ }
+ return exist;
+ }
+
+
+ /**
+ * Returns if component name existed in Settings.
+ *
+ * @param context The current context.
+ * @param shortcutType The preferred shortcut type user selected.
+ * @param componentId The component id that need to be checked existed in Settings.
+ * @return {@code true} if componentName existed in Settings.
+ */
+ public static boolean hasValueInSettings(Context context, @UserShortcutType int shortcutType,
+ @NonNull String componentId) {
+ final String targetKey = convertToKey(shortcutType);
+ final String targetString = Settings.Secure.getString(context.getContentResolver(),
+ targetKey);
+
+ if (TextUtils.isEmpty(targetString)) {
+ return false;
+ }
+
+ sStringColonSplitter.setString(targetString);
+ while (sStringColonSplitter.hasNext()) {
+ final String id = sStringColonSplitter.next();
+ if (componentId.equals(id)) {
+ return true;
+ }
+ }
+
+ return false;
+ }
+
+ /**
+ * Converts {@link UserShortcutType} to key in Settings.
+ *
+ * @param type The shortcut type.
+ * @return Mapping key in Settings.
+ */
+ public static String convertToKey(@UserShortcutType int type) {
+ switch (type) {
+ case UserShortcutType.SOFTWARE:
+ return Settings.Secure.ACCESSIBILITY_BUTTON_TARGET_COMPONENT;
+ case UserShortcutType.HARDWARE:
+ return Settings.Secure.ACCESSIBILITY_SHORTCUT_TARGET_SERVICE;
+ case UserShortcutType.TRIPLETAP:
+ return Settings.Secure.ACCESSIBILITY_DISPLAY_MAGNIFICATION_ENABLED;
+ default:
+ throw new IllegalArgumentException(
+ "Unsupported user shortcut type: " + type);
+ }
+ }
+
+ /**
+ * Converts {@link ShortcutType} to {@link UserShortcutType}.
+ *
+ * @param type The shortcut type.
+ * @return {@link UserShortcutType}.
+ */
+ public static @UserShortcutType int convertToUserType(@ShortcutType int type) {
+ switch (type) {
+ case ACCESSIBILITY_BUTTON:
+ return UserShortcutType.SOFTWARE;
+ case ACCESSIBILITY_SHORTCUT_KEY:
+ return UserShortcutType.HARDWARE;
+ default:
+ throw new IllegalArgumentException(
+ "Unsupported shortcut type:" + type);
+ }
+ }
+}
diff --git a/core/java/com/android/internal/app/AbstractMultiProfilePagerAdapter.java b/core/java/com/android/internal/app/AbstractMultiProfilePagerAdapter.java
index bcf731d993df..d50826f815a0 100644
--- a/core/java/com/android/internal/app/AbstractMultiProfilePagerAdapter.java
+++ b/core/java/com/android/internal/app/AbstractMultiProfilePagerAdapter.java
@@ -299,11 +299,8 @@ public abstract class AbstractMultiProfilePagerAdapter extends PagerAdapter {
.createEvent(DevicePolicyEnums.RESOLVER_EMPTY_STATE_WORK_APPS_DISABLED)
.setStrings(getMetricsCategory())
.write();
- showEmptyState(activeListAdapter,
- R.drawable.ic_work_apps_off,
- R.string.resolver_turn_on_work_apps,
- R.string.resolver_turn_on_work_apps_explanation,
- (View.OnClickListener) v -> {
+ showWorkProfileOffEmptyState(activeListAdapter,
+ v -> {
ProfileDescriptor descriptor = getItem(
userHandleToPageIndex(activeListAdapter.getUserHandle()));
showSpinner(descriptor.getEmptyStateView());
@@ -319,27 +316,29 @@ public abstract class AbstractMultiProfilePagerAdapter extends PagerAdapter {
DevicePolicyEnums.RESOLVER_EMPTY_STATE_NO_SHARING_TO_PERSONAL)
.setStrings(getMetricsCategory())
.write();
- showEmptyState(activeListAdapter,
- R.drawable.ic_sharing_disabled,
- R.string.resolver_cant_share_with_personal_apps,
- R.string.resolver_cant_share_cross_profile_explanation);
+ showNoWorkToPersonalIntentsEmptyState(activeListAdapter);
} else {
DevicePolicyEventLogger.createEvent(
DevicePolicyEnums.RESOLVER_EMPTY_STATE_NO_SHARING_TO_WORK)
.setStrings(getMetricsCategory())
.write();
- showEmptyState(activeListAdapter,
- R.drawable.ic_sharing_disabled,
- R.string.resolver_cant_share_with_work_apps,
- R.string.resolver_cant_share_cross_profile_explanation);
+ showNoPersonalToWorkIntentsEmptyState(activeListAdapter);
}
return false;
}
}
- showListView(activeListAdapter);
return activeListAdapter.rebuildList(doPostProcessing);
}
+ protected abstract void showWorkProfileOffEmptyState(
+ ResolverListAdapter activeListAdapter, View.OnClickListener listener);
+
+ protected abstract void showNoPersonalToWorkIntentsEmptyState(
+ ResolverListAdapter activeListAdapter);
+
+ protected abstract void showNoWorkToPersonalIntentsEmptyState(
+ ResolverListAdapter activeListAdapter);
+
void showEmptyState(ResolverListAdapter listAdapter) {
UserHandle listUserHandle = listAdapter.getUserHandle();
if (UserHandle.myUserId() == listUserHandle.getIdentifier()
@@ -353,16 +352,16 @@ public abstract class AbstractMultiProfilePagerAdapter extends PagerAdapter {
showEmptyState(listAdapter,
R.drawable.ic_no_apps,
R.string.resolver_no_apps_available,
- R.string.resolver_no_apps_available_explanation);
+ /* subtitleRes */ 0);
}
}
- private void showEmptyState(ResolverListAdapter activeListAdapter,
+ protected void showEmptyState(ResolverListAdapter activeListAdapter,
@DrawableRes int iconRes, @StringRes int titleRes, @StringRes int subtitleRes) {
showEmptyState(activeListAdapter, iconRes, titleRes, subtitleRes, /* buttonOnClick */ null);
}
- private void showEmptyState(ResolverListAdapter activeListAdapter,
+ protected void showEmptyState(ResolverListAdapter activeListAdapter,
@DrawableRes int iconRes, @StringRes int titleRes, @StringRes int subtitleRes,
View.OnClickListener buttonOnClick) {
ProfileDescriptor descriptor = getItem(
@@ -379,11 +378,18 @@ public abstract class AbstractMultiProfilePagerAdapter extends PagerAdapter {
title.setText(titleRes);
TextView subtitle = emptyStateView.findViewById(R.id.resolver_empty_state_subtitle);
- subtitle.setText(subtitleRes);
+ if (subtitleRes != 0) {
+ subtitle.setVisibility(View.VISIBLE);
+ subtitle.setText(subtitleRes);
+ } else {
+ subtitle.setVisibility(View.GONE);
+ }
Button button = emptyStateView.findViewById(R.id.resolver_empty_state_button);
button.setVisibility(buttonOnClick != null ? View.VISIBLE : View.GONE);
button.setOnClickListener(buttonOnClick);
+
+ activeListAdapter.markTabLoaded();
}
private void showSpinner(View emptyStateView) {
@@ -403,7 +409,7 @@ public abstract class AbstractMultiProfilePagerAdapter extends PagerAdapter {
emptyStateView.findViewById(R.id.resolver_empty_state_progress).setVisibility(View.GONE);
}
- private void showListView(ResolverListAdapter activeListAdapter) {
+ protected void showListView(ResolverListAdapter activeListAdapter) {
ProfileDescriptor descriptor = getItem(
userHandleToPageIndex(activeListAdapter.getUserHandle()));
descriptor.rootView.findViewById(R.id.resolver_list).setVisibility(View.VISIBLE);
diff --git a/core/java/com/android/internal/app/AccessibilityButtonChooserActivity.java b/core/java/com/android/internal/app/AccessibilityButtonChooserActivity.java
index 86d2ed6c15c0..c40864131a2e 100644
--- a/core/java/com/android/internal/app/AccessibilityButtonChooserActivity.java
+++ b/core/java/com/android/internal/app/AccessibilityButtonChooserActivity.java
@@ -22,16 +22,26 @@ import static android.view.accessibility.AccessibilityManager.ShortcutType;
import static com.android.internal.accessibility.AccessibilityShortcutController.COLOR_INVERSION_COMPONENT_NAME;
import static com.android.internal.accessibility.AccessibilityShortcutController.DALTONIZER_COMPONENT_NAME;
import static com.android.internal.accessibility.AccessibilityShortcutController.MAGNIFICATION_CONTROLLER_NAME;
-import static com.android.internal.app.AccessibilityButtonChooserActivity.WhiteListingFeatureElementIndex.COMPONENT_ID;
-import static com.android.internal.app.AccessibilityButtonChooserActivity.WhiteListingFeatureElementIndex.FRAGMENT_TYPE;
-import static com.android.internal.app.AccessibilityButtonChooserActivity.WhiteListingFeatureElementIndex.ICON_ID;
-import static com.android.internal.app.AccessibilityButtonChooserActivity.WhiteListingFeatureElementIndex.LABEL_ID;
-import static com.android.internal.app.AccessibilityButtonChooserActivity.WhiteListingFeatureElementIndex.SETTINGS_KEY;
+import static com.android.internal.accessibility.common.ShortcutConstants.AccessibilityServiceFragmentType;
+import static com.android.internal.accessibility.common.ShortcutConstants.ShortcutMenuMode;
+import static com.android.internal.accessibility.common.ShortcutConstants.TargetType;
+import static com.android.internal.accessibility.common.ShortcutConstants.UserShortcutType;
+import static com.android.internal.accessibility.common.ShortcutConstants.UserShortcutType.HARDWARE;
+import static com.android.internal.accessibility.common.ShortcutConstants.WhiteListingFeatureElementIndex.COMPONENT_ID;
+import static com.android.internal.accessibility.common.ShortcutConstants.WhiteListingFeatureElementIndex.FRAGMENT_TYPE;
+import static com.android.internal.accessibility.common.ShortcutConstants.WhiteListingFeatureElementIndex.ICON_ID;
+import static com.android.internal.accessibility.common.ShortcutConstants.WhiteListingFeatureElementIndex.LABEL_ID;
+import static com.android.internal.accessibility.common.ShortcutConstants.WhiteListingFeatureElementIndex.SETTINGS_KEY;
+import static com.android.internal.accessibility.util.AccessibilityUtils.getAccessibilityServiceFragmentType;
+import static com.android.internal.accessibility.util.AccessibilityUtils.setAccessibilityServiceState;
+import static com.android.internal.accessibility.util.ShortcutUtils.convertToUserType;
+import static com.android.internal.accessibility.util.ShortcutUtils.hasValuesInSettings;
+import static com.android.internal.accessibility.util.ShortcutUtils.optInValueToSettings;
+import static com.android.internal.accessibility.util.ShortcutUtils.optOutValueFromSettings;
import static com.android.internal.util.Preconditions.checkArgument;
import android.accessibilityservice.AccessibilityServiceInfo;
import android.accessibilityservice.AccessibilityShortcutInfo;
-import android.annotation.IntDef;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.app.Activity;
@@ -41,15 +51,12 @@ import android.content.ComponentName;
import android.content.Context;
import android.content.DialogInterface;
import android.content.res.TypedArray;
-import android.graphics.ColorMatrix;
-import android.graphics.ColorMatrixColorFilter;
import android.graphics.drawable.Drawable;
import android.os.Build;
import android.os.Bundle;
-import android.os.UserHandle;
+import android.os.storage.StorageManager;
import android.provider.Settings;
-import android.text.TextUtils;
-import android.util.ArraySet;
+import android.text.BidiFormatter;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
@@ -57,129 +64,33 @@ import android.view.Window;
import android.view.accessibility.AccessibilityManager;
import android.widget.AdapterView;
import android.widget.BaseAdapter;
-import android.widget.FrameLayout;
+import android.widget.Button;
+import android.widget.CheckBox;
import android.widget.ImageView;
import android.widget.Switch;
import android.widget.TextView;
+import android.widget.Toast;
import com.android.internal.R;
-import java.lang.annotation.Retention;
-import java.lang.annotation.RetentionPolicy;
import java.util.ArrayList;
import java.util.Collections;
-import java.util.HashSet;
import java.util.List;
-import java.util.Set;
-import java.util.StringJoiner;
+import java.util.Locale;
/**
* Activity used to display and persist a service or feature target for the Accessibility button.
*/
public class AccessibilityButtonChooserActivity extends Activity {
- private static final char SERVICES_SEPARATOR = ':';
- private static final float DISABLED_ALPHA = 0.5f;
- private static final float ENABLED_ALPHA = 1.0f;
- private static final TextUtils.SimpleStringSplitter sStringColonSplitter =
- new TextUtils.SimpleStringSplitter(SERVICES_SEPARATOR);
@ShortcutType
- private int mShortcutType;
+ private static int sShortcutType;
@UserShortcutType
private int mShortcutUserType;
private final List<AccessibilityButtonTarget> mTargets = new ArrayList<>();
private AlertDialog mAlertDialog;
+ private AlertDialog mEnableDialog;
private TargetAdapter mTargetAdapter;
-
- /**
- * Annotation for different user shortcut type UI type.
- *
- * {@code DEFAULT} for displaying default value.
- * {@code SOFTWARE} for displaying specifying the accessibility services or features which
- * choose accessibility button in the navigation bar as preferred shortcut.
- * {@code HARDWARE} for displaying specifying the accessibility services or features which
- * choose accessibility shortcut as preferred shortcut.
- * {@code TRIPLETAP} for displaying specifying magnification to be toggled via quickly
- * tapping screen 3 times as preferred shortcut.
- */
- @Retention(RetentionPolicy.SOURCE)
- @IntDef({
- UserShortcutType.DEFAULT,
- UserShortcutType.SOFTWARE,
- UserShortcutType.HARDWARE,
- UserShortcutType.TRIPLETAP,
- })
- /** Denotes the user shortcut type. */
- private @interface UserShortcutType {
- int DEFAULT = 0;
- int SOFTWARE = 1; // 1 << 0
- int HARDWARE = 2; // 1 << 1
- int TRIPLETAP = 4; // 1 << 2
- }
-
- /**
- * Annotation for different accessibilityService fragment UI type.
- *
- * {@code LEGACY} for displaying appearance aligned with sdk version Q accessibility service
- * page, but only hardware shortcut allowed and under service in version Q or early.
- * {@code INVISIBLE} for displaying appearance without switch bar.
- * {@code INTUITIVE} for displaying appearance with version R accessibility design.
- * {@code BOUNCE} for displaying appearance with pop-up action.
- */
- @Retention(RetentionPolicy.SOURCE)
- @IntDef({
- AccessibilityServiceFragmentType.LEGACY,
- AccessibilityServiceFragmentType.INVISIBLE,
- AccessibilityServiceFragmentType.INTUITIVE,
- AccessibilityServiceFragmentType.BOUNCE,
- })
- private @interface AccessibilityServiceFragmentType {
- int LEGACY = 0;
- int INVISIBLE = 1;
- int INTUITIVE = 2;
- int BOUNCE = 3;
- }
-
- /**
- * Annotation for different shortcut menu mode.
- *
- * {@code LAUNCH} for clicking list item to trigger the service callback.
- * {@code EDIT} for clicking list item and save button to disable the service.
- */
- @Retention(RetentionPolicy.SOURCE)
- @IntDef({
- ShortcutMenuMode.LAUNCH,
- ShortcutMenuMode.EDIT,
- })
- private @interface ShortcutMenuMode {
- int LAUNCH = 0;
- int EDIT = 1;
- }
-
- /**
- * Annotation for align the element index of white listing feature
- * {@code WHITE_LISTING_FEATURES}.
- *
- * {@code COMPONENT_ID} is to get the service component name.
- * {@code LABEL_ID} is to get the service label text.
- * {@code ICON_ID} is to get the service icon.
- * {@code FRAGMENT_TYPE} is to get the service fragment type.
- * {@code SETTINGS_KEY} is to get the service settings key.
- */
- @Retention(RetentionPolicy.SOURCE)
- @IntDef({
- WhiteListingFeatureElementIndex.COMPONENT_ID,
- WhiteListingFeatureElementIndex.LABEL_ID,
- WhiteListingFeatureElementIndex.ICON_ID,
- WhiteListingFeatureElementIndex.FRAGMENT_TYPE,
- WhiteListingFeatureElementIndex.SETTINGS_KEY,
- })
- @interface WhiteListingFeatureElementIndex {
- int COMPONENT_ID = 0;
- int LABEL_ID = 1;
- int ICON_ID = 2;
- int FRAGMENT_TYPE = 3;
- int SETTINGS_KEY = 4;
- }
+ private AccessibilityButtonTarget mCurrentCheckedTarget;
private static final String[][] WHITE_LISTING_FEATURES = {
{
@@ -214,18 +125,21 @@ public class AccessibilityButtonChooserActivity extends Activity {
requestWindowFeature(Window.FEATURE_NO_TITLE);
}
- mShortcutType = getIntent().getIntExtra(AccessibilityManager.EXTRA_SHORTCUT_TYPE,
+ sShortcutType = getIntent().getIntExtra(AccessibilityManager.EXTRA_SHORTCUT_TYPE,
/* unexpectedShortcutType */ -1);
- final boolean existInShortcutType = (mShortcutType == ACCESSIBILITY_BUTTON)
- || (mShortcutType == ACCESSIBILITY_SHORTCUT_KEY);
- checkArgument(existInShortcutType, "Unexpected shortcut type: " + mShortcutType);
+ final boolean existInShortcutType = (sShortcutType == ACCESSIBILITY_BUTTON)
+ || (sShortcutType == ACCESSIBILITY_SHORTCUT_KEY);
+ checkArgument(existInShortcutType, "Unexpected shortcut type: " + sShortcutType);
- mShortcutUserType = convertToUserType(mShortcutType);
+ mShortcutUserType = convertToUserType(sShortcutType);
- mTargets.addAll(getServiceTargets(this, mShortcutType));
+ mTargets.addAll(getServiceTargets(this, sShortcutType));
- mTargetAdapter = new TargetAdapter(mTargets, mShortcutType);
+ final String selectDialogTitle =
+ getString(R.string.accessibility_select_shortcut_menu_title);
+ mTargetAdapter = new TargetAdapter(mTargets);
mAlertDialog = new AlertDialog.Builder(this)
+ .setTitle(selectDialogTitle)
.setAdapter(mTargetAdapter, /* listener= */ null)
.setPositiveButton(
getString(R.string.edit_accessibility_shortcut_menu_button),
@@ -242,38 +156,23 @@ public class AccessibilityButtonChooserActivity extends Activity {
super.onDestroy();
}
- /**
- * Gets the corresponding fragment type of a given accessibility service.
- *
- * @param accessibilityServiceInfo The accessibilityService's info.
- * @return int from {@link AccessibilityServiceFragmentType}.
- */
- private static @AccessibilityServiceFragmentType int getAccessibilityServiceFragmentType(
- AccessibilityServiceInfo accessibilityServiceInfo) {
- final int targetSdk = accessibilityServiceInfo.getResolveInfo()
- .serviceInfo.applicationInfo.targetSdkVersion;
- final boolean requestA11yButton = (accessibilityServiceInfo.flags
- & AccessibilityServiceInfo.FLAG_REQUEST_ACCESSIBILITY_BUTTON) != 0;
+ private static List<AccessibilityButtonTarget> getServiceTargets(@NonNull Context context,
+ @ShortcutType int shortcutType) {
+ final List<AccessibilityButtonTarget> targets = getInstalledServiceTargets(context);
+ final AccessibilityManager ams = context.getSystemService(AccessibilityManager.class);
+ final List<String> requiredTargets = ams.getAccessibilityShortcutTargets(shortcutType);
+ targets.removeIf(target -> !requiredTargets.contains(target.getId()));
- if (targetSdk <= Build.VERSION_CODES.Q) {
- return AccessibilityServiceFragmentType.LEGACY;
- }
- return requestA11yButton
- ? AccessibilityServiceFragmentType.INVISIBLE
- : AccessibilityServiceFragmentType.INTUITIVE;
+ return targets;
}
- private static List<AccessibilityButtonTarget> getServiceTargets(@NonNull Context context,
- @ShortcutType int shortcutType) {
+ private static List<AccessibilityButtonTarget> getInstalledServiceTargets(
+ @NonNull Context context) {
final List<AccessibilityButtonTarget> targets = new ArrayList<>();
targets.addAll(getAccessibilityServiceTargets(context));
targets.addAll(getAccessibilityActivityTargets(context));
targets.addAll(getWhiteListingServiceTargets(context));
- final AccessibilityManager ams = context.getSystemService(AccessibilityManager.class);
- final List<String> requiredTargets = ams.getAccessibilityShortcutTargets(shortcutType);
- targets.removeIf(target -> !requiredTargets.contains(target.getId()));
-
return targets;
}
@@ -288,6 +187,14 @@ public class AccessibilityButtonChooserActivity extends Activity {
final List<AccessibilityButtonTarget> targets = new ArrayList<>(installedServices.size());
for (AccessibilityServiceInfo info : installedServices) {
+ final int targetSdk =
+ info.getResolveInfo().serviceInfo.applicationInfo.targetSdkVersion;
+ final boolean hasRequestAccessibilityButtonFlag =
+ (info.flags & AccessibilityServiceInfo.FLAG_REQUEST_ACCESSIBILITY_BUTTON) != 0;
+ if ((targetSdk < Build.VERSION_CODES.R) && !hasRequestAccessibilityButtonFlag
+ && (sShortcutType == ACCESSIBILITY_BUTTON)) {
+ continue;
+ }
targets.add(new AccessibilityButtonTarget(context, info));
}
@@ -363,35 +270,31 @@ public class AccessibilityButtonChooserActivity extends Activity {
}
}
- private void disableService(String componentId) {
+ private void setServiceEnabled(String componentId, boolean enabled) {
if (isWhiteListingService(componentId)) {
- setWhiteListingServiceEnabled(componentId, /* settingsValueOff */ 0);
+ setWhiteListingServiceEnabled(componentId,
+ enabled ? /* settingsValueOn */ 1 : /* settingsValueOff */ 0);
} else {
final ComponentName componentName = ComponentName.unflattenFromString(componentId);
- setAccessibilityServiceState(this, componentName, /* enabled= */ false);
+ setAccessibilityServiceState(this, componentName, enabled);
}
}
private static class ViewHolder {
View mItemView;
+ CheckBox mCheckBox;
ImageView mIconView;
TextView mLabelView;
- FrameLayout mItemContainer;
- ImageView mActionViewItem;
Switch mSwitchItem;
}
private static class TargetAdapter extends BaseAdapter {
@ShortcutMenuMode
private int mShortcutMenuMode = ShortcutMenuMode.LAUNCH;
- @ShortcutType
- private int mShortcutButtonType;
private List<AccessibilityButtonTarget> mButtonTargets;
- TargetAdapter(List<AccessibilityButtonTarget> targets,
- @ShortcutType int shortcutButtonType) {
+ TargetAdapter(List<AccessibilityButtonTarget> targets) {
this.mButtonTargets = targets;
- this.mShortcutButtonType = shortcutButtonType;
}
void setShortcutMenuMode(@ShortcutMenuMode int shortcutMenuMode) {
@@ -428,13 +331,11 @@ public class AccessibilityButtonChooserActivity extends Activity {
false);
holder = new ViewHolder();
holder.mItemView = convertView;
+ holder.mCheckBox = convertView.findViewById(
+ R.id.accessibility_button_target_checkbox);
holder.mIconView = convertView.findViewById(R.id.accessibility_button_target_icon);
holder.mLabelView = convertView.findViewById(
R.id.accessibility_button_target_label);
- holder.mItemContainer = convertView.findViewById(
- R.id.accessibility_button_target_item_container);
- holder.mActionViewItem = convertView.findViewById(
- R.id.accessibility_button_target_view_item);
holder.mSwitchItem = convertView.findViewById(
R.id.accessibility_button_target_switch_item);
convertView.setTag(holder);
@@ -443,9 +344,6 @@ public class AccessibilityButtonChooserActivity extends Activity {
}
final AccessibilityButtonTarget target = mButtonTargets.get(position);
- holder.mIconView.setImageDrawable(target.getDrawable());
- holder.mLabelView.setText(target.getLabel());
-
updateActionItem(context, holder, target);
return convertView;
@@ -456,58 +354,42 @@ public class AccessibilityButtonChooserActivity extends Activity {
switch (target.getFragmentType()) {
case AccessibilityServiceFragmentType.LEGACY:
- updateLegacyActionItemVisibility(context, holder);
+ updateLegacyActionItemVisibility(holder, target);
break;
case AccessibilityServiceFragmentType.INVISIBLE:
- updateInvisibleActionItemVisibility(context, holder);
+ updateInvisibleActionItemVisibility(holder, target);
break;
case AccessibilityServiceFragmentType.INTUITIVE:
updateIntuitiveActionItemVisibility(context, holder, target);
break;
case AccessibilityServiceFragmentType.BOUNCE:
- updateBounceActionItemVisibility(context, holder);
+ updateBounceActionItemVisibility(holder, target);
break;
default:
throw new IllegalStateException("Unexpected fragment type");
}
}
- private void updateLegacyActionItemVisibility(@NonNull Context context,
- @NonNull ViewHolder holder) {
+ private void updateLegacyActionItemVisibility(@NonNull ViewHolder holder,
+ AccessibilityButtonTarget target) {
final boolean isLaunchMenuMode = (mShortcutMenuMode == ShortcutMenuMode.LAUNCH);
- final boolean isHardwareButtonTriggered =
- (mShortcutButtonType == ACCESSIBILITY_SHORTCUT_KEY);
- final boolean enabledState = (isLaunchMenuMode || isHardwareButtonTriggered);
- final ColorMatrix grayScaleMatrix = new ColorMatrix();
- grayScaleMatrix.setSaturation(/* grayScale */0);
-
- holder.mIconView.setColorFilter(enabledState
- ? null : new ColorMatrixColorFilter(grayScaleMatrix));
- holder.mIconView.setAlpha(enabledState
- ? ENABLED_ALPHA : DISABLED_ALPHA);
- holder.mLabelView.setEnabled(enabledState);
- holder.mActionViewItem.setEnabled(enabledState);
- holder.mActionViewItem.setImageDrawable(context.getDrawable(R.drawable.ic_delete_item));
- holder.mActionViewItem.setVisibility(View.VISIBLE);
+
+ holder.mCheckBox.setChecked(!isLaunchMenuMode && target.isChecked());
+ holder.mCheckBox.setVisibility(isLaunchMenuMode ? View.GONE : View.VISIBLE);
+ holder.mIconView.setImageDrawable(target.getDrawable());
+ holder.mLabelView.setText(target.getLabel());
holder.mSwitchItem.setVisibility(View.GONE);
- holder.mItemContainer.setVisibility(isLaunchMenuMode ? View.GONE : View.VISIBLE);
- holder.mItemView.setEnabled(enabledState);
- holder.mItemView.setClickable(!enabledState);
- }
-
- private void updateInvisibleActionItemVisibility(@NonNull Context context,
- @NonNull ViewHolder holder) {
- holder.mIconView.setColorFilter(null);
- holder.mIconView.setAlpha(ENABLED_ALPHA);
- holder.mLabelView.setEnabled(true);
- holder.mActionViewItem.setEnabled(true);
- holder.mActionViewItem.setImageDrawable(context.getDrawable(R.drawable.ic_delete_item));
- holder.mActionViewItem.setVisibility(View.VISIBLE);
+ }
+
+ private void updateInvisibleActionItemVisibility(@NonNull ViewHolder holder,
+ AccessibilityButtonTarget target) {
+ final boolean isEditMenuMode = (mShortcutMenuMode == ShortcutMenuMode.EDIT);
+
+ holder.mCheckBox.setChecked(isEditMenuMode && target.isChecked());
+ holder.mCheckBox.setVisibility(isEditMenuMode ? View.VISIBLE : View.GONE);
+ holder.mIconView.setImageDrawable(target.getDrawable());
+ holder.mLabelView.setText(target.getLabel());
holder.mSwitchItem.setVisibility(View.GONE);
- holder.mItemContainer.setVisibility((mShortcutMenuMode == ShortcutMenuMode.EDIT)
- ? View.VISIBLE : View.GONE);
- holder.mItemView.setEnabled(true);
- holder.mItemView.setClickable(false);
}
private void updateIntuitiveActionItemVisibility(@NonNull Context context,
@@ -517,37 +399,31 @@ public class AccessibilityButtonChooserActivity extends Activity {
? isWhiteListingServiceEnabled(context, target)
: isAccessibilityServiceEnabled(context, target);
- holder.mIconView.setColorFilter(null);
- holder.mIconView.setAlpha(ENABLED_ALPHA);
- holder.mLabelView.setEnabled(true);
- holder.mActionViewItem.setEnabled(true);
- holder.mActionViewItem.setImageDrawable(context.getDrawable(R.drawable.ic_delete_item));
- holder.mActionViewItem.setVisibility(isEditMenuMode ? View.VISIBLE : View.GONE);
+ holder.mCheckBox.setChecked(isEditMenuMode && target.isChecked());
+ holder.mCheckBox.setVisibility(isEditMenuMode ? View.VISIBLE : View.GONE);
+ holder.mIconView.setImageDrawable(target.getDrawable());
+ holder.mLabelView.setText(target.getLabel());
holder.mSwitchItem.setVisibility(isEditMenuMode ? View.GONE : View.VISIBLE);
holder.mSwitchItem.setChecked(!isEditMenuMode && isServiceEnabled);
- holder.mItemContainer.setVisibility(View.VISIBLE);
- holder.mItemView.setEnabled(true);
- holder.mItemView.setClickable(false);
- }
-
- private void updateBounceActionItemVisibility(@NonNull Context context,
- @NonNull ViewHolder holder) {
- holder.mIconView.setColorFilter(null);
- holder.mIconView.setAlpha(ENABLED_ALPHA);
- holder.mLabelView.setEnabled(true);
- holder.mActionViewItem.setEnabled(true);
- holder.mActionViewItem.setImageDrawable(context.getDrawable(R.drawable.ic_delete_item));
- holder.mActionViewItem.setVisibility((mShortcutMenuMode == ShortcutMenuMode.EDIT)
- ? View.VISIBLE : View.GONE);
+ }
+
+ private void updateBounceActionItemVisibility(@NonNull ViewHolder holder,
+ AccessibilityButtonTarget target) {
+ final boolean isEditMenuMode = (mShortcutMenuMode == ShortcutMenuMode.EDIT);
+
+ holder.mCheckBox.setChecked(isEditMenuMode && target.isChecked());
+ holder.mCheckBox.setVisibility(isEditMenuMode ? View.VISIBLE : View.GONE);
+ holder.mIconView.setImageDrawable(target.getDrawable());
+ holder.mLabelView.setText(target.getLabel());
holder.mSwitchItem.setVisibility(View.GONE);
- holder.mItemContainer.setVisibility(View.VISIBLE);
- holder.mItemView.setEnabled(true);
- holder.mItemView.setClickable(false);
}
}
private static class AccessibilityButtonTarget {
private String mId;
+ @TargetType
+ private int mType;
+ private boolean mChecked;
private CharSequence mLabel;
private Drawable mDrawable;
@AccessibilityServiceFragmentType
@@ -556,6 +432,8 @@ public class AccessibilityButtonChooserActivity extends Activity {
AccessibilityButtonTarget(@NonNull Context context,
@NonNull AccessibilityServiceInfo serviceInfo) {
this.mId = serviceInfo.getComponentName().flattenToString();
+ this.mType = TargetType.ACCESSIBILITY_SERVICE;
+ this.mChecked = isTargetShortcutUsed(context, mId);
this.mLabel = serviceInfo.getResolveInfo().loadLabel(context.getPackageManager());
this.mDrawable = serviceInfo.getResolveInfo().loadIcon(context.getPackageManager());
this.mFragmentType = getAccessibilityServiceFragmentType(serviceInfo);
@@ -564,6 +442,8 @@ public class AccessibilityButtonChooserActivity extends Activity {
AccessibilityButtonTarget(@NonNull Context context,
@NonNull AccessibilityShortcutInfo shortcutInfo) {
this.mId = shortcutInfo.getComponentName().flattenToString();
+ this.mType = TargetType.ACCESSIBILITY_ACTIVITY;
+ this.mChecked = isTargetShortcutUsed(context, mId);
this.mLabel = shortcutInfo.getActivityInfo().loadLabel(context.getPackageManager());
this.mDrawable = shortcutInfo.getActivityInfo().loadIcon(context.getPackageManager());
this.mFragmentType = AccessibilityServiceFragmentType.BOUNCE;
@@ -572,15 +452,29 @@ public class AccessibilityButtonChooserActivity extends Activity {
AccessibilityButtonTarget(Context context, @NonNull String id, int labelResId,
int iconRes, @AccessibilityServiceFragmentType int fragmentType) {
this.mId = id;
+ this.mType = TargetType.WHITE_LISTING;
+ this.mChecked = isTargetShortcutUsed(context, mId);
this.mLabel = context.getText(labelResId);
this.mDrawable = context.getDrawable(iconRes);
this.mFragmentType = fragmentType;
}
+ public void setChecked(boolean checked) {
+ mChecked = checked;
+ }
+
public String getId() {
return mId;
}
+ public int getType() {
+ return mType;
+ }
+
+ public boolean isChecked() {
+ return mChecked;
+ }
+
public CharSequence getLabel() {
return mLabel;
}
@@ -633,19 +527,19 @@ public class AccessibilityButtonChooserActivity extends Activity {
}
private void onLegacyTargetSelected(AccessibilityButtonTarget target) {
- if (mShortcutType == ACCESSIBILITY_BUTTON) {
+ if (sShortcutType == ACCESSIBILITY_BUTTON) {
final AccessibilityManager ams = getSystemService(AccessibilityManager.class);
ams.notifyAccessibilityButtonClicked(getDisplayId(), target.getId());
- } else if (mShortcutType == ACCESSIBILITY_SHORTCUT_KEY) {
+ } else if (sShortcutType == ACCESSIBILITY_SHORTCUT_KEY) {
switchServiceState(target);
}
}
private void onInvisibleTargetSelected(AccessibilityButtonTarget target) {
final AccessibilityManager ams = getSystemService(AccessibilityManager.class);
- if (mShortcutType == ACCESSIBILITY_BUTTON) {
+ if (sShortcutType == ACCESSIBILITY_BUTTON) {
ams.notifyAccessibilityButtonClicked(getDisplayId(), target.getId());
- } else if (mShortcutType == ACCESSIBILITY_SHORTCUT_KEY) {
+ } else if (sShortcutType == ACCESSIBILITY_SHORTCUT_KEY) {
ams.performAccessibilityShortcut(target.getId());
}
}
@@ -656,9 +550,9 @@ public class AccessibilityButtonChooserActivity extends Activity {
private void onBounceTargetSelected(AccessibilityButtonTarget target) {
final AccessibilityManager ams = getSystemService(AccessibilityManager.class);
- if (mShortcutType == ACCESSIBILITY_BUTTON) {
+ if (sShortcutType == ACCESSIBILITY_BUTTON) {
ams.notifyAccessibilityButtonClicked(getDisplayId(), target.getId());
- } else if (mShortcutType == ACCESSIBILITY_SHORTCUT_KEY) {
+ } else if (sShortcutType == ACCESSIBILITY_SHORTCUT_KEY) {
ams.performAccessibilityShortcut(target.getId());
}
}
@@ -679,66 +573,101 @@ public class AccessibilityButtonChooserActivity extends Activity {
}
}
- private void onTargetDeleted(AdapterView<?> parent, View view, int position, long id) {
- final AccessibilityButtonTarget target = mTargets.get(position);
- final String componentId = target.getId();
+ private void onTargetChecked(AdapterView<?> parent, View view, int position, long id) {
+ mCurrentCheckedTarget = mTargets.get(position);
+ if ((mCurrentCheckedTarget.getType() == TargetType.ACCESSIBILITY_SERVICE)
+ && !mCurrentCheckedTarget.isChecked()) {
+ mEnableDialog = new AlertDialog.Builder(this)
+ .setView(createEnableDialogContentView(this, mCurrentCheckedTarget,
+ this::onPermissionAllowButtonClicked,
+ this::onPermissionDenyButtonClicked))
+ .create();
+ mEnableDialog.show();
+ return;
+ }
+
+ onTargetChecked(mCurrentCheckedTarget, !mCurrentCheckedTarget.isChecked());
+ }
+
+ private void onTargetChecked(AccessibilityButtonTarget target, boolean checked) {
switch (target.getFragmentType()) {
case AccessibilityServiceFragmentType.LEGACY:
- onLegacyTargetDeleted(position, componentId);
+ onLegacyTargetChecked(checked);
break;
case AccessibilityServiceFragmentType.INVISIBLE:
- onInvisibleTargetDeleted(position, componentId);
+ onInvisibleTargetChecked(checked);
break;
case AccessibilityServiceFragmentType.INTUITIVE:
- onIntuitiveTargetDeleted(position, componentId);
+ onIntuitiveTargetChecked(checked);
break;
case AccessibilityServiceFragmentType.BOUNCE:
- onBounceTargetDeleted(position, componentId);
+ onBounceTargetChecked(checked);
break;
default:
throw new IllegalStateException("Unexpected fragment type");
}
-
- if (mTargets.isEmpty()) {
- mAlertDialog.dismiss();
- }
}
- private void onLegacyTargetDeleted(int position, String componentId) {
- if (mShortcutType == ACCESSIBILITY_SHORTCUT_KEY) {
- optOutValueFromSettings(this, mShortcutUserType, componentId);
-
- mTargets.remove(position);
- mTargetAdapter.notifyDataSetChanged();
+ private void onLegacyTargetChecked(boolean checked) {
+ if (sShortcutType == ACCESSIBILITY_BUTTON) {
+ setServiceEnabled(mCurrentCheckedTarget.getId(), checked);
+ if (!checked) {
+ optOutValueFromSettings(this, HARDWARE, mCurrentCheckedTarget.getId());
+ final String warningText =
+ getString(R.string.accessibility_uncheck_legacy_item_warning,
+ mCurrentCheckedTarget.getLabel());
+ Toast.makeText(this, warningText, Toast.LENGTH_SHORT).show();
+ }
+ } else if (sShortcutType == ACCESSIBILITY_SHORTCUT_KEY) {
+ updateValueToSettings(mCurrentCheckedTarget.getId(), checked);
+ } else {
+ throw new IllegalStateException("Unexpected shortcut type");
}
- }
- private void onInvisibleTargetDeleted(int position, String componentId) {
- optOutValueFromSettings(this, mShortcutUserType, componentId);
+ mCurrentCheckedTarget.setChecked(checked);
+ mTargetAdapter.notifyDataSetChanged();
+ }
- final int shortcutTypes = UserShortcutType.SOFTWARE | UserShortcutType.HARDWARE;
- if (!hasValuesInSettings(this, shortcutTypes, componentId)) {
- disableService(componentId);
+ private void onInvisibleTargetChecked(boolean checked) {
+ final int shortcutTypes = UserShortcutType.SOFTWARE | HARDWARE;
+ if (!hasValuesInSettings(this, shortcutTypes, mCurrentCheckedTarget.getId())) {
+ setServiceEnabled(mCurrentCheckedTarget.getId(), checked);
}
- mTargets.remove(position);
+ updateValueToSettings(mCurrentCheckedTarget.getId(), checked);
+ mCurrentCheckedTarget.setChecked(checked);
mTargetAdapter.notifyDataSetChanged();
}
- private void onIntuitiveTargetDeleted(int position, String componentId) {
- optOutValueFromSettings(this, mShortcutUserType, componentId);
- mTargets.remove(position);
+ private void onIntuitiveTargetChecked(boolean checked) {
+ updateValueToSettings(mCurrentCheckedTarget.getId(), checked);
+ mCurrentCheckedTarget.setChecked(checked);
mTargetAdapter.notifyDataSetChanged();
}
- private void onBounceTargetDeleted(int position, String componentId) {
- optOutValueFromSettings(this, mShortcutUserType, componentId);
- mTargets.remove(position);
+ private void onBounceTargetChecked(boolean checked) {
+ updateValueToSettings(mCurrentCheckedTarget.getId(), checked);
+ mCurrentCheckedTarget.setChecked(checked);
mTargetAdapter.notifyDataSetChanged();
}
- private void onCancelButtonClicked() {
+ private void updateValueToSettings(String componentId, boolean checked) {
+ if (checked) {
+ optInValueToSettings(this, mShortcutUserType, componentId);
+ } else {
+ optOutValueFromSettings(this, mShortcutUserType, componentId);
+ }
+ }
+
+ private void onDoneButtonClicked() {
+ mTargets.clear();
+ mTargets.addAll(getServiceTargets(this, sShortcutType));
+ if (mTargets.isEmpty()) {
+ mAlertDialog.dismiss();
+ return;
+ }
+
mTargetAdapter.setShortcutMenuMode(ShortcutMenuMode.LAUNCH);
mTargetAdapter.notifyDataSetChanged();
@@ -749,11 +678,13 @@ public class AccessibilityButtonChooserActivity extends Activity {
}
private void onEditButtonClicked() {
+ mTargets.clear();
+ mTargets.addAll(getInstalledServiceTargets(this));
mTargetAdapter.setShortcutMenuMode(ShortcutMenuMode.EDIT);
mTargetAdapter.notifyDataSetChanged();
mAlertDialog.getButton(DialogInterface.BUTTON_POSITIVE).setText(
- getString(R.string.cancel_accessibility_shortcut_menu_button));
+ getString(R.string.done_accessibility_shortcut_menu_button));
updateDialogListeners();
}
@@ -761,193 +692,80 @@ public class AccessibilityButtonChooserActivity extends Activity {
private void updateDialogListeners() {
final boolean isEditMenuMode =
(mTargetAdapter.getShortcutMenuMode() == ShortcutMenuMode.EDIT);
+ final int selectDialogTitleId = R.string.accessibility_select_shortcut_menu_title;
+ final int editDialogTitleId =
+ (sShortcutType == ACCESSIBILITY_BUTTON)
+ ? R.string.accessibility_edit_shortcut_menu_button_title
+ : R.string.accessibility_edit_shortcut_menu_volume_title;
+ mAlertDialog.setTitle(getString(isEditMenuMode ? editDialogTitleId : selectDialogTitleId));
mAlertDialog.getButton(DialogInterface.BUTTON_POSITIVE).setOnClickListener(
- isEditMenuMode ? view -> onCancelButtonClicked() : view -> onEditButtonClicked());
+ isEditMenuMode ? view -> onDoneButtonClicked() : view -> onEditButtonClicked());
mAlertDialog.getListView().setOnItemClickListener(
- isEditMenuMode ? this::onTargetDeleted : this::onTargetSelected);
- }
-
- /**
- * @return the set of enabled accessibility services for {@param userId}. If there are no
- * services, it returns the unmodifiable {@link Collections#emptySet()}.
- */
- private Set<ComponentName> getEnabledServicesFromSettings(Context context, int userId) {
- final String enabledServicesSetting = Settings.Secure.getStringForUser(
- context.getContentResolver(), Settings.Secure.ENABLED_ACCESSIBILITY_SERVICES,
- userId);
- if (TextUtils.isEmpty(enabledServicesSetting)) {
- return Collections.emptySet();
- }
-
- final Set<ComponentName> enabledServices = new HashSet<>();
- final TextUtils.StringSplitter colonSplitter =
- new TextUtils.SimpleStringSplitter(SERVICES_SEPARATOR);
- colonSplitter.setString(enabledServicesSetting);
-
- for (String componentNameString : colonSplitter) {
- final ComponentName enabledService = ComponentName.unflattenFromString(
- componentNameString);
- if (enabledService != null) {
- enabledServices.add(enabledService);
- }
- }
-
- return enabledServices;
+ isEditMenuMode ? this::onTargetChecked : this::onTargetSelected);
}
- /**
- * Changes an accessibility component's state.
- */
- private void setAccessibilityServiceState(Context context, ComponentName componentName,
- boolean enabled) {
- setAccessibilityServiceState(context, componentName, enabled, UserHandle.myUserId());
- }
-
- /**
- * Changes an accessibility component's state for {@param userId}.
- */
- private void setAccessibilityServiceState(Context context, ComponentName componentName,
- boolean enabled, int userId) {
- Set<ComponentName> enabledServices = getEnabledServicesFromSettings(
- context, userId);
-
- if (enabledServices.isEmpty()) {
- enabledServices = new ArraySet<>(/* capacity= */ 1);
- }
-
- if (enabled) {
- enabledServices.add(componentName);
- } else {
- enabledServices.remove(componentName);
- }
-
- final StringBuilder enabledServicesBuilder = new StringBuilder();
- for (ComponentName enabledService : enabledServices) {
- enabledServicesBuilder.append(enabledService.flattenToString());
- enabledServicesBuilder.append(
- SERVICES_SEPARATOR);
- }
-
- final int enabledServicesBuilderLength = enabledServicesBuilder.length();
- if (enabledServicesBuilderLength > 0) {
- enabledServicesBuilder.deleteCharAt(enabledServicesBuilderLength - 1);
- }
-
- Settings.Secure.putStringForUser(context.getContentResolver(),
- Settings.Secure.ENABLED_ACCESSIBILITY_SERVICES,
- enabledServicesBuilder.toString(), userId);
+ private static boolean isTargetShortcutUsed(@NonNull Context context, String id) {
+ final AccessibilityManager ams = context.getSystemService(AccessibilityManager.class);
+ final List<String> requiredTargets = ams.getAccessibilityShortcutTargets(sShortcutType);
+ return requiredTargets.contains(id);
}
- /**
- * Opts out component name into colon-separated {@code shortcutType} key's string in Settings.
- *
- * @param context The current context.
- * @param shortcutType The preferred shortcut type user selected.
- * @param componentId The component id that need to be opted out from Settings.
- */
- private void optOutValueFromSettings(
- Context context, @UserShortcutType int shortcutType, String componentId) {
- final StringJoiner joiner = new StringJoiner(String.valueOf(SERVICES_SEPARATOR));
- final String targetsKey = convertToKey(shortcutType);
- final String targetsValue = Settings.Secure.getString(context.getContentResolver(),
- targetsKey);
-
- if (TextUtils.isEmpty(targetsValue)) {
- return;
- }
-
- sStringColonSplitter.setString(targetsValue);
- while (sStringColonSplitter.hasNext()) {
- final String id = sStringColonSplitter.next();
- if (TextUtils.isEmpty(id) || componentId.equals(id)) {
- continue;
- }
- joiner.add(id);
+ private void onPermissionAllowButtonClicked(View view) {
+ if (mCurrentCheckedTarget.getFragmentType() != AccessibilityServiceFragmentType.LEGACY) {
+ updateValueToSettings(mCurrentCheckedTarget.getId(), /* checked= */ true);
}
-
- Settings.Secure.putString(context.getContentResolver(), targetsKey, joiner.toString());
+ onTargetChecked(mCurrentCheckedTarget, /* checked= */ true);
+ mEnableDialog.dismiss();
}
- /**
- * Returns if component name existed in one of {@code shortcutTypes} string in Settings.
- *
- * @param context The current context.
- * @param shortcutTypes A combination of {@link UserShortcutType}.
- * @param componentId The component name that need to be checked existed in Settings.
- * @return {@code true} if componentName existed in Settings.
- */
- private boolean hasValuesInSettings(Context context, int shortcutTypes,
- @NonNull String componentId) {
- boolean exist = false;
- if ((shortcutTypes & UserShortcutType.SOFTWARE) == UserShortcutType.SOFTWARE) {
- exist = hasValueInSettings(context, UserShortcutType.SOFTWARE, componentId);
- }
- if (((shortcutTypes & UserShortcutType.HARDWARE) == UserShortcutType.HARDWARE)) {
- exist |= hasValueInSettings(context, UserShortcutType.HARDWARE, componentId);
- }
- return exist;
+ private void onPermissionDenyButtonClicked(View view) {
+ mEnableDialog.dismiss();
}
+ private static View createEnableDialogContentView(Context context,
+ AccessibilityButtonTarget target, View.OnClickListener allowListener,
+ View.OnClickListener denyListener) {
+ final LayoutInflater inflater = (LayoutInflater) context.getSystemService(
+ Context.LAYOUT_INFLATER_SERVICE);
- /**
- * Returns if component name existed in Settings.
- *
- * @param context The current context.
- * @param shortcutType The preferred shortcut type user selected.
- * @param componentId The component id that need to be checked existed in Settings.
- * @return {@code true} if componentName existed in Settings.
- */
- private boolean hasValueInSettings(Context context, @UserShortcutType int shortcutType,
- @NonNull String componentId) {
- final String targetKey = convertToKey(shortcutType);
- final String targetString = Settings.Secure.getString(context.getContentResolver(),
- targetKey);
+ final View content = inflater.inflate(
+ R.layout.accessibility_enable_service_encryption_warning, /* root= */ null);
- if (TextUtils.isEmpty(targetString)) {
- return false;
+ final TextView encryptionWarningView = (TextView) content.findViewById(
+ R.id.accessibility_encryption_warning);
+ if (StorageManager.isNonDefaultBlockEncrypted()) {
+ final String text = context.getString(
+ R.string.accessibility_enable_service_encryption_warning,
+ getServiceName(context, target.getLabel()));
+ encryptionWarningView.setText(text);
+ encryptionWarningView.setVisibility(View.VISIBLE);
+ } else {
+ encryptionWarningView.setVisibility(View.GONE);
}
- sStringColonSplitter.setString(targetString);
- while (sStringColonSplitter.hasNext()) {
- final String id = sStringColonSplitter.next();
- if (componentId.equals(id)) {
- return true;
- }
- }
+ final ImageView permissionDialogIcon = content.findViewById(
+ R.id.accessibility_permissionDialog_icon);
+ permissionDialogIcon.setImageDrawable(target.getDrawable());
- return false;
- }
+ final TextView permissionDialogTitle = content.findViewById(
+ R.id.accessibility_permissionDialog_title);
+ permissionDialogTitle.setText(context.getString(R.string.accessibility_enable_service_title,
+ getServiceName(context, target.getLabel())));
- /**
- * Converts {@link UserShortcutType} to key in Settings.
- *
- * @param type The shortcut type.
- * @return Mapping key in Settings.
- */
- private String convertToKey(@UserShortcutType int type) {
- switch (type) {
- case UserShortcutType.SOFTWARE:
- return Settings.Secure.ACCESSIBILITY_BUTTON_TARGET_COMPONENT;
- case UserShortcutType.HARDWARE:
- return Settings.Secure.ACCESSIBILITY_SHORTCUT_TARGET_SERVICE;
- case UserShortcutType.TRIPLETAP:
- return Settings.Secure.ACCESSIBILITY_DISPLAY_MAGNIFICATION_ENABLED;
- default:
- throw new IllegalArgumentException(
- "Unsupported user shortcut type: " + type);
- }
+ final Button permissionAllowButton = content.findViewById(
+ R.id.accessibility_permission_enable_allow_button);
+ final Button permissionDenyButton = content.findViewById(
+ R.id.accessibility_permission_enable_deny_button);
+ permissionAllowButton.setOnClickListener(allowListener);
+ permissionDenyButton.setOnClickListener(denyListener);
+
+ return content;
}
- private static @UserShortcutType int convertToUserType(@ShortcutType int type) {
- switch (type) {
- case ACCESSIBILITY_BUTTON:
- return UserShortcutType.SOFTWARE;
- case ACCESSIBILITY_SHORTCUT_KEY:
- return UserShortcutType.HARDWARE;
- default:
- throw new IllegalArgumentException(
- "Unsupported shortcut type:" + type);
- }
+ // Gets the service name and bidi wrap it to protect from bidi side effects.
+ private static CharSequence getServiceName(Context context, CharSequence label) {
+ final Locale locale = context.getResources().getConfiguration().getLocales().get(0);
+ return BidiFormatter.getInstance(locale).unicodeWrap(label);
}
}
diff --git a/core/java/com/android/internal/app/ChooserActivity.java b/core/java/com/android/internal/app/ChooserActivity.java
index 38fd560eae46..c487e960854b 100644
--- a/core/java/com/android/internal/app/ChooserActivity.java
+++ b/core/java/com/android/internal/app/ChooserActivity.java
@@ -2447,6 +2447,11 @@ public class ChooserActivity extends ResolverActivity implements
offset += findViewById(R.id.tabs).getHeight();
}
+ View tabDivider = findViewById(R.id.resolver_tab_divider);
+ if (tabDivider.getVisibility() == View.VISIBLE) {
+ offset += tabDivider.getHeight();
+ }
+
int directShareHeight = 0;
rowsToShow = Math.min(4, rowsToShow);
mLastNumberOfChildren = recyclerView.getChildCount();
diff --git a/core/java/com/android/internal/app/ChooserMultiProfilePagerAdapter.java b/core/java/com/android/internal/app/ChooserMultiProfilePagerAdapter.java
index b39d42ec1e96..2167b1ebd473 100644
--- a/core/java/com/android/internal/app/ChooserMultiProfilePagerAdapter.java
+++ b/core/java/com/android/internal/app/ChooserMultiProfilePagerAdapter.java
@@ -20,6 +20,7 @@ import android.annotation.Nullable;
import android.content.Context;
import android.os.UserHandle;
import android.view.LayoutInflater;
+import android.view.View;
import android.view.ViewGroup;
import com.android.internal.R;
@@ -169,6 +170,32 @@ public class ChooserMultiProfilePagerAdapter extends AbstractMultiProfilePagerAd
return ResolverActivity.METRICS_CATEGORY_CHOOSER;
}
+ @Override
+ protected void showWorkProfileOffEmptyState(ResolverListAdapter activeListAdapter,
+ View.OnClickListener listener) {
+ showEmptyState(activeListAdapter,
+ R.drawable.ic_work_apps_off,
+ R.string.resolver_turn_on_work_apps_share,
+ /* subtitleRes */ 0,
+ listener);
+ }
+
+ @Override
+ protected void showNoPersonalToWorkIntentsEmptyState(ResolverListAdapter activeListAdapter) {
+ showEmptyState(activeListAdapter,
+ R.drawable.ic_sharing_disabled,
+ R.string.resolver_cant_share_with_work_apps,
+ R.string.resolver_cant_share_cross_profile_explanation);
+ }
+
+ @Override
+ protected void showNoWorkToPersonalIntentsEmptyState(ResolverListAdapter activeListAdapter) {
+ showEmptyState(activeListAdapter,
+ R.drawable.ic_sharing_disabled,
+ R.string.resolver_cant_share_with_personal_apps,
+ R.string.resolver_cant_share_cross_profile_explanation);
+ }
+
class ChooserProfileDescriptor extends ProfileDescriptor {
private ChooserActivity.ChooserGridAdapter chooserGridAdapter;
private RecyclerView recyclerView;
diff --git a/core/java/com/android/internal/app/IAppOpsService.aidl b/core/java/com/android/internal/app/IAppOpsService.aidl
index 1c1c25459b66..907ea55d52a0 100644
--- a/core/java/com/android/internal/app/IAppOpsService.aidl
+++ b/core/java/com/android/internal/app/IAppOpsService.aidl
@@ -103,4 +103,6 @@ interface IAppOpsService {
int checkOperationRaw(int code, int uid, String packageName);
void reloadNonHistoricalState();
+
+ void collectNoteOpCallsForValidation(String stackTrace, int op, String packageName, long version);
}
diff --git a/core/java/com/android/internal/app/ResolverActivity.java b/core/java/com/android/internal/app/ResolverActivity.java
index 2ea63b347cff..ec371d9a7311 100644
--- a/core/java/com/android/internal/app/ResolverActivity.java
+++ b/core/java/com/android/internal/app/ResolverActivity.java
@@ -163,7 +163,7 @@ public class ResolverActivity extends Activity implements
* TODO(arangelov): Remove a couple of weeks after work/personal tabs are finalized.
*/
@VisibleForTesting
- public static boolean ENABLE_TABBED_VIEW = false;
+ public static boolean ENABLE_TABBED_VIEW = true;
private static final String TAB_TAG_PERSONAL = "personal";
private static final String TAB_TAG_WORK = "work";
@@ -645,7 +645,7 @@ public class ResolverActivity extends Activity implements
final DisplayResolveInfo dri =
mMultiProfilePagerAdapter.getActiveListAdapter().getOtherProfile();
- if (dri != null && !ENABLE_TABBED_VIEW) {
+ if (dri != null && !shouldShowTabs()) {
mProfileView.setVisibility(View.VISIBLE);
View text = mProfileView.findViewById(R.id.profile_button);
if (!(text instanceof TextView)) {
@@ -854,6 +854,11 @@ public class ResolverActivity extends Activity implements
private void setAlwaysButtonEnabled(boolean hasValidSelection, int checkedPos,
boolean filtered) {
+ if (mMultiProfilePagerAdapter.getCurrentUserHandle() != getUser()) {
+ // Never allow the inactive profile to always open an app.
+ mAlwaysButton.setEnabled(false);
+ return;
+ }
boolean enabled = false;
ResolveInfo ri = null;
if (hasValidSelection) {
@@ -877,19 +882,21 @@ public class ResolverActivity extends Activity implements
}
}
- ActivityInfo activityInfo = ri.activityInfo;
+ if (ri != null) {
+ ActivityInfo activityInfo = ri.activityInfo;
- boolean hasRecordPermission =
- mPm.checkPermission(android.Manifest.permission.RECORD_AUDIO,
- activityInfo.packageName)
- == android.content.pm.PackageManager.PERMISSION_GRANTED;
+ boolean hasRecordPermission =
+ mPm.checkPermission(android.Manifest.permission.RECORD_AUDIO,
+ activityInfo.packageName)
+ == android.content.pm.PackageManager.PERMISSION_GRANTED;
- if (!hasRecordPermission) {
- // OK, we know the record permission, is this a capture device
- boolean hasAudioCapture =
- getIntent().getBooleanExtra(
- ResolverActivity.EXTRA_IS_AUDIO_CAPTURE_DEVICE, false);
- enabled = !hasAudioCapture;
+ if (!hasRecordPermission) {
+ // OK, we know the record permission, is this a capture device
+ boolean hasAudioCapture =
+ getIntent().getBooleanExtra(
+ ResolverActivity.EXTRA_IS_AUDIO_CAPTURE_DEVICE, false);
+ enabled = !hasAudioCapture;
+ }
}
mAlwaysButton.setEnabled(enabled);
}
@@ -982,6 +989,8 @@ public class ResolverActivity extends Activity implements
}
if (shouldShowEmptyState(listAdapter)) {
mMultiProfilePagerAdapter.showEmptyState(listAdapter);
+ } else {
+ mMultiProfilePagerAdapter.showListView(listAdapter);
}
if (doPostProcessing) {
if (mMultiProfilePagerAdapter.getCurrentUserHandle().getIdentifier()
@@ -1330,9 +1339,12 @@ public class ResolverActivity extends Activity implements
+ "cannot be null.");
}
// We partially rebuild the inactive adapter to determine if we should auto launch
- boolean rebuildCompleted = mMultiProfilePagerAdapter.rebuildActiveTab(true);
- if (hasWorkProfile() && ENABLE_TABBED_VIEW) {
- boolean rebuildInactiveCompleted = mMultiProfilePagerAdapter.rebuildInactiveTab(false);
+ // isTabLoaded will be true here if the empty state screen is shown instead of the list.
+ boolean rebuildCompleted = mMultiProfilePagerAdapter.rebuildActiveTab(true)
+ || mMultiProfilePagerAdapter.getActiveListAdapter().isTabLoaded();
+ if (shouldShowTabs()) {
+ boolean rebuildInactiveCompleted = mMultiProfilePagerAdapter.rebuildInactiveTab(false)
+ || mMultiProfilePagerAdapter.getInactiveListAdapter().isTabLoaded();
rebuildCompleted = rebuildCompleted && rebuildInactiveCompleted;
}
@@ -1392,8 +1404,8 @@ public class ResolverActivity extends Activity implements
if (numberOfProfiles == 1 && maybeAutolaunchIfSingleTarget()) {
return true;
} else if (numberOfProfiles == 2
- && mMultiProfilePagerAdapter.getActiveListAdapter().isListLoaded()
- && mMultiProfilePagerAdapter.getInactiveListAdapter().isListLoaded()
+ && mMultiProfilePagerAdapter.getActiveListAdapter().isTabLoaded()
+ && mMultiProfilePagerAdapter.getInactiveListAdapter().isTabLoaded()
&& (maybeAutolaunchIfNoAppsOnInactiveTab()
|| maybeAutolaunchIfCrossProfileSupported())) {
return true;
@@ -1567,14 +1579,38 @@ public class ResolverActivity extends Activity implements
viewPager.setVisibility(View.VISIBLE);
tabHost.setCurrentTab(mMultiProfilePagerAdapter.getCurrentPage());
- mMultiProfilePagerAdapter.setOnProfileSelectedListener(tabHost::setCurrentTab);
+ mMultiProfilePagerAdapter.setOnProfileSelectedListener(
+ index -> {
+ tabHost.setCurrentTab(index);
+ resetButtonBar();
+ resetCheckedItem();
+ });
findViewById(R.id.resolver_tab_divider).setVisibility(View.VISIBLE);
}
+ private void resetCheckedItem() {
+ if (!isIntentPicker()) {
+ return;
+ }
+ mLastSelected = ListView.INVALID_POSITION;
+ ListView inactiveListView = (ListView) mMultiProfilePagerAdapter.getInactiveAdapterView();
+ if (inactiveListView.getCheckedItemCount() > 0) {
+ inactiveListView.setItemChecked(inactiveListView.getCheckedItemPosition(), false);
+ }
+ }
+
private void resetTabsHeaderStyle(TabWidget tabWidget) {
+ String workContentDescription = getString(R.string.resolver_work_tab_accessibility);
+ String personalContentDescription = getString(R.string.resolver_personal_tab_accessibility);
for (int i = 0; i < tabWidget.getChildCount(); i++) {
- TextView title = tabWidget.getChildAt(i).findViewById(android.R.id.title);
+ View tabView = tabWidget.getChildAt(i);
+ TextView title = tabView.findViewById(android.R.id.title);
title.setTextColor(getColor(R.color.resolver_tabs_inactive_color));
+ if (title.getText().equals(getString(R.string.resolver_personal_tab))) {
+ tabView.setContentDescription(personalContentDescription);
+ } else if (title.getText().equals(getString(R.string.resolver_work_tab))) {
+ tabView.setContentDescription(workContentDescription);
+ }
}
}
@@ -1677,6 +1713,10 @@ public class ResolverActivity extends Activity implements
}
private void resetAlwaysOrOnceButtonBar() {
+ // Disable both buttons initially
+ setAlwaysButtonEnabled(false, ListView.INVALID_POSITION, false);
+ mOnceButton.setEnabled(false);
+
int filteredPosition = mMultiProfilePagerAdapter.getActiveListAdapter()
.getFilteredPosition();
if (useLayoutWithDefault() && filteredPosition != ListView.INVALID_POSITION) {
diff --git a/core/java/com/android/internal/app/ResolverListAdapter.java b/core/java/com/android/internal/app/ResolverListAdapter.java
index 54453d0d0f46..61a404e3bc5f 100644
--- a/core/java/com/android/internal/app/ResolverListAdapter.java
+++ b/core/java/com/android/internal/app/ResolverListAdapter.java
@@ -87,7 +87,7 @@ public class ResolverListAdapter extends BaseAdapter {
private final ResolverListCommunicator mResolverListCommunicator;
private Runnable mPostListReadyRunnable;
private final boolean mIsAudioCaptureDevice;
- private boolean mIsListLoaded;
+ private boolean mIsTabLoaded;
public ResolverListAdapter(Context context, List<Intent> payloadIntents,
Intent[] initialIntents, List<ResolveInfo> rList,
@@ -192,7 +192,7 @@ public class ResolverListAdapter extends BaseAdapter {
mLastChosenPosition = -1;
mAllTargetsAreBrowsers = false;
mDisplayList.clear();
- mIsListLoaded = false;
+ mIsTabLoaded = false;
if (mBaseResolveList != null) {
currentResolveList = mUnfilteredResolveList = new ArrayList<>();
@@ -354,7 +354,7 @@ public class ResolverListAdapter extends BaseAdapter {
mResolverListCommunicator.sendVoiceChoicesIfNeeded();
postListReadyRunnable(doPostProcessing);
- mIsListLoaded = true;
+ mIsTabLoaded = true;
}
/**
@@ -614,8 +614,12 @@ public class ResolverListAdapter extends BaseAdapter {
return mIntents;
}
- protected boolean isListLoaded() {
- return mIsListLoaded;
+ protected boolean isTabLoaded() {
+ return mIsTabLoaded;
+ }
+
+ protected void markTabLoaded() {
+ mIsTabLoaded = true;
}
/**
diff --git a/core/java/com/android/internal/app/ResolverMultiProfilePagerAdapter.java b/core/java/com/android/internal/app/ResolverMultiProfilePagerAdapter.java
index f6382d397d6f..0440f5e92ce4 100644
--- a/core/java/com/android/internal/app/ResolverMultiProfilePagerAdapter.java
+++ b/core/java/com/android/internal/app/ResolverMultiProfilePagerAdapter.java
@@ -20,6 +20,7 @@ import android.annotation.Nullable;
import android.content.Context;
import android.os.UserHandle;
import android.view.LayoutInflater;
+import android.view.View;
import android.view.ViewGroup;
import android.widget.ListView;
@@ -161,6 +162,32 @@ public class ResolverMultiProfilePagerAdapter extends AbstractMultiProfilePagerA
return ResolverActivity.METRICS_CATEGORY_RESOLVER;
}
+ @Override
+ protected void showWorkProfileOffEmptyState(ResolverListAdapter activeListAdapter,
+ View.OnClickListener listener) {
+ showEmptyState(activeListAdapter,
+ R.drawable.ic_work_apps_off,
+ R.string.resolver_turn_on_work_apps_view,
+ /* subtitleRes */ 0,
+ listener);
+ }
+
+ @Override
+ protected void showNoPersonalToWorkIntentsEmptyState(ResolverListAdapter activeListAdapter) {
+ showEmptyState(activeListAdapter,
+ R.drawable.ic_sharing_disabled,
+ R.string.resolver_cant_access_work_apps,
+ R.string.resolver_cant_access_work_apps_explanation);
+ }
+
+ @Override
+ protected void showNoWorkToPersonalIntentsEmptyState(ResolverListAdapter activeListAdapter) {
+ showEmptyState(activeListAdapter,
+ R.drawable.ic_sharing_disabled,
+ R.string.resolver_cant_access_personal_apps,
+ R.string.resolver_cant_access_personal_apps_explanation);
+ }
+
class ResolverProfileDescriptor extends ProfileDescriptor {
private ResolverListAdapter resolverListAdapter;
final ListView listView;
diff --git a/core/java/com/android/internal/compat/CompatibilityChangeInfo.java b/core/java/com/android/internal/compat/CompatibilityChangeInfo.java
index 16628d71712c..ab890d277f43 100644
--- a/core/java/com/android/internal/compat/CompatibilityChangeInfo.java
+++ b/core/java/com/android/internal/compat/CompatibilityChangeInfo.java
@@ -30,6 +30,7 @@ public class CompatibilityChangeInfo implements Parcelable {
private final @Nullable String mName;
private final int mEnableAfterTargetSdk;
private final boolean mDisabled;
+ private final boolean mLoggingOnly;
private final @Nullable String mDescription;
public long getId() {
@@ -49,17 +50,22 @@ public class CompatibilityChangeInfo implements Parcelable {
return mDisabled;
}
+ public boolean getLoggingOnly() {
+ return mLoggingOnly;
+ }
+
public String getDescription() {
return mDescription;
}
public CompatibilityChangeInfo(
Long changeId, String name, int enableAfterTargetSdk, boolean disabled,
- String description) {
+ boolean loggingOnly, String description) {
this.mChangeId = changeId;
this.mName = name;
this.mEnableAfterTargetSdk = enableAfterTargetSdk;
this.mDisabled = disabled;
+ this.mLoggingOnly = loggingOnly;
this.mDescription = description;
}
@@ -68,6 +74,7 @@ public class CompatibilityChangeInfo implements Parcelable {
mName = in.readString();
mEnableAfterTargetSdk = in.readInt();
mDisabled = in.readBoolean();
+ mLoggingOnly = in.readBoolean();
mDescription = in.readString();
}
@@ -82,6 +89,7 @@ public class CompatibilityChangeInfo implements Parcelable {
dest.writeString(mName);
dest.writeInt(mEnableAfterTargetSdk);
dest.writeBoolean(mDisabled);
+ dest.writeBoolean(mLoggingOnly);
dest.writeString(mDescription);
}
diff --git a/core/java/com/android/internal/compat/OverrideAllowedState.java b/core/java/com/android/internal/compat/OverrideAllowedState.java
index 56216c251070..9a78ad2011cf 100644
--- a/core/java/com/android/internal/compat/OverrideAllowedState.java
+++ b/core/java/com/android/internal/compat/OverrideAllowedState.java
@@ -33,7 +33,8 @@ public final class OverrideAllowedState implements Parcelable {
DISABLED_NOT_DEBUGGABLE,
DISABLED_NON_TARGET_SDK,
DISABLED_TARGET_SDK_TOO_HIGH,
- PACKAGE_DOES_NOT_EXIST
+ PACKAGE_DOES_NOT_EXIST,
+ LOGGING_ONLY_CHANGE
})
@Retention(RetentionPolicy.SOURCE)
public @interface State {
@@ -49,7 +50,7 @@ public final class OverrideAllowedState implements Parcelable {
public static final int DISABLED_NOT_DEBUGGABLE = 1;
/**
* Change cannot be overridden, due to the build being non-debuggable and the change being
- * non-targetSdk.
+ * enabled regardless of targetSdk.
*/
public static final int DISABLED_NON_TARGET_SDK = 2;
/**
@@ -60,6 +61,10 @@ public final class OverrideAllowedState implements Parcelable {
* Package does not exist.
*/
public static final int PACKAGE_DOES_NOT_EXIST = 4;
+ /**
+ * Change is marked as logging only, and cannot be toggled.
+ */
+ public static final int LOGGING_ONLY_CHANGE = 5;
@State
public final int state;
@@ -118,6 +123,10 @@ public final class OverrideAllowedState implements Parcelable {
"Cannot override %1$d for %2$s because the package does not exist, and "
+ "the change is targetSdk gated.",
changeId, packageName));
+ case LOGGING_ONLY_CHANGE:
+ throw new SecurityException(String.format(
+ "Cannot override %1$d because it is marked as a logging-only change.",
+ changeId));
}
}
@@ -150,4 +159,28 @@ public final class OverrideAllowedState implements Parcelable {
&& appTargetSdk == otherState.appTargetSdk
&& changeIdTargetSdk == otherState.changeIdTargetSdk;
}
+
+ private String stateName() {
+ switch (state) {
+ case ALLOWED:
+ return "ALLOWED";
+ case DISABLED_NOT_DEBUGGABLE:
+ return "DISABLED_NOT_DEBUGGABLE";
+ case DISABLED_NON_TARGET_SDK:
+ return "DISABLED_NON_TARGET_SDK";
+ case DISABLED_TARGET_SDK_TOO_HIGH:
+ return "DISABLED_TARGET_SDK_TOO_HIGH";
+ case PACKAGE_DOES_NOT_EXIST:
+ return "PACKAGE_DOES_NOT_EXIST";
+ case LOGGING_ONLY_CHANGE:
+ return "LOGGING_ONLY_CHANGE";
+ }
+ return "UNKNOWN";
+ }
+
+ @Override
+ public String toString() {
+ return "OverrideAllowedState(state=" + stateName() + "; appTargetSdk=" + appTargetSdk
+ + "; changeIdTargetSdk=" + changeIdTargetSdk + ")";
+ }
}
diff --git a/core/java/com/android/internal/content/om/OverlayConfig.java b/core/java/com/android/internal/content/om/OverlayConfig.java
index 2b08a773b6e7..fbef027ac37f 100644
--- a/core/java/com/android/internal/content/om/OverlayConfig.java
+++ b/core/java/com/android/internal/content/om/OverlayConfig.java
@@ -21,7 +21,6 @@ import android.annotation.Nullable;
import android.content.pm.PackagePartitions;
import android.content.pm.parsing.ParsingPackageRead;
import android.os.Build;
-import android.os.Process;
import android.os.Trace;
import android.util.ArrayMap;
import android.util.Log;
@@ -186,13 +185,6 @@ public class OverlayConfig {
*/
@NonNull
public static OverlayConfig getZygoteInstance() {
- if (Process.myUid() != Process.ROOT_UID) {
- // Scan the overlays in the zygote process to generate configuration settings for
- // overlays on the system image. Do not cache this instance so OverlayConfig will not
- // be present in applications by default.
- throw new IllegalStateException("Can only be invoked in the root process");
- }
-
Trace.traceBegin(Trace.TRACE_TAG_RRO, "OverlayConfig#getZygoteInstance");
try {
return new OverlayConfig(null /* rootDirectory */, OverlayScanner::new,
@@ -209,13 +201,12 @@ public class OverlayConfig {
*/
@NonNull
public static OverlayConfig initializeSystemInstance(PackageProvider packageProvider) {
- if (Process.myUid() != Process.SYSTEM_UID) {
- throw new IllegalStateException("Can only be invoked in the system process");
- }
-
Trace.traceBegin(Trace.TRACE_TAG_RRO, "OverlayConfig#initializeSystemInstance");
- sInstance = new OverlayConfig(null, null, packageProvider);
- Trace.traceEnd(Trace.TRACE_TAG_RRO);
+ try {
+ sInstance = new OverlayConfig(null, null, packageProvider);
+ } finally {
+ Trace.traceEnd(Trace.TRACE_TAG_RRO);
+ }
return sInstance;
}
@@ -379,10 +370,6 @@ public class OverlayConfig {
*/
@NonNull
public String[] createImmutableFrameworkIdmapsInZygote() {
- if (Process.myUid() != Process.ROOT_UID) {
- throw new IllegalStateException("This method can only be called from the root process");
- }
-
final String targetPath = "/system/framework/framework-res.apk";
final ArrayList<String> idmapPaths = new ArrayList<>();
final ArrayList<IdmapInvocation> idmapInvocations =
diff --git a/core/java/com/android/internal/logging/InstanceId.java b/core/java/com/android/internal/logging/InstanceId.java
index 85643fcffa2f..c90d851201a2 100644
--- a/core/java/com/android/internal/logging/InstanceId.java
+++ b/core/java/com/android/internal/logging/InstanceId.java
@@ -48,6 +48,17 @@ public final class InstanceId implements Parcelable {
return mId;
}
+ /**
+ * Create a fake instance ID for testing purposes. Not for production use. See also
+ * InstanceIdSequenceFake, which is a testing replacement for InstanceIdSequence.
+ * @param id The ID you want to assign.
+ * @return new InstanceId.
+ */
+ @VisibleForTesting
+ public static InstanceId fakeInstanceId(int id) {
+ return new InstanceId(id);
+ }
+
@Override
public int hashCode() {
return mId;
diff --git a/core/java/com/android/internal/logging/testing/UiEventLoggerFake.java b/core/java/com/android/internal/logging/testing/UiEventLoggerFake.java
index 130ee64ac887..91ba0dfbcc54 100644
--- a/core/java/com/android/internal/logging/testing/UiEventLoggerFake.java
+++ b/core/java/com/android/internal/logging/testing/UiEventLoggerFake.java
@@ -20,7 +20,7 @@ import com.android.internal.logging.InstanceId;
import com.android.internal.logging.UiEventLogger;
import java.util.LinkedList;
-import java.util.Queue;
+import java.util.List;
/**
* Fake logger that queues up logged events for inspection.
@@ -52,11 +52,24 @@ public class UiEventLoggerFake implements UiEventLogger {
}
}
- private Queue<FakeUiEvent> mLogs = new LinkedList<>();
+ private List<FakeUiEvent> mLogs = new LinkedList<>();
- public Queue<FakeUiEvent> getLogs() {
+ /** Returns list of all logging events recorded. */
+ public List<FakeUiEvent> getLogs() {
return mLogs;
}
+ /** Returns number of logging events recorded. */
+ public int numLogs() {
+ return mLogs.size();
+ }
+ /** Returns a particular logging event. */
+ public FakeUiEvent get(int index) {
+ return mLogs.get(index);
+ }
+ /** Returns event id (as integer) of a particular logging event. */
+ public int eventId(int index) {
+ return mLogs.get(index).eventId;
+ }
@Override
public void log(UiEventEnum event) {
@@ -67,7 +80,7 @@ public class UiEventLoggerFake implements UiEventLogger {
public void log(UiEventEnum event, int uid, String packageName) {
final int eventId = event.getId();
if (eventId > 0) {
- mLogs.offer(new FakeUiEvent(eventId, uid, packageName));
+ mLogs.add(new FakeUiEvent(eventId, uid, packageName));
}
}
@@ -76,7 +89,7 @@ public class UiEventLoggerFake implements UiEventLogger {
InstanceId instance) {
final int eventId = event.getId();
if (eventId > 0) {
- mLogs.offer(new FakeUiEvent(eventId, uid, packageName, instance));
+ mLogs.add(new FakeUiEvent(eventId, uid, packageName, instance));
}
}
}
diff --git a/core/java/com/android/internal/net/VpnConfig.java b/core/java/com/android/internal/net/VpnConfig.java
index 6d2d7356a2e8..7dc38711a6ef 100644
--- a/core/java/com/android/internal/net/VpnConfig.java
+++ b/core/java/com/android/internal/net/VpnConfig.java
@@ -232,7 +232,7 @@ public class VpnConfig implements Parcelable {
.append(", allowIPv4=").append(allowIPv4)
.append(", allowIPv6=").append(allowIPv6)
.append(", underlyingNetworks=").append(Arrays.toString(underlyingNetworks))
- .append(", proxyInfo=").append(proxyInfo.toString())
+ .append(", proxyInfo=").append(proxyInfo)
.append("}")
.toString();
}
diff --git a/core/java/com/android/internal/util/DataClass.java b/core/java/com/android/internal/util/DataClass.java
index 43539c7c4011..ee139d90888f 100644
--- a/core/java/com/android/internal/util/DataClass.java
+++ b/core/java/com/android/internal/util/DataClass.java
@@ -15,7 +15,13 @@
*/
package com.android.internal.util;
-import static java.lang.annotation.ElementType.*;
+import static java.lang.annotation.ElementType.ANNOTATION_TYPE;
+import static java.lang.annotation.ElementType.CONSTRUCTOR;
+import static java.lang.annotation.ElementType.FIELD;
+import static java.lang.annotation.ElementType.LOCAL_VARIABLE;
+import static java.lang.annotation.ElementType.METHOD;
+import static java.lang.annotation.ElementType.PARAMETER;
+import static java.lang.annotation.ElementType.TYPE;
import android.annotation.IntDef;
import android.annotation.Nullable;
@@ -243,6 +249,13 @@ public @interface DataClass {
}
/**
+ * Mark that the field should have a {@link Nullable} argument for its setter.
+ */
+ @Retention(RetentionPolicy.SOURCE)
+ @Target({FIELD})
+ @interface MaySetToNull {}
+
+ /**
* Callback used by {@link #genForEachField}.
*
* @param <THIS> The enclosing data class instance.
diff --git a/core/java/com/android/internal/widget/ResolverDrawerLayout.java b/core/java/com/android/internal/widget/ResolverDrawerLayout.java
index b117e40cdbb6..c83cab77dd13 100644
--- a/core/java/com/android/internal/widget/ResolverDrawerLayout.java
+++ b/core/java/com/android/internal/widget/ResolverDrawerLayout.java
@@ -121,7 +121,8 @@ public class ResolverDrawerLayout extends ViewGroup {
private final Rect mTempRect = new Rect();
- private AbsListView mNestedScrollingChild;
+ private AbsListView mNestedListChild;
+ private RecyclerView mNestedRecyclerChild;
private final ViewTreeObserver.OnTouchModeChangeListener mTouchModeChangeListener =
new ViewTreeObserver.OnTouchModeChangeListener() {
@@ -347,11 +348,20 @@ public class ResolverDrawerLayout extends ViewGroup {
return mIsDragging || mOpenOnClick;
}
- private boolean isNestedChildScrolled() {
- return mNestedScrollingChild != null
- && mNestedScrollingChild.getChildCount() > 0
- && (mNestedScrollingChild.getFirstVisiblePosition() > 0
- || mNestedScrollingChild.getChildAt(0).getTop() < 0);
+ private boolean isNestedListChildScrolled() {
+ return mNestedListChild != null
+ && mNestedListChild.getChildCount() > 0
+ && (mNestedListChild.getFirstVisiblePosition() > 0
+ || mNestedListChild.getChildAt(0).getTop() < 0);
+ }
+
+ private boolean isNestedRecyclerChildScrolled() {
+ if (mNestedRecyclerChild != null && mNestedRecyclerChild.getChildCount() > 0) {
+ final RecyclerView.ViewHolder vh =
+ mNestedRecyclerChild.findViewHolderForAdapterPosition(0);
+ return vh == null || vh.itemView.getTop() < 0;
+ }
+ return false;
}
@Override
@@ -396,8 +406,10 @@ public class ResolverDrawerLayout extends ViewGroup {
}
if (mIsDragging) {
final float dy = y - mLastTouchY;
- if (dy > 0 && isNestedChildScrolled()) {
- mNestedScrollingChild.smoothScrollBy((int) -dy, 0);
+ if (dy > 0 && isNestedListChildScrolled()) {
+ mNestedListChild.smoothScrollBy((int) -dy, 0);
+ } else if (dy > 0 && isNestedRecyclerChildScrolled()) {
+ mNestedRecyclerChild.scrollBy(0, (int) -dy);
} else {
performDrag(dy);
}
@@ -452,8 +464,10 @@ public class ResolverDrawerLayout extends ViewGroup {
smoothScrollTo(mCollapsibleHeight + mUncollapsibleHeight, yvel);
mDismissOnScrollerFinished = true;
} else {
- if (isNestedChildScrolled()) {
- mNestedScrollingChild.smoothScrollToPosition(0);
+ if (isNestedListChildScrolled()) {
+ mNestedListChild.smoothScrollToPosition(0);
+ } else if (isNestedRecyclerChildScrolled()) {
+ mNestedRecyclerChild.smoothScrollToPosition(0);
}
smoothScrollTo(yvel < 0 ? 0 : mCollapsibleHeight, yvel);
}
@@ -729,8 +743,11 @@ public class ResolverDrawerLayout extends ViewGroup {
@Override
public boolean onStartNestedScroll(View child, View target, int nestedScrollAxes) {
if ((nestedScrollAxes & View.SCROLL_AXIS_VERTICAL) != 0) {
- if (child instanceof AbsListView) {
- mNestedScrollingChild = (AbsListView) child;
+ if (target instanceof AbsListView) {
+ mNestedListChild = (AbsListView) target;
+ }
+ if (target instanceof RecyclerView) {
+ mNestedRecyclerChild = (RecyclerView) target;
}
return true;
}
diff --git a/core/java/com/android/server/SystemConfig.java b/core/java/com/android/server/SystemConfig.java
index 3378c073eace..d40924b603a5 100644
--- a/core/java/com/android/server/SystemConfig.java
+++ b/core/java/com/android/server/SystemConfig.java
@@ -82,6 +82,9 @@ public class SystemConfig {
// property for runtime configuration differentiation
private static final String SKU_PROPERTY = "ro.boot.product.hardware.sku";
+ // property for runtime configuration differentiation in vendor
+ private static final String VENDOR_SKU_PROPERTY = "ro.boot.product.vendor.sku";
+
// Group-ids that are given to all packages as read from etc/permissions/*.xml.
int[] mGlobalGids;
@@ -468,6 +471,17 @@ public class SystemConfig {
readPermissions(Environment.buildPath(
Environment.getVendorDirectory(), "etc", "permissions"), vendorPermissionFlag);
+ String vendorSkuProperty = SystemProperties.get(VENDOR_SKU_PROPERTY, "");
+ if (!vendorSkuProperty.isEmpty()) {
+ String vendorSkuDir = "sku_" + vendorSkuProperty;
+ readPermissions(Environment.buildPath(
+ Environment.getVendorDirectory(), "etc", "sysconfig", vendorSkuDir),
+ vendorPermissionFlag);
+ readPermissions(Environment.buildPath(
+ Environment.getVendorDirectory(), "etc", "permissions", vendorSkuDir),
+ vendorPermissionFlag);
+ }
+
// Allow ODM to customize system configs as much as Vendor, because /odm is another
// vendor partition other than /vendor.
int odmPermissionFlag = vendorPermissionFlag;
diff --git a/core/jni/Android.bp b/core/jni/Android.bp
index ade2c7d86faf..189a0a72e42c 100644
--- a/core/jni/Android.bp
+++ b/core/jni/Android.bp
@@ -1,13 +1,4 @@
-genrule {
- name: "android_util_StatsLogInternal.cpp",
- tools: ["stats-log-api-gen"],
- cmd: "$(location stats-log-api-gen) --jni $(genDir)/android_util_StatsLogInternal.cpp",
- out: [
- "android_util_StatsLogInternal.cpp",
- ],
-}
-
cc_library_shared {
name: "libandroid_runtime",
host_supported: true,
@@ -149,6 +140,7 @@ cc_library_shared {
"android_media_AudioEffectDescriptor.cpp",
"android_media_AudioRecord.cpp",
"android_media_AudioSystem.cpp",
+ "android_media_AudioTrackCallback.cpp",
"android_media_AudioTrack.cpp",
"android_media_AudioAttributes.cpp",
"android_media_AudioProductStrategies.cpp",
@@ -277,7 +269,6 @@ cc_library_shared {
// our headers include libnativewindow's public headers
"libnativewindow",
],
- generated_sources: ["android_util_StatsLogInternal.cpp"],
header_libs: ["bionic_libc_platform_headers"],
},
host: {
diff --git a/core/jni/AndroidRuntime.cpp b/core/jni/AndroidRuntime.cpp
index c41398c97ca0..ba7aef7c208e 100644
--- a/core/jni/AndroidRuntime.cpp
+++ b/core/jni/AndroidRuntime.cpp
@@ -108,7 +108,6 @@ namespace android {
extern int register_android_app_admin_SecurityLog(JNIEnv* env);
extern int register_android_content_AssetManager(JNIEnv* env);
extern int register_android_util_EventLog(JNIEnv* env);
-extern int register_android_util_StatsLogInternal(JNIEnv* env);
extern int register_android_util_Log(JNIEnv* env);
extern int register_android_util_MemoryIntArray(JNIEnv* env);
extern int register_android_content_StringBlock(JNIEnv* env);
@@ -1435,7 +1434,6 @@ static const RegJNIRec gRegJNI[] = {
REG_JNI(register_android_util_EventLog),
REG_JNI(register_android_util_Log),
REG_JNI(register_android_util_MemoryIntArray),
- REG_JNI(register_android_util_StatsLogInternal),
REG_JNI(register_android_app_admin_SecurityLog),
REG_JNI(register_android_content_AssetManager),
REG_JNI(register_android_content_StringBlock),
diff --git a/core/jni/android_media_AudioTrack.cpp b/core/jni/android_media_AudioTrack.cpp
index a888b43a4854..13518186376d 100644
--- a/core/jni/android_media_AudioTrack.cpp
+++ b/core/jni/android_media_AudioTrack.cpp
@@ -31,13 +31,14 @@
#include <binder/MemoryHeapBase.h>
#include <binder/MemoryBase.h>
-#include "android_media_AudioFormat.h"
+#include "android_media_AudioAttributes.h"
#include "android_media_AudioErrors.h"
+#include "android_media_AudioFormat.h"
+#include "android_media_AudioTrackCallback.h"
+#include "android_media_DeviceCallback.h"
#include "android_media_MediaMetricsJNI.h"
#include "android_media_PlaybackParams.h"
-#include "android_media_DeviceCallback.h"
#include "android_media_VolumeShaper.h"
-#include "android_media_AudioAttributes.h"
#include <cinttypes>
@@ -75,22 +76,12 @@ struct audiotrack_callback_cookie {
// ----------------------------------------------------------------------------
class AudioTrackJniStorage {
- public:
- sp<MemoryHeapBase> mMemHeap;
- sp<MemoryBase> mMemBase;
- audiotrack_callback_cookie mCallbackData;
- sp<JNIDeviceCallback> mDeviceCallback;
-
- AudioTrackJniStorage() {
- mCallbackData.audioTrack_class = 0;
- mCallbackData.audioTrack_ref = 0;
- mCallbackData.isOffload = false;
- }
-
- ~AudioTrackJniStorage() {
- mMemBase.clear();
- mMemHeap.clear();
- }
+public:
+ sp<MemoryHeapBase> mMemHeap;
+ sp<MemoryBase> mMemBase;
+ audiotrack_callback_cookie mCallbackData{};
+ sp<JNIDeviceCallback> mDeviceCallback;
+ sp<JNIAudioTrackCallback> mAudioTrackCallback;
bool allocSharedMem(int sizeInBytes) {
mMemHeap = new MemoryHeapBase(sizeInBytes, 0, "AudioTrack Heap Base");
@@ -459,6 +450,10 @@ static jint android_media_AudioTrack_setup(JNIEnv *env, jobject thiz, jobject we
lpJniStorage->mCallbackData.audioTrack_ref = env->NewGlobalRef(weak_this);
lpJniStorage->mCallbackData.busy = false;
}
+ lpJniStorage->mAudioTrackCallback =
+ new JNIAudioTrackCallback(env, thiz, lpJniStorage->mCallbackData.audioTrack_ref,
+ javaAudioTrackFields.postNativeEventInJava);
+ lpTrack->setAudioTrackCallback(lpJniStorage->mAudioTrackCallback);
nSession = (jint *) env->GetPrimitiveArrayCritical(jSession, NULL);
if (nSession == NULL) {
diff --git a/core/jni/android_media_AudioTrackCallback.cpp b/core/jni/android_media_AudioTrackCallback.cpp
new file mode 100644
index 000000000000..d97566b87adc
--- /dev/null
+++ b/core/jni/android_media_AudioTrackCallback.cpp
@@ -0,0 +1,99 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+//#define LOG_NDEBUG 0
+
+#define LOG_TAG "AudioTrackCallback-JNI"
+
+#include <algorithm>
+
+#include <nativehelper/JNIHelp.h>
+#include <utils/Errors.h>
+#include <utils/Log.h>
+
+#include "android_media_AudioTrackCallback.h"
+#include "core_jni_helpers.h"
+
+using namespace android;
+
+#define BYTE_BUFFER_NAME "java/nio/ByteBuffer"
+#define BYTE_BUFFER_ALLOCATE_DIRECT_NAME "allocateDirect"
+
+JNIAudioTrackCallback::JNIAudioTrackCallback(JNIEnv* env, jobject thiz, jobject weak_thiz,
+ jmethodID postEventFromNative) {
+ // Hold onto the AudioTrack class for use in calling the static method
+ // that posts events to the application thread.
+ jclass clazz = env->GetObjectClass(thiz);
+ if (clazz == nullptr) {
+ return;
+ }
+ mClass = (jclass)env->NewGlobalRef(clazz);
+
+ // We use a weak reference so the AudioTrack object can be garbage collected.
+ // The reference is only used as a proxy for callbacks.
+ mObject = env->NewGlobalRef(weak_thiz);
+
+ mPostEventFromNative = postEventFromNative;
+
+ jclass byteBufferClass = FindClassOrDie(env, BYTE_BUFFER_NAME);
+ mByteBufferClass = (jclass)env->NewGlobalRef(byteBufferClass);
+ mAllocateDirectMethod =
+ GetStaticMethodIDOrDie(env, mByteBufferClass, BYTE_BUFFER_ALLOCATE_DIRECT_NAME,
+ "(I)Ljava/nio/ByteBuffer;");
+}
+
+JNIAudioTrackCallback::~JNIAudioTrackCallback() {
+ // remove global references
+ JNIEnv* env = AndroidRuntime::getJNIEnv();
+ if (env == nullptr) {
+ return;
+ }
+ env->DeleteGlobalRef(mObject);
+ env->DeleteGlobalRef(mClass);
+ env->DeleteGlobalRef(mByteBufferClass);
+}
+
+binder::Status JNIAudioTrackCallback::onCodecFormatChanged(
+ const std::vector<uint8_t>& audioMetadata) {
+ JNIEnv* env = AndroidRuntime::getJNIEnv();
+ if (env == nullptr) {
+ return binder::Status::ok();
+ }
+
+ jobject byteBuffer = env->CallStaticObjectMethod(mByteBufferClass, mAllocateDirectMethod,
+ (jint)audioMetadata.size());
+ if (env->ExceptionCheck()) {
+ ALOGW("An exception occurred while allocating direct buffer");
+ env->ExceptionDescribe();
+ env->ExceptionClear();
+ }
+ if (byteBuffer == nullptr) {
+ ALOGE("Failed allocating a direct ByteBuffer");
+ return binder::Status::fromStatusT(NO_MEMORY);
+ }
+
+ uint8_t* byteBufferAddr = (uint8_t*)env->GetDirectBufferAddress(byteBuffer);
+ std::copy(audioMetadata.begin(), audioMetadata.end(), byteBufferAddr);
+ env->CallStaticVoidMethod(mClass, mPostEventFromNative, mObject,
+ AUDIO_NATIVE_EVENT_CODEC_FORMAT_CHANGE, 0, 0, byteBuffer);
+ if (env->ExceptionCheck()) {
+ ALOGW("An exception occurred while notifying codec format changed.");
+ env->ExceptionDescribe();
+ env->ExceptionClear();
+ }
+
+ return binder::Status::ok();
+}
diff --git a/core/jni/android_media_AudioTrackCallback.h b/core/jni/android_media_AudioTrackCallback.h
new file mode 100644
index 000000000000..3b8a8bb1bba8
--- /dev/null
+++ b/core/jni/android_media_AudioTrackCallback.h
@@ -0,0 +1,45 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef ANDROID_MEDIA_AUDIO_TRACK_CALLBACK_H
+#define ANDROID_MEDIA_AUDIO_TRACK_CALLBACK_H
+
+#include <android/media/BnAudioTrackCallback.h>
+
+namespace android {
+
+#define AUDIO_NATIVE_EVENT_CODEC_FORMAT_CHANGE 100
+
+// TODO(b/149870866) : Extract common part for JNIAudioTrackCallback and JNIDeviceCallback
+class JNIAudioTrackCallback : public media::BnAudioTrackCallback {
+public:
+ JNIAudioTrackCallback(JNIEnv* env, jobject thiz, jobject weak_thiz,
+ jmethodID postEventFromNative);
+ ~JNIAudioTrackCallback() override;
+
+ binder::Status onCodecFormatChanged(const std::vector<uint8_t>& audioMetadata) override;
+
+private:
+ jclass mClass; // Reference to AudioTrack class
+ jobject mObject; // Weak ref to AudioTrack Java object to call on
+ jmethodID mPostEventFromNative; // postEventFromNative method ID
+ jclass mByteBufferClass; // Reference to ByteBuffer class
+ jmethodID mAllocateDirectMethod; // ByteBuffer.allocateDirect method ID
+};
+
+}; // namespace android
+
+#endif // ANDROID_MEDIA_AUDIO_TRACK_CALLBACK_H
diff --git a/core/jni/com_android_internal_os_Zygote.cpp b/core/jni/com_android_internal_os_Zygote.cpp
index 4e139a34c555..2128f99ff609 100644
--- a/core/jni/com_android_internal_os_Zygote.cpp
+++ b/core/jni/com_android_internal_os_Zygote.cpp
@@ -134,6 +134,11 @@ static jmethodID gCreateSystemServerClassLoader;
static bool gIsSecurityEnforced = true;
/**
+ * True if the app process is running in its mount namespace.
+ */
+static bool gInAppMountNamespace = false;
+
+/**
* The maximum number of characters (not including a null terminator) that a
* process name may contain.
*/
@@ -548,6 +553,17 @@ static void SetGids(JNIEnv* env, jintArray managed_gids, fail_fn_t fail_fn) {
}
}
+static void ensureInAppMountNamespace(fail_fn_t fail_fn) {
+ if (gInAppMountNamespace) {
+ // In app mount namespace already
+ return;
+ }
+ if (unshare(CLONE_NEWNS) == -1) {
+ fail_fn(CREATE_ERROR("Failed to unshare(): %s", strerror(errno)));
+ }
+ gInAppMountNamespace = true;
+}
+
// Sets the resource limits via setrlimit(2) for the values in the
// two-dimensional array of integers that's passed in. The second dimension
// contains a tuple of length 3: (resource, rlim_cur, rlim_max). nullptr is
@@ -811,9 +827,7 @@ static void MountEmulatedStorage(uid_t uid, jint mount_mode,
}
// Create a second private mount namespace for our process
- if (unshare(CLONE_NEWNS) == -1) {
- fail_fn(CREATE_ERROR("Failed to unshare(): %s", strerror(errno)));
- }
+ ensureInAppMountNamespace(fail_fn);
// Handle force_mount_namespace with MOUNT_EXTERNAL_NONE.
if (mount_mode == MOUNT_EXTERNAL_NONE) {
@@ -1319,6 +1333,7 @@ static void isolateAppData(JNIEnv* env, jobjectArray pkg_data_info_list,
if ((size % 3) != 0) {
fail_fn(CREATE_ERROR("Wrong pkg_inode_list size %d", size));
}
+ ensureInAppMountNamespace(fail_fn);
// Mount tmpfs on all possible data directories, so app no longer see the original apps data.
char internalCePath[PATH_MAX];
diff --git a/core/jni/fd_utils.cpp b/core/jni/fd_utils.cpp
index cfd3c0915002..c72668f84fb1 100644
--- a/core/jni/fd_utils.cpp
+++ b/core/jni/fd_utils.cpp
@@ -33,7 +33,6 @@
// Static whitelist of open paths that the zygote is allowed to keep open.
static const char* kPathWhitelist[] = {
- "/apex/com.android.appsearch/javalib/framework-appsearch.jar",
"/apex/com.android.conscrypt/javalib/conscrypt.jar",
"/apex/com.android.ipsec/javalib/ike.jar",
"/apex/com.android.media/javalib/updatable-media.jar",
diff --git a/core/proto/android/app/appexit_enums.proto b/core/proto/android/app/appexit_enums.proto
new file mode 100644
index 000000000000..491e1dc203b5
--- /dev/null
+++ b/core/proto/android/app/appexit_enums.proto
@@ -0,0 +1,240 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+syntax = "proto2";
+option java_multiple_files = true;
+
+package android.app;
+
+/**
+ * The reason code that why app process is killed.
+ */
+enum AppExitReasonCode {
+ /**
+ * Application process died due to unknown reason.
+ */
+ REASON_UNKNOWN = 0;
+
+ /**
+ * Application process exit normally by itself, for example,
+ * via {@link android.os.Process#exit}; {@link #status} will specify the exit code.
+ *
+ * <p>Applications should normally not do this, as the system has a better knowledge
+ * in terms of process management.</p>
+ */
+ REASON_EXIT_SELF = 1;
+
+ /**
+ * Application process died due to the result of an OS signal; for example,
+ * {@link android.os.Process#SIGNAL_KILL}; {@link #status} will specify the signum.
+ */
+ REASON_SIGNALED = 2;
+
+ /**
+ * Application process was killed by the system low memory killer, meaning the system was
+ * under memory pressure at the time of kill.
+ */
+ REASON_LOW_MEMORY = 3;
+
+ /**
+ * Application process died because of an unhandled exception in Java code.
+ */
+ REASON_CRASH = 4;
+
+ /**
+ * Application process died because it's crashed due to a native code crash.
+ */
+ REASON_CRASH_NATIVE = 5;
+
+ /**
+ * Application process was killed due to being unresponsive (ANR).
+ */
+ REASON_ANR = 6;
+
+ /**
+ * Application process was killed because it took too long to attach to the system
+ * during the start.
+ */
+ REASON_INITIALIZATION_FAILURE = 7;
+
+ /**
+ * Application process was killed because of initialization failure,
+ * for example, it took too long to attach to the system during the start,
+ * or there was an error during initialization.
+ */
+ REASON_PERMISSION_CHANGE = 8;
+
+ /**
+ * Application process was killed by the activity manager due to excessive resource usage.
+ */
+ REASON_EXCESSIVE_RESOURCE_USAGE = 9;
+
+ /**
+ * Application process was killed because of the user request, for example,
+ * user clicked the "Force stop" button of the application in the Settings,
+ * or swiped away the application from Recents.
+ */
+ REASON_USER_REQUESTED = 10;
+
+ /**
+ * Application process was killed, because the user they are running as on devices
+ * with mutlple users, was stopped.
+ */
+ REASON_USER_STOPPED = 11;
+
+ /**
+ * Application process was killed because its dependency was going away, for example,
+ * a stable content provider connection's client will be killed if the provider is killed.
+ */
+ REASON_DEPENDENCY_DIED = 12;
+
+ /**
+ * Application process was killed by the system for various other reasons,
+ * for example, the application package got disabled by the user;
+ * {@link #description} will specify the cause given by the system.
+ */
+ REASON_OTHER = 13;
+}
+
+/**
+ * The supplemental reason code that why app process is killed
+ */
+enum AppExitSubReasonCode {
+ /**
+ * Application process kills subReason is unknown.
+ */
+ SUBREASON_UNKNOWN = 0;
+
+ /**
+ * Application process was killed because user quit it on the "wait for debugger" dialog.
+ */
+ SUBREASON_WAIT_FOR_DEBUGGER = 1;
+
+ /**
+ * Application process was killed by the activity manager because there were too many cached
+ * processes.
+ */
+ SUBREASON_TOO_MANY_CACHED = 2;
+
+ /**
+ * Application process was killed by the activity manager because there were too many empty
+ * processes.
+ */
+ SUBREASON_TOO_MANY_EMPTY = 3;
+
+ /**
+ * Application process was killed by the activity manager because there were too many cached
+ * processes and this process had been in empty state for a long time.
+ */
+ SUBREASON_TRIM_EMPTY = 4;
+
+ /**
+ * Application process was killed by the activity manager because system was on
+ * memory pressure and this process took large amount of cached memory.
+ */
+ SUBREASON_LARGE_CACHED = 5;
+
+ /**
+ * Application process was killed by the activity manager because the system was on
+ * low memory pressure for a significant amount of time since last idle.
+ */
+ SUBREASON_MEMORY_PRESSURE = 6;
+
+ /**
+ * Application process was killed by the activity manager due to excessive CPU usage.
+ */
+ SUBREASON_EXCESSIVE_CPU = 7;
+
+ /**
+ * System update has done (so the system update process should be killed).
+ */
+ SUBREASON_SYSTEM_UPDATE_DONE = 8;
+
+ /**
+ * Kill all foreground services, for now it only occurs when enabling the quiet
+ * mode for the managed profile.
+ */
+ SUBREASON_KILL_ALL_FG = 9;
+
+ /**
+ * All background processes except certain ones were killed, for now it only occurs
+ * when the density of the default display is changed.
+ */
+ SUBREASON_KILL_ALL_BG_EXCEPT = 10;
+
+ /**
+ * The process associated with the UID was explicitly killed, for example,
+ * it could be because of permission changes.
+ */
+ SUBREASON_KILL_UID = 11;
+
+ /**
+ * The process was explicitly killed with its PID, typically because of
+ * the low memory for surfaces.
+ */
+ SUBREASON_KILL_PID = 12;
+
+ /**
+ * The start of the process was invalid.
+ */
+ SUBREASON_INVALID_START = 13;
+
+ /**
+ * The process was killed because it's in an invalid state, typically
+ * it's triggered from SHELL.
+ */
+ SUBREASON_INVALID_STATE = 14;
+
+ /**
+ * The process was killed when it's imperceptible to user, because it was
+ * in a bad state.
+ */
+ SUBREASON_IMPERCEPTIBLE = 15;
+
+ /**
+ * The process was killed because it's being moved out from LRU list.
+ */
+ SUBREASON_REMOVE_LRU = 16;
+
+ /**
+ * The process was killed because it's isolated and was in a cached state.
+ */
+ SUBREASON_ISOLATED_NOT_NEEDED = 17;
+}
+
+/**
+ * The relative importance level that the system places on a process.
+ * Keep sync with the definitions in
+ * {@link android.app.ActivityManager.RunningAppProcessInfo}
+ */
+enum Importance {
+ option allow_alias = true;
+
+ IMPORTANCE_FOREGROUND = 100;
+ IMPORTANCE_FOREGROUND_SERVICE = 125;
+ IMPORTANCE_TOP_SLEEPING_PRE_28 = 150;
+ IMPORTANCE_VISIBLE = 200;
+ IMPORTANCE_PERCEPTIBLE_PRE_26 = 130;
+ IMPORTANCE_PERCEPTIBLE = 230;
+ IMPORTANCE_CANT_SAVE_STATE_PRE_26 = 170;
+ IMPORTANCE_SERVICE = 300;
+ IMPORTANCE_TOP_SLEEPING = 325;
+ IMPORTANCE_CANT_SAVE_STATE = 350;
+ IMPORTANCE_CACHED = 400;
+ IMPORTANCE_BACKGROUND = 400;
+ IMPORTANCE_EMPTY = 500;
+ IMPORTANCE_GONE = 1000;
+}
diff --git a/core/proto/android/app/appexitinfo.proto b/core/proto/android/app/appexitinfo.proto
index 6a4922000805..66173f60bfd5 100644
--- a/core/proto/android/app/appexitinfo.proto
+++ b/core/proto/android/app/appexitinfo.proto
@@ -20,6 +20,7 @@ option java_multiple_files = true;
package android.app;
import "frameworks/base/core/proto/android/privacy.proto";
+import "frameworks/base/core/proto/android/app/appexit_enums.proto";
/**
* An android.app.ApplicationExitInfo object.
@@ -33,150 +34,9 @@ message ApplicationExitInfoProto {
optional int32 defining_uid = 4;
optional string process_name = 5;
optional int32 connection_group = 6;
-
- enum ReasonCode {
- /**
- * Application process died due to unknown reason.
- */
- REASON_UNKNOWN = 0;
-
- /**
- * Application process exit normally by itself, for example,
- * via {@link android.os.Process#exit}; {@link #status} will specify the exit code.
- *
- * <p>Applications should normally not do this, as the system has a better knowledge
- * in terms of process management.</p>
- */
- REASON_EXIT_SELF = 1;
-
- /**
- * Application process died due to the result of an OS signal; for example,
- * {@link android.os.Process#SIGNAL_KILL}; {@link #status} will specify the signum.
- */
- REASON_SIGNALED = 2;
-
- /**
- * Application process was killed by the system low memory killer, meaning the system was
- * under memory pressure at the time of kill.
- */
- REASON_LOW_MEMORY = 3;
-
- /**
- * Application process died because of an unhandled exception in Java code.
- */
- REASON_CRASH = 4;
-
- /**
- * Application process died because it's crashed due to a native code crash.
- */
- REASON_CRASH_NATIVE = 5;
-
- /**
- * Application process was killed due to being unresponsive (ANR).
- */
- REASON_ANR = 6;
-
- /**
- * Application process was killed because it took too long to attach to the system
- * during the start.
- */
- REASON_INITIALIZATION_FAILURE = 7;
-
- /**
- * Application process was killed because of initialization failure,
- * for example, it took too long to attach to the system during the start,
- * or there was an error during initialization.
- */
- REASON_PERMISSION_CHANGE = 8;
-
- /**
- * Application process was killed by the activity manager due to excessive resource usage.
- */
- REASON_EXCESSIVE_RESOURCE_USAGE = 9;
-
- /**
- * Application process was killed by the system for various other reasons,
- * for example, the application package got disabled by the user;
- * {@link #description} will specify the cause given by the system.
- */
- REASON_OTHER = 10;
-
- }
- optional ReasonCode reason = 7;
-
- enum SubReason {
- /**
- * Application process kills subReason is unknown.
- */
- SUBREASON_UNKNOWN = 0;
-
- /**
- * Application process was killed because user quit it on the "wait for debugger" dialog.
- */
- SUBREASON_WAIT_FOR_DEBUGGER = 1;
-
- /**
- * Application process was killed by the activity manager because there were too many cached
- * processes.
- */
- SUBREASON_TOO_MANY_CACHED = 2;
-
- /**
- * Application process was killed by the activity manager because there were too many empty
- * processes.
- */
- SUBREASON_TOO_MANY_EMPTY = 3;
-
- /**
- * Application process was killed by the activity manager because there were too many cached
- * processes and this process had been in empty state for a long time.
- */
- SUBREASON_TRIM_EMPTY = 4;
-
- /**
- * Application process was killed by the activity manager because system was on
- * memory pressure and this process took large amount of cached memory.
- */
- SUBREASON_LARGE_CACHED = 5;
-
- /**
- * Application process was killed by the activity manager because the system was on
- * low memory pressure for a significant amount of time since last idle.
- */
- SUBREASON_MEMORY_PRESSURE = 6;
-
- /**
- * Application process was killed by the activity manager due to excessive CPU usage.
- */
- SUBREASON_EXCESSIVE_CPU = 7;
- }
-
- optional SubReason sub_reason = 8;
-
+ optional AppExitReasonCode reason = 7;
+ optional AppExitSubReasonCode sub_reason = 8;
optional int32 status = 9;
-
- enum Importance {
- option allow_alias = true;
- /**
- * Keep sync with the definitions in
- * {@link android.app.ActivityManager.RunningAppProcessInfo}
- */
- IMPORTANCE_FOREGROUND = 100;
- IMPORTANCE_FOREGROUND_SERVICE = 125;
- IMPORTANCE_TOP_SLEEPING_PRE_28 = 150;
- IMPORTANCE_VISIBLE = 200;
- IMPORTANCE_PERCEPTIBLE_PRE_26 = 130;
- IMPORTANCE_PERCEPTIBLE = 230;
- IMPORTANCE_CANT_SAVE_STATE_PRE_26 = 170;
- IMPORTANCE_SERVICE = 300;
- IMPORTANCE_TOP_SLEEPING = 325;
- IMPORTANCE_CANT_SAVE_STATE = 350;
- IMPORTANCE_CACHED = 400;
- IMPORTANCE_BACKGROUND = 400;
- IMPORTANCE_EMPTY = 500;
- IMPORTANCE_GONE = 1000;
- }
-
optional Importance importance = 10;
optional int64 pss = 11;
optional int64 rss = 12;
diff --git a/core/proto/android/bluetooth/enums.proto b/core/proto/android/bluetooth/enums.proto
index b4f3d1ea5ae4..22f249820b11 100644
--- a/core/proto/android/bluetooth/enums.proto
+++ b/core/proto/android/bluetooth/enums.proto
@@ -40,6 +40,7 @@ enum EnableDisableReasonEnum {
ENABLE_DISABLE_REASON_CRASH = 7;
ENABLE_DISABLE_REASON_USER_SWITCH = 8;
ENABLE_DISABLE_REASON_RESTORE_USER_SETTING = 9;
+ ENABLE_DISABLE_REASON_FACTORY_RESET = 10;
}
enum DirectionEnum {
diff --git a/core/proto/android/providers/settings/config.proto b/core/proto/android/providers/settings/config.proto
index cc2419614d93..b0a70ef56dbc 100644
--- a/core/proto/android/providers/settings/config.proto
+++ b/core/proto/android/providers/settings/config.proto
@@ -47,6 +47,7 @@ message ConfigSettingsProto {
repeated SettingProto systemui_settings = 20;
repeated SettingProto telephony_settings = 21;
repeated SettingProto textclassifier_settings = 22;
+ repeated SettingProto blobstore_settings = 23;
message NamespaceProto {
optional string namespace = 1;
diff --git a/core/proto/android/providers/settings/secure.proto b/core/proto/android/providers/settings/secure.proto
index 6d9e8ab776b7..a3313b21131d 100644
--- a/core/proto/android/providers/settings/secure.proto
+++ b/core/proto/android/providers/settings/secure.proto
@@ -77,6 +77,7 @@ message SecureSettingsProto {
optional SettingProto interactive_ui_timeout_ms = 33 [ (android.privacy).dest = DEST_AUTOMATIC ];
// Settings for magnification mode
optional SettingProto accessibility_magnification_mode = 34 [ (android.privacy).dest = DEST_AUTOMATIC ];
+ optional SettingProto button_long_press_targets = 35 [ (android.privacy).dest = DEST_AUTOMATIC ];
}
optional Accessibility accessibility = 2;
diff --git a/core/proto/android/server/windowmanagerservice.proto b/core/proto/android/server/windowmanagerservice.proto
index e8a0b46e8430..60892557891b 100644
--- a/core/proto/android/server/windowmanagerservice.proto
+++ b/core/proto/android/server/windowmanagerservice.proto
@@ -53,10 +53,10 @@ message RootWindowContainerProto {
option (.android.msg_privacy).dest = DEST_AUTOMATIC;
optional WindowContainerProto window_container = 1;
- repeated DisplayContentProto displays = 2;
+ repeated DisplayContentProto displays = 2 [deprecated=true];
reserved 3; // IdentifierProto windows
/* window references in top down z order */
- repeated WindowStateProto windows = 4;
+ repeated WindowStateProto windows = 4 [deprecated=true];
optional KeyguardControllerProto keyguard_controller = 5;
// Whether or not the home activity is the recents activity. This is needed for the CTS tests to
// know what activity types to check for when invoking splitscreen multi-window.
@@ -192,7 +192,8 @@ message DisplayContentProto {
optional bool single_task_instance = 22;
optional int32 focused_root_task_id = 23;
optional .com.android.server.wm.IdentifierProto resumed_activity = 24;
- repeated TaskProto tasks = 25;
+ repeated TaskProto tasks = 25 [deprecated=true];
+ optional bool display_ready = 26;
}
/* represents DisplayArea object */
@@ -201,7 +202,7 @@ message DisplayAreaProto {
optional WindowContainerProto window_container = 1;
optional string name = 2 [ (.android.privacy).dest = DEST_EXPLICIT ];
- repeated DisplayAreaChildProto children = 3;
+ repeated DisplayAreaChildProto children = 3 [deprecated=true];
}
/* represents a generic child of a DisplayArea */
@@ -254,8 +255,8 @@ message TaskProto {
optional int32 surface_width = 8;
optional int32 surface_height = 9;
- repeated TaskProto tasks = 10;
- repeated ActivityRecordProto activities = 11;
+ repeated TaskProto tasks = 10 [deprecated=true];
+ repeated ActivityRecordProto activities = 11 [deprecated=true];
optional .com.android.server.wm.IdentifierProto resumed_activity = 12;
optional string real_activity = 13;
@@ -321,7 +322,7 @@ message WindowTokenProto {
optional WindowContainerProto window_container = 1;
optional int32 hash_code = 2;
- repeated WindowStateProto windows = 3;
+ repeated WindowStateProto windows = 3 [deprecated=true];
optional bool waiting_to_show = 5;
optional bool paused = 6;
}
@@ -346,7 +347,7 @@ message WindowStateProto {
optional .android.graphics.RectProto surface_insets = 12;
optional WindowStateAnimatorProto animator = 13;
optional bool animating_exit = 14;
- repeated WindowStateProto child_windows = 15;
+ repeated WindowStateProto child_windows = 15 [deprecated=true];
optional .android.graphics.RectProto surface_position = 16;
optional int32 requested_width = 18;
optional int32 requested_height = 19;
@@ -426,6 +427,32 @@ message WindowContainerProto {
optional int32 orientation = 2;
optional bool visible = 3;
optional SurfaceAnimatorProto surface_animator = 4;
+ repeated WindowContainerChildProto children = 5;
+}
+
+/* represents a generic child of a WindowContainer */
+message WindowContainerChildProto {
+ option (.android.msg_privacy).dest = DEST_AUTOMATIC;
+
+ /* A window container can have multiple children of different types stored as
+ * a WindowContainerChildProto but each instance of WindowContainerChildProto
+ * can only contain a single type.
+ */
+ /* We do not know the derived typ and the class is dumped
+ * as a WindowContainer */
+ optional WindowContainerProto window_container = 2;
+ /* represents a DisplayContent child */
+ optional DisplayContentProto display_content = 3;
+ /* represents a DisplayArea child */
+ optional DisplayAreaProto display_area = 4;
+ /* represents a Task child */
+ optional TaskProto task = 5;
+ /* represents an ActivityRecord child */
+ optional ActivityRecordProto activity = 6;
+ /* represents a WindowToken child */
+ optional WindowTokenProto window_token = 7;
+ /* represents a WindowState child */
+ optional WindowStateProto window = 8;
}
/* represents ConfigurationContainer */
diff --git a/core/proto/android/view/remote_animation_target.proto b/core/proto/android/view/remote_animation_target.proto
index 24d27858bd20..150493d251c6 100644
--- a/core/proto/android/view/remote_animation_target.proto
+++ b/core/proto/android/view/remote_animation_target.proto
@@ -44,4 +44,6 @@ message RemoteAnimationTargetProto {
optional .android.app.WindowConfigurationProto window_configuration = 10;
optional .android.view.SurfaceControlProto start_leash = 11;
optional .android.graphics.RectProto start_bounds = 12;
+ optional .android.graphics.RectProto local_bounds = 13;
+ optional .android.graphics.RectProto screen_space_bounds = 14;
}
diff --git a/core/res/res/drawable/ic_pan_tool.xml b/core/res/res/drawable/ic_pan_tool.xml
new file mode 100644
index 000000000000..c1a8549b2141
--- /dev/null
+++ b/core/res/res/drawable/ic_pan_tool.xml
@@ -0,0 +1,26 @@
+<!--
+ Copyright (C) 2020 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="24dp"
+ android:height="24dp"
+ android:viewportWidth="24"
+ android:viewportHeight="24"
+ android:tint="?attr/colorControlNormal">
+ <path
+ android:pathData="M23,5.5V20c0,2.2 -1.8,4 -4,4h-7.3c-1.08,0 -2.1,-0.43 -2.85,-1.19L1,14.83c0,0 1.26,-1.23 1.3,-1.25c0.22,-0.19 0.49,-0.29 0.79,-0.29c0.22,0 0.42,0.06 0.6,0.16C3.73,13.46 8,15.91 8,15.91V4c0,-0.83 0.67,-1.5 1.5,-1.5S11,3.17 11,4v7h1V1.5C12,0.67 12.67,0 13.5,0S15,0.67 15,1.5V11h1V2.5C16,1.67 16.67,1 17.5,1S19,1.67 19,2.5V11h1V5.5C20,4.67 20.67,4 21.5,4S23,4.67 23,5.5z"
+ android:fillColor="#FFFFFF"/>
+</vector>
diff --git a/core/res/res/drawable/ic_delete_item.xml b/core/res/res/drawable/ic_visibility.xml
index 8a398a44635e..195624156999 100644
--- a/core/res/res/drawable/ic_delete_item.xml
+++ b/core/res/res/drawable/ic_visibility.xml
@@ -12,7 +12,7 @@
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
- -->
+-->
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
@@ -21,6 +21,6 @@
android:viewportHeight="24"
android:tint="?attr/colorControlNormal">
<path
- android:pathData="M6,19c0,1.1 0.9,2 2,2h8c1.1,0 2,-0.9 2,-2V7H6v12zM19,4h-3.5l-1,-1h-5l-1,1H5v2h14V4z"
+ android:pathData="M12,4.5C7,4.5 2.73,7.61 1,12c1.73,4.39 6,7.5 11,7.5s9.27,-3.11 11,-7.5c-1.73,-4.39 -6,-7.5 -11,-7.5zM12,17c-2.76,0 -5,-2.24 -5,-5s2.24,-5 5,-5 5,2.24 5,5 -2.24,5 -5,5zM12,9c-1.66,0 -3,1.34 -3,3s1.34,3 3,3 3,-1.34 3,-3 -1.34,-3 -3,-3z"
android:fillColor="#FFFFFF"/>
</vector>
diff --git a/core/res/res/layout/accessibility_button_chooser_item.xml b/core/res/res/layout/accessibility_button_chooser_item.xml
index d19e313055ae..b7dd892fd161 100644
--- a/core/res/res/layout/accessibility_button_chooser_item.xml
+++ b/core/res/res/layout/accessibility_button_chooser_item.xml
@@ -21,10 +21,17 @@
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="center"
- android:paddingStart="16dp"
- android:paddingEnd="16dp"
- android:paddingTop="12dp"
- android:paddingBottom="12dp">
+ android:padding="16dp">
+
+ <CheckBox
+ android:id="@+id/accessibility_button_target_checkbox"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:paddingStart="16dp"
+ android:background="@null"
+ android:clickable="false"
+ android:focusable="false"
+ android:visibility="gone"/>
<ImageView
android:id="@+id/accessibility_button_target_icon"
@@ -36,29 +43,18 @@
android:id="@+id/accessibility_button_target_label"
android:layout_width="0dp"
android:layout_height="wrap_content"
- android:layout_marginStart="14dp"
+ android:layout_marginStart="16dp"
android:layout_weight="1"
- android:textColor="?attr/textColorPrimary"/>
+ android:textSize="20sp"
+ android:textColor="?attr/textColorPrimary"
+ android:fontFamily="sans-serif-medium"/>
- <FrameLayout
- android:id="@+id/accessibility_button_target_item_container"
+ <Switch
+ android:id="@+id/accessibility_button_target_switch_item"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
- android:minWidth="56dp">
-
- <ImageView
- android:id="@+id/accessibility_button_target_view_item"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:layout_gravity="center"/>
-
- <Switch android:id="@+id/accessibility_button_target_switch_item"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:layout_gravity="center"
- android:background="@null"
- android:clickable="false"
- android:focusable="false"/>
- </FrameLayout>
+ android:background="@null"
+ android:clickable="false"
+ android:focusable="false"/>
</LinearLayout>
diff --git a/core/res/res/layout/accessibility_enable_service_encryption_warning.xml b/core/res/res/layout/accessibility_enable_service_encryption_warning.xml
new file mode 100644
index 000000000000..400051660592
--- /dev/null
+++ b/core/res/res/layout/accessibility_enable_service_encryption_warning.xml
@@ -0,0 +1,175 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Copyright (C) 2020 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+
+<ScrollView
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:textDirection="locale"
+ android:scrollbarStyle="outsideOverlay">
+
+ <LinearLayout
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:gravity="center"
+ android:orientation="vertical">
+
+ <LinearLayout
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:paddingStart="24dp"
+ android:paddingEnd="24dp"
+ android:gravity="center"
+ android:orientation="vertical">
+
+ <ImageView
+ android:id="@+id/accessibility_permissionDialog_icon"
+ android:layout_width="36dp"
+ android:layout_height="36dp"
+ android:layout_marginTop="16dp"
+ android:layout_marginBottom="16dp"
+ android:scaleType="fitCenter"/>
+
+ <TextView
+ android:id="@+id/accessibility_permissionDialog_title"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:gravity="center"
+ android:textSize="20sp"
+ android:textColor="?android:attr/textColorPrimary"
+ android:fontFamily="google-sans-medium"/>
+
+ <TextView
+ android:id="@+id/accessibility_encryption_warning"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:padding="10dip"
+ android:textAlignment="viewStart"
+ android:textAppearance="?android:attr/textAppearanceMedium"/>
+
+ <TextView
+ android:id="@+id/accessibility_permissionDialog_description"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:layout_marginTop="16dp"
+ android:layout_marginBottom="32dp"
+ android:text="@string/accessibility_service_warning_description"
+ android:textSize="16sp"
+ android:textColor="?android:attr/textColorPrimary"
+ android:fontFamily="sans-serif"/>
+
+ <LinearLayout
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:gravity="center"
+ android:orientation="horizontal">
+
+ <ImageView
+ android:id="@+id/accessibility_controlScreen_icon"
+ android:layout_width="18dp"
+ android:layout_height="18dp"
+ android:layout_marginRight="12dp"
+ android:src="@android:drawable/ic_visibility"
+ android:scaleType="fitCenter"/>
+
+ <TextView
+ android:id="@+id/accessibility_controlScreen_title"
+ android:layout_width="0dp"
+ android:layout_height="wrap_content"
+ android:layout_weight="1"
+ android:text="@string/accessibility_service_screen_control_title"
+ android:textSize="16sp"
+ android:textColor="?android:attr/textColorPrimary"
+ android:fontFamily="sans-serif"/>
+ </LinearLayout>
+
+ <TextView
+ android:id="@+id/accessibility_controlScreen_description"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:layout_marginBottom="24dp"
+ android:paddingStart="30dp"
+ android:text="@string/accessibility_service_screen_control_description"
+ android:textSize="14sp"
+ android:textColor="?android:attr/textColorSecondary"
+ android:fontFamily="sans-serif"/>
+
+ <LinearLayout
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:gravity="center"
+ android:orientation="horizontal">
+
+ <ImageView
+ android:id="@+id/accessibility_performAction_icon"
+ android:layout_width="18dp"
+ android:layout_height="18dp"
+ android:layout_marginEnd="12dp"
+ android:src="@android:drawable/ic_pan_tool"
+ android:scaleType="fitCenter"/>
+
+ <TextView
+ android:id="@+id/accessibility_performAction_title"
+ android:layout_width="0dp"
+ android:layout_height="wrap_content"
+ android:layout_weight="1"
+ android:text="@string/accessibility_service_action_perform_title"
+ android:textSize="16sp"
+ android:textColor="?android:attr/textColorPrimary"
+ android:fontFamily="sans-serif"/>
+ </LinearLayout>
+
+ <TextView
+ android:id="@+id/accessibility_performAction_description"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:layout_marginBottom="24dp"
+ android:paddingStart="30dp"
+ android:text="@string/accessibility_service_action_perform_description"
+ android:textSize="14sp"
+ android:textColor="?android:attr/textColorSecondary"
+ android:fontFamily="sans-serif" />
+ </LinearLayout>
+
+ <View
+ android:layout_width="match_parent"
+ android:layout_height="1dp"
+ android:background="@color/chooser_row_divider"/>
+
+ <Button
+ android:id="@+id/accessibility_permission_enable_allow_button"
+ android:layout_width="match_parent"
+ android:layout_height="56dp"
+ android:background="?android:attr/selectableItemBackground"
+ android:text="@string/accessibility_dialog_button_allow"
+ style="?attr/buttonBarPositiveButtonStyle"/>
+
+ <View
+ android:layout_width="match_parent"
+ android:layout_height="1dp"
+ android:background="@color/chooser_row_divider"/>
+
+ <Button
+ android:id="@+id/accessibility_permission_enable_deny_button"
+ android:layout_width="match_parent"
+ android:layout_height="56dp"
+ android:background="?android:attr/selectableItemBackground"
+ android:text="@string/accessibility_dialog_button_deny"
+ style="?attr/buttonBarPositiveButtonStyle"/>
+ </LinearLayout>
+
+</ScrollView> \ No newline at end of file
diff --git a/core/res/res/layout/chooser_list_per_profile.xml b/core/res/res/layout/chooser_list_per_profile.xml
index b833243a966c..6b1b002267cb 100644
--- a/core/res/res/layout/chooser_list_per_profile.xml
+++ b/core/res/res/layout/chooser_list_per_profile.xml
@@ -16,9 +16,7 @@
<RelativeLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
- android:layout_height="match_parent"
- android:paddingTop="8dp"
- android:paddingBottom="8dp">
+ android:layout_height="match_parent">
<com.android.internal.widget.RecyclerView
android:layout_width="match_parent"
android:layout_height="match_parent"
diff --git a/core/res/res/layout/resolver_list.xml b/core/res/res/layout/resolver_list.xml
index d940376dd3e8..e17fc8a16b9f 100644
--- a/core/res/res/layout/resolver_list.xml
+++ b/core/res/res/layout/resolver_list.xml
@@ -100,7 +100,8 @@
android:layout_width="match_parent"
android:layout_height="1dp"
android:background="?attr/colorBackgroundFloating"
- android:foreground="?attr/dividerVertical" />
+ android:foreground="?attr/dividerVertical"
+ android:layout_marginBottom="@dimen/resolver_tab_divider_bottom_padding"/>
<FrameLayout
android:id="@android:id/tabcontent"
android:layout_width="match_parent"
diff --git a/core/res/res/layout/resolver_list_per_profile.xml b/core/res/res/layout/resolver_list_per_profile.xml
index 9aa21ab0256b..9410301e40fc 100644
--- a/core/res/res/layout/resolver_list_per_profile.xml
+++ b/core/res/res/layout/resolver_list_per_profile.xml
@@ -17,9 +17,7 @@
<RelativeLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
- android:layout_height="match_parent"
- android:paddingTop="8dp"
- android:paddingBottom="8dp">
+ android:layout_height="match_parent">
<ListView
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
diff --git a/core/res/res/layout/resolver_list_with_default.xml b/core/res/res/layout/resolver_list_with_default.xml
index 4e1908c282f3..0d4523add3cb 100644
--- a/core/res/res/layout/resolver_list_with_default.xml
+++ b/core/res/res/layout/resolver_list_with_default.xml
@@ -183,7 +183,8 @@
android:layout_width="match_parent"
android:layout_height="1dp"
android:background="?attr/colorBackgroundFloating"
- android:foreground="?attr/dividerVertical" />
+ android:foreground="?attr/dividerVertical"
+ android:layout_marginBottom="@dimen/resolver_tab_divider_bottom_padding"/>
<FrameLayout
android:id="@android:id/tabcontent"
android:layout_width="match_parent"
diff --git a/core/res/res/values-af/strings.xml b/core/res/res/values-af/strings.xml
index af56edd2353b..632c400d4d49 100644
--- a/core/res/res/values-af/strings.xml
+++ b/core/res/res/values-af/strings.xml
@@ -249,10 +249,8 @@
<item quantity="other">Neem skermkiekie vir foutverslag oor <xliff:g id="NUMBER_1">%d</xliff:g> sekondes.</item>
<item quantity="one">Neem skermkiekie vir foutverslag oor <xliff:g id="NUMBER_0">%d</xliff:g> sekonde.</item>
</plurals>
- <!-- no translation found for bugreport_screenshot_success_toast (7986095104151473745) -->
- <skip />
- <!-- no translation found for bugreport_screenshot_failure_toast (6736320861311294294) -->
- <skip />
+ <string name="bugreport_screenshot_success_toast" msgid="7986095104151473745">"Skermkiekie met foutverslag geneem"</string>
+ <string name="bugreport_screenshot_failure_toast" msgid="6736320861311294294">"Kon nie skermkiekie met foutverslag neem nie"</string>
<string name="global_action_toggle_silent_mode" msgid="8464352592860372188">"Stilmodus"</string>
<string name="global_action_silent_mode_on_status" msgid="2371892537738632013">"Klank is AF"</string>
<string name="global_action_silent_mode_off_status" msgid="6608006545950920042">"Klank is AAN"</string>
@@ -454,9 +452,11 @@
<string name="permdesc_acceptHandovers" msgid="7129026180128626870">"Laat die program toe om \'n oproep voort te sit wat in \'n ander program begin is."</string>
<string name="permlab_readPhoneNumbers" msgid="5668704794723365628">"lees foonnommers"</string>
<string name="permdesc_readPhoneNumbers" msgid="7368652482818338871">"Laat die program toe om toegang tot die toestel se foonnommers te kry."</string>
+ <string name="permlab_wakeLock" product="automotive" msgid="1904736682319375676">"hou motorskerm aan"</string>
<string name="permlab_wakeLock" product="tablet" msgid="1527660973931694000">"verhoed dat tablet slaap"</string>
<string name="permlab_wakeLock" product="tv" msgid="2856941418123343518">"keer dat jou Android TV-toestel slaap"</string>
<string name="permlab_wakeLock" product="default" msgid="569409726861695115">"verhoed foon om te slaap"</string>
+ <string name="permdesc_wakeLock" product="automotive" msgid="5995045369683254571">"Laat die program toe om die motorskerm aan te hou."</string>
<string name="permdesc_wakeLock" product="tablet" msgid="2441742939101526277">"Laat die program toe om die tablet te keer om te slaap."</string>
<string name="permdesc_wakeLock" product="tv" msgid="2329298966735118796">"Laat die program toe om te keer dat jou Android TV-toestel slaap."</string>
<string name="permdesc_wakeLock" product="default" msgid="3689523792074007163">"Laat die program toe om die foon te keer om te slaap."</string>
@@ -1631,6 +1631,9 @@
<string name="safe_media_volume_warning" product="default" msgid="3751676824423049994">"Verhoog volume bo aanbevole vlak?\n\nOm lang tydperke teen hoë volume te luister, kan jou gehoor beskadig."</string>
<string name="accessibility_shortcut_warning_dialog_title" msgid="4017995837692622933">"Gebruik toeganklikheidkortpad?"</string>
<string name="accessibility_shortcut_toogle_warning" msgid="4161716521310929544">"Wanneer die kortpad aan is, sal \'n toeganklikheidkenmerk begin word as albei volumeknoppies 3 sekondes lank gedruk word."</string>
+ <string name="accessibility_select_shortcut_menu_title" msgid="7310194076629867377">"Tik op die toeganklikheidprogram wat jy wil gebruik"</string>
+ <string name="accessibility_edit_shortcut_menu_button_title" msgid="6096484087245145325">"Kies programme wat jy met toeganklikheidknoppie wil gebruik"</string>
+ <string name="accessibility_edit_shortcut_menu_volume_title" msgid="4849108668454490699">"Kies programme wat jy met die volumesleutelkortpad wil gebruik"</string>
<string name="edit_accessibility_shortcut_menu_button" msgid="8885752738733772935">"Wysig kortpaaie"</string>
<string name="cancel_accessibility_shortcut_menu_button" msgid="1817413122335452474">"Kanselleer"</string>
<string name="disable_accessibility_shortcut" msgid="5806091378745232383">"Skakel kortpad af"</string>
@@ -1853,8 +1856,7 @@
<string name="default_notification_channel_label" msgid="3697928973567217330">"Ongekategoriseer"</string>
<string name="importance_from_user" msgid="2782756722448800447">"Jy stel die belangrikheid van hierdie kennisgewings."</string>
<string name="importance_from_person" msgid="4235804979664465383">"Dit is belangrik as gevolg van die mense wat betrokke is."</string>
- <!-- no translation found for notification_history_title_placeholder (7748630986182249599) -->
- <skip />
+ <string name="notification_history_title_placeholder" msgid="7748630986182249599">"Gepasmaakte programkennisgewing"</string>
<string name="user_creation_account_exists" msgid="2239146360099708035">"Laat <xliff:g id="APP">%1$s</xliff:g> toe om \'n nuwe gebruiker met <xliff:g id="ACCOUNT">%2$s</xliff:g> te skep (\'n gebruiker met hierdie rekening bestaan reeds)?"</string>
<string name="user_creation_adding" msgid="7305185499667958364">"Laat <xliff:g id="APP">%1$s</xliff:g> toe om \'n nuwe gebruiker met <xliff:g id="ACCOUNT">%2$s</xliff:g> te skep?"</string>
<string name="language_selection_title" msgid="52674936078683285">"Voeg \'n taal by"</string>
@@ -2028,14 +2030,19 @@
<string name="as_app_forced_to_restricted_bucket" msgid="8233871289353898964">"<xliff:g id="PACKAGE_NAME">%1$s</xliff:g> is in die BEPERK-groep geplaas"</string>
<string name="resolver_personal_tab" msgid="2051260504014442073">"Persoonlik"</string>
<string name="resolver_work_tab" msgid="2690019516263167035">"Werk"</string>
+ <string name="resolver_personal_tab_accessibility" msgid="5739524949153091224">"Persoonlike aansig"</string>
+ <string name="resolver_work_tab_accessibility" msgid="4753168230363802734">"Werkaansig"</string>
<string name="resolver_cant_share_with_work_apps" msgid="7539495559434146897">"Kan nie met werkprogramme deel nie"</string>
<string name="resolver_cant_share_with_personal_apps" msgid="8020581735267157241">"Kan nie met persoonlike programme deel nie"</string>
- <string name="resolver_cant_share_cross_profile_explanation" msgid="3536237105241882679">"Jou IT-admin het deling tussen persoonlike en werkprogramme geblokkeer"</string>
- <string name="resolver_turn_on_work_apps" msgid="8987359079870455469">"Skakel werkprogramme aan"</string>
- <string name="resolver_turn_on_work_apps_explanation" msgid="6322467455509618928">"Skakel werkprogramme aan om toegang tot werkprogramme en -kontakte te kry"</string>
+ <string name="resolver_cant_share_cross_profile_explanation" msgid="5556640604460901386">"Jou IT-admin het deling tussen persoonlike en werkprofiele geblokkeer"</string>
+ <string name="resolver_cant_access_work_apps" msgid="375634344111233790">"Kan nie toegang tot werkprogramme kry nie"</string>
+ <string name="resolver_cant_access_work_apps_explanation" msgid="3958762224516867388">"Jou IT-admin laat jou nie toe om persoonlike inhoud in werkprogramme te bekyk nie"</string>
+ <string name="resolver_cant_access_personal_apps" msgid="1953215925406474177">"Kan nie toegang tot persoonlike programme kry nie"</string>
+ <string name="resolver_cant_access_personal_apps_explanation" msgid="1725572276741281136">"Jou IT-admin laat jou nie toe om werkinhoud in persoonlike programme te bekyk nie"</string>
+ <string name="resolver_turn_on_work_apps_share" msgid="619263911204978175">"Skakel werkprofiel aan om inhoud te deel"</string>
+ <string name="resolver_turn_on_work_apps_view" msgid="3073389230905543680">"Skakel werkprofiel aan om inhoud te bekyk"</string>
<string name="resolver_no_apps_available" msgid="7710339903040989654">"Geen programme beskikbaar nie"</string>
- <string name="resolver_no_apps_available_explanation" msgid="4662694431121196560">"Ons kon geen programme kry nie"</string>
- <string name="resolver_switch_on_work" msgid="8294542702883688533">"Skakel werk aan"</string>
+ <string name="resolver_switch_on_work" msgid="2873009160846966379">"Skakel aan"</string>
<string name="permlab_accessCallAudio" msgid="1682957511874097664">"Neem oudio in telefonie-oproepe op of speel dit"</string>
<string name="permdesc_accessCallAudio" msgid="8448360894684277823">"Laat hierdie program, indien dit as die verstekbellerprogram aangewys is, toe om oudio in telefonie-oproepe op te neem of te speel."</string>
</resources>
diff --git a/core/res/res/values-am/strings.xml b/core/res/res/values-am/strings.xml
index 9a0ed24f2ede..898a56a7ba91 100644
--- a/core/res/res/values-am/strings.xml
+++ b/core/res/res/values-am/strings.xml
@@ -249,10 +249,8 @@
<item quantity="one">በ<xliff:g id="NUMBER_1">%d</xliff:g> ሰከንዶች ውስጥ ለሳንካ ሪፖርት ቅጽበታዊ ገጽ ዕይታን በማንሳት ላይ።</item>
<item quantity="other">በ<xliff:g id="NUMBER_1">%d</xliff:g> ሰከንዶች ውስጥ ለሳንካ ሪፖርት ቅጽበታዊ ገጽ ዕይታን በማንሳት ላይ።</item>
</plurals>
- <!-- no translation found for bugreport_screenshot_success_toast (7986095104151473745) -->
- <skip />
- <!-- no translation found for bugreport_screenshot_failure_toast (6736320861311294294) -->
- <skip />
+ <string name="bugreport_screenshot_success_toast" msgid="7986095104151473745">"ቅጽበታዊ ገጽ እይታ ከሳንካ ሪፖርት ጋር ተነስቷል"</string>
+ <string name="bugreport_screenshot_failure_toast" msgid="6736320861311294294">"ቅጽበታዊ ገጽ እይታን ከሳንካ ሪፖርት ጋር ማንሳት አልተሳካም"</string>
<string name="global_action_toggle_silent_mode" msgid="8464352592860372188">"የፀጥታ ሁነታ"</string>
<string name="global_action_silent_mode_on_status" msgid="2371892537738632013">"ድምፅ ጠፍቷል"</string>
<string name="global_action_silent_mode_off_status" msgid="6608006545950920042">"ድምፅ በርቷል"</string>
@@ -454,9 +452,11 @@
<string name="permdesc_acceptHandovers" msgid="7129026180128626870">"መተግበሪያው በሌላ መተግበሪያ ውስጥ የተጀመረ ጥሪ እንዲቀጥል ያስችለዋል።"</string>
<string name="permlab_readPhoneNumbers" msgid="5668704794723365628">"ስልክ ቁጥሮች ያንብቡ"</string>
<string name="permdesc_readPhoneNumbers" msgid="7368652482818338871">"መተግበሪያው የመሣሪያውን የስልክ ቁጥሮች እንዲደርስባቸው ይፈቅድለታል።"</string>
+ <string name="permlab_wakeLock" product="automotive" msgid="1904736682319375676">"የመኪና ማያ ገጽ እንደበራ አቆይ"</string>
<string name="permlab_wakeLock" product="tablet" msgid="1527660973931694000">"ጡባዊ ከማንቀላፋት ተከላከል"</string>
<string name="permlab_wakeLock" product="tv" msgid="2856941418123343518">"የእርስዎ Android TV መሣሪያ እንዳይተኛ ይከላከሉ"</string>
<string name="permlab_wakeLock" product="default" msgid="569409726861695115">"ስልክ ከማንቀላፋት ተከላከል"</string>
+ <string name="permdesc_wakeLock" product="automotive" msgid="5995045369683254571">"መተግበሪያው የመኪናው ማያ ገጽ እንደበራ እንዲያቆየው ያስችለዋል።"</string>
<string name="permdesc_wakeLock" product="tablet" msgid="2441742939101526277">"ጡባዊውን ከመተኛት መከልከል ለመተግበሪያው ይፈቅዳሉ።"</string>
<string name="permdesc_wakeLock" product="tv" msgid="2329298966735118796">"የእርስዎን Android TV ከመተኛት እንዲከላከል ለመተግበሪያው ይፈቅድለታል።"</string>
<string name="permdesc_wakeLock" product="default" msgid="3689523792074007163">"ስልኩን ከመተኛት መከልከል ለመተግበሪያው ይፈቅዳሉ።"</string>
@@ -1631,6 +1631,12 @@
<string name="safe_media_volume_warning" product="default" msgid="3751676824423049994">"ድምጹ ከሚመከረው መጠን በላይ ከፍ ይበል?\n\nበከፍተኛ ድምጽ ለረጅም ጊዜ ማዳመጥ ጆሮዎን ሊጎዳው ይችላል።"</string>
<string name="accessibility_shortcut_warning_dialog_title" msgid="4017995837692622933">"የተደራሽነት አቋራጭ ጥቅም ላይ ይዋል?"</string>
<string name="accessibility_shortcut_toogle_warning" msgid="4161716521310929544">"አቋራጩ ሲበራ ሁለቱንም የድምጽ አዝራሮች ለ3 ሰከንዶች ተጭኖ መቆየት የተደራሽነት ባህሪን ያስጀምረዋል።"</string>
+ <!-- no translation found for accessibility_select_shortcut_menu_title (7310194076629867377) -->
+ <skip />
+ <!-- no translation found for accessibility_edit_shortcut_menu_button_title (6096484087245145325) -->
+ <skip />
+ <!-- no translation found for accessibility_edit_shortcut_menu_volume_title (4849108668454490699) -->
+ <skip />
<string name="edit_accessibility_shortcut_menu_button" msgid="8885752738733772935">"አቋራጮችን አርትዕ ያድርጉ"</string>
<string name="cancel_accessibility_shortcut_menu_button" msgid="1817413122335452474">"ይቅር"</string>
<string name="disable_accessibility_shortcut" msgid="5806091378745232383">"አቋራጩን አጥፋ"</string>
@@ -1853,8 +1859,7 @@
<string name="default_notification_channel_label" msgid="3697928973567217330">"ያልተመደቡ"</string>
<string name="importance_from_user" msgid="2782756722448800447">"የእነዚህን ማሳወቂያዎች አስፈላጊነት አዘጋጅተዋል።"</string>
<string name="importance_from_person" msgid="4235804979664465383">"ይሄ በሚሳተፉ ሰዎች ምክንያት አስፈላጊ ነው።"</string>
- <!-- no translation found for notification_history_title_placeholder (7748630986182249599) -->
- <skip />
+ <string name="notification_history_title_placeholder" msgid="7748630986182249599">"ብጁ የመተግበሪያ ማሳወቂያ"</string>
<string name="user_creation_account_exists" msgid="2239146360099708035">"<xliff:g id="APP">%1$s</xliff:g> በ<xliff:g id="ACCOUNT">%2$s</xliff:g> አዲስ ተጠቃሚ እንዲፈጥር ይፈቀድለት (ይህ መለያ ያለው ተጠቃሚ አስቀድሞ አለ)?"</string>
<string name="user_creation_adding" msgid="7305185499667958364">"<xliff:g id="APP">%1$s</xliff:g> አዲስ ተጠቃሚ ከ <xliff:g id="ACCOUNT">%2$s</xliff:g> ጋር መፍጠር እንዲችል ይፍቀዱ?"</string>
<string name="language_selection_title" msgid="52674936078683285">"ቋንቋ ያክሉ"</string>
@@ -2028,14 +2033,29 @@
<string name="as_app_forced_to_restricted_bucket" msgid="8233871289353898964">"<xliff:g id="PACKAGE_NAME">%1$s</xliff:g> ወደ የRESTRICTED ባልዲ ተከትቷል"</string>
<string name="resolver_personal_tab" msgid="2051260504014442073">"የግል"</string>
<string name="resolver_work_tab" msgid="2690019516263167035">"ሥራ"</string>
+ <!-- no translation found for resolver_personal_tab_accessibility (5739524949153091224) -->
+ <skip />
+ <!-- no translation found for resolver_work_tab_accessibility (4753168230363802734) -->
+ <skip />
<string name="resolver_cant_share_with_work_apps" msgid="7539495559434146897">"በሥራ መተግበሪያዎች ማጋራት አይቻልም"</string>
<string name="resolver_cant_share_with_personal_apps" msgid="8020581735267157241">"በግል መተግበሪያዎች ማጋራት አይቻልም"</string>
- <string name="resolver_cant_share_cross_profile_explanation" msgid="3536237105241882679">"የእርስዎ አይቲ አስተዳዳሪ በግል እና በሥራ መተግበሪያዎች መካከል ማጋራትን አግደዋል"</string>
- <string name="resolver_turn_on_work_apps" msgid="8987359079870455469">"የሥራ መተግበሪያዎች ያብሩ"</string>
- <string name="resolver_turn_on_work_apps_explanation" msgid="6322467455509618928">"የሥራ መተግበሪያዎች እና እውቂያዎችን ለመድረስ የሥራ መተግበሪያዎችን ያብሩ"</string>
+ <!-- no translation found for resolver_cant_share_cross_profile_explanation (5556640604460901386) -->
+ <skip />
+ <!-- no translation found for resolver_cant_access_work_apps (375634344111233790) -->
+ <skip />
+ <!-- no translation found for resolver_cant_access_work_apps_explanation (3958762224516867388) -->
+ <skip />
+ <!-- no translation found for resolver_cant_access_personal_apps (1953215925406474177) -->
+ <skip />
+ <!-- no translation found for resolver_cant_access_personal_apps_explanation (1725572276741281136) -->
+ <skip />
+ <!-- no translation found for resolver_turn_on_work_apps_share (619263911204978175) -->
+ <skip />
+ <!-- no translation found for resolver_turn_on_work_apps_view (3073389230905543680) -->
+ <skip />
<string name="resolver_no_apps_available" msgid="7710339903040989654">"ምንም መተግበሪያዎች አይገኙም"</string>
- <string name="resolver_no_apps_available_explanation" msgid="4662694431121196560">"ምንም መተግበሪያዎች ልናገኝ አልቻልንም"</string>
- <string name="resolver_switch_on_work" msgid="8294542702883688533">"ሥራን ያብሩ"</string>
+ <!-- no translation found for resolver_switch_on_work (2873009160846966379) -->
+ <skip />
<string name="permlab_accessCallAudio" msgid="1682957511874097664">"በስልክ ጥሪዎች ላይ ኦዲዮን መቅዳት ወይም ማጫወት"</string>
<string name="permdesc_accessCallAudio" msgid="8448360894684277823">"ይህ መተግበሪያ እንደ ነባሪ የመደወያ መተግበሪያ ሲመደብ በስልክ ጥሪዎች ላይ ኦዲዮን እንዲቀዳ ወይም እንዲያጫውት ያስችለዋል።"</string>
</resources>
diff --git a/core/res/res/values-ar/strings.xml b/core/res/res/values-ar/strings.xml
index 7d1e01d5d235..cf9cab19c77a 100644
--- a/core/res/res/values-ar/strings.xml
+++ b/core/res/res/values-ar/strings.xml
@@ -215,7 +215,7 @@
<string name="power_dialog" product="tv" msgid="7792839006640933763">"‏خيارات Android TV"</string>
<string name="power_dialog" product="default" msgid="1107775420270203046">"خيارات الهاتف"</string>
<string name="silent_mode" msgid="8796112363642579333">"وضع صامت"</string>
- <string name="turn_on_radio" msgid="2961717788170634233">"تشغيل اللاسلكي"</string>
+ <string name="turn_on_radio" msgid="2961717788170634233">"تفعيل اللاسلكي"</string>
<string name="turn_off_radio" msgid="7222573978109933360">"إيقاف تفعيل الشبكة اللاسلكية"</string>
<string name="screen_lock" msgid="2072642720826409809">"قفل الشاشة"</string>
<string name="power_off" msgid="4111692782492232778">"إيقاف التشغيل"</string>
@@ -261,10 +261,8 @@
<item quantity="other">سيتم التقاط لقطة شاشة لتقرير الخطأ خلال <xliff:g id="NUMBER_1">%d</xliff:g> ثانية.</item>
<item quantity="one">سيتم التقاط لقطة شاشة لتقرير الخطأ خلال <xliff:g id="NUMBER_0">%d</xliff:g> ثانية.</item>
</plurals>
- <!-- no translation found for bugreport_screenshot_success_toast (7986095104151473745) -->
- <skip />
- <!-- no translation found for bugreport_screenshot_failure_toast (6736320861311294294) -->
- <skip />
+ <string name="bugreport_screenshot_success_toast" msgid="7986095104151473745">"تم التقاط لقطة شاشة من خلال تقرير خطأ."</string>
+ <string name="bugreport_screenshot_failure_toast" msgid="6736320861311294294">"تعذّر التقاط لقطة شاشة من خلال تقرير خطأ."</string>
<string name="global_action_toggle_silent_mode" msgid="8464352592860372188">"وضع صامت"</string>
<string name="global_action_silent_mode_on_status" msgid="2371892537738632013">"الصوت متوقف"</string>
<string name="global_action_silent_mode_off_status" msgid="6608006545950920042">"الصوت قيد التفعيل"</string>
@@ -466,9 +464,11 @@
<string name="permdesc_acceptHandovers" msgid="7129026180128626870">"السماح للتطبيق بمواصلة مكالمة بدأت في تطبيق آخر."</string>
<string name="permlab_readPhoneNumbers" msgid="5668704794723365628">"قراءة أرقام الهواتف"</string>
<string name="permdesc_readPhoneNumbers" msgid="7368652482818338871">"للسماح للتطبيق بالوصول إلى أرقام الهواتف على هذا الجهاز."</string>
+ <string name="permlab_wakeLock" product="automotive" msgid="1904736682319375676">"الاحتفاظ بشاشة السيارة مفعَّلة"</string>
<string name="permlab_wakeLock" product="tablet" msgid="1527660973931694000">"منع الجهاز اللوحي من الدخول في وضع السكون"</string>
<string name="permlab_wakeLock" product="tv" msgid="2856941418123343518">"‏منع جهاز Android TV من الانتقال إلى وضع السكون"</string>
<string name="permlab_wakeLock" product="default" msgid="569409726861695115">"منع الهاتف من الدخول في وضع السكون"</string>
+ <string name="permdesc_wakeLock" product="automotive" msgid="5995045369683254571">"يسمح هذا الإذن للتطبيق بالاحتفاظ بشاشة السيارة مفعَّلة."</string>
<string name="permdesc_wakeLock" product="tablet" msgid="2441742939101526277">"للسماح للتطبيق بمنع الجهاز اللوحي من الانتقال إلى وضع السكون."</string>
<string name="permdesc_wakeLock" product="tv" msgid="2329298966735118796">"‏للسماح للتطبيق بمنع جهاز Android TV من الانتقال إلى وضع السكون."</string>
<string name="permdesc_wakeLock" product="default" msgid="3689523792074007163">"للسماح للتطبيق بمنع الهاتف من الانتقال إلى وضع السكون."</string>
@@ -617,7 +617,7 @@
<string name="face_icon_content_description" msgid="465030547475916280">"رمز الوجه"</string>
<string name="permlab_readSyncSettings" msgid="6250532864893156277">"قراءة إعدادات المزامنة"</string>
<string name="permdesc_readSyncSettings" msgid="1325658466358779298">"للسماح للتطبيق بقراءة الإعدادات المتزامنة لحساب ما. على سبيل المثال، يمكن أن يؤدي هذا إلى تحديد ما إذا تمت مزامنة تطبيق \"الأشخاص\" مع حساب ما."</string>
- <string name="permlab_writeSyncSettings" msgid="6583154300780427399">"التبديل بين تشغيل المزامنة وإيقافها"</string>
+ <string name="permlab_writeSyncSettings" msgid="6583154300780427399">"التبديل بين تفعيل المزامنة وإيقافها"</string>
<string name="permdesc_writeSyncSettings" msgid="6029151549667182687">"للسماح للتطبيق بتعديل إعدادات المزامنة لحساب ما. على سبيل المثال، يمكن استخدام ذلك لتفعيل مزامنة تطبيق \"الأشخاص\" مع حساب ما."</string>
<string name="permlab_readSyncStats" msgid="3747407238320105332">"قراءة إحصاءات المزامنة"</string>
<string name="permdesc_readSyncStats" msgid="3867809926567379434">"للسماح للتطبيق بقراءة إحصائيات المزامنة لحساب ما، بما في ذلك سجل الأحداث المتزامنة ومقدار البيانات التي تمت مزامنتها."</string>
@@ -853,7 +853,7 @@
<string name="lockscreen_transport_pause_description" msgid="6705284702135372494">"إيقاف مؤقت"</string>
<string name="lockscreen_transport_play_description" msgid="106868788691652733">"تشغيل"</string>
<string name="lockscreen_transport_stop_description" msgid="1449552232598355348">"إيقاف"</string>
- <string name="lockscreen_transport_rew_description" msgid="7680106856221622779">"إرجاع"</string>
+ <string name="lockscreen_transport_rew_description" msgid="7680106856221622779">"ترجيع"</string>
<string name="lockscreen_transport_ffw_description" msgid="4763794746640196772">"تقديم سريع"</string>
<string name="emergency_calls_only" msgid="3057351206678279851">"مكالمات الطوارئ فقط"</string>
<string name="lockscreen_network_locked_message" msgid="2814046965899249635">"الشبكة مؤمّنة"</string>
@@ -1719,6 +1719,12 @@
<string name="safe_media_volume_warning" product="default" msgid="3751676824423049994">"هل تريد رفع مستوى الصوت فوق المستوى الموصى به؟\n\nقد يضر سماع صوت عالٍ لفترات طويلة بسمعك."</string>
<string name="accessibility_shortcut_warning_dialog_title" msgid="4017995837692622933">"هل تريد استخدام اختصار \"سهولة الاستخدام\"؟"</string>
<string name="accessibility_shortcut_toogle_warning" msgid="4161716521310929544">"عند تفعيل الاختصار، يؤدي الضغط على زرّي التحكّم في مستوى الصوت معًا لمدة 3 ثوانٍ إلى تفعيل إحدى ميزات إمكانية الوصول."</string>
+ <!-- no translation found for accessibility_select_shortcut_menu_title (7310194076629867377) -->
+ <skip />
+ <!-- no translation found for accessibility_edit_shortcut_menu_button_title (6096484087245145325) -->
+ <skip />
+ <!-- no translation found for accessibility_edit_shortcut_menu_volume_title (4849108668454490699) -->
+ <skip />
<string name="edit_accessibility_shortcut_menu_button" msgid="8885752738733772935">"تعديل الاختصارات"</string>
<string name="cancel_accessibility_shortcut_menu_button" msgid="1817413122335452474">"إلغاء"</string>
<string name="disable_accessibility_shortcut" msgid="5806091378745232383">"إيقاف الاختصار"</string>
@@ -1981,8 +1987,7 @@
<string name="default_notification_channel_label" msgid="3697928973567217330">"غير مصنفة"</string>
<string name="importance_from_user" msgid="2782756722448800447">"لقد عيَّنت أهمية هذه الإشعارات."</string>
<string name="importance_from_person" msgid="4235804979664465383">"هذه الرسالة مهمة نظرًا لأهمية الأشخاص المعنيين."</string>
- <!-- no translation found for notification_history_title_placeholder (7748630986182249599) -->
- <skip />
+ <string name="notification_history_title_placeholder" msgid="7748630986182249599">"إشعار تطبيق مخصّص"</string>
<string name="user_creation_account_exists" msgid="2239146360099708035">"هل تسمح لتطبيق <xliff:g id="APP">%1$s</xliff:g> بإنشاء مستخدم جديد باستخدام <xliff:g id="ACCOUNT">%2$s</xliff:g> (يوجد مستخدم بهذا الحساب مسبقًا)؟"</string>
<string name="user_creation_adding" msgid="7305185499667958364">"هل تسمح لتطبيق <xliff:g id="APP">%1$s</xliff:g> بإنشاء مستخدم جديد باستخدام <xliff:g id="ACCOUNT">%2$s</xliff:g> ؟"</string>
<string name="language_selection_title" msgid="52674936078683285">"إضافة لغة"</string>
@@ -2164,14 +2169,29 @@
<string name="as_app_forced_to_restricted_bucket" msgid="8233871289353898964">"تم وضع <xliff:g id="PACKAGE_NAME">%1$s</xliff:g> في الحزمة \"محظورة\"."</string>
<string name="resolver_personal_tab" msgid="2051260504014442073">"شخصي"</string>
<string name="resolver_work_tab" msgid="2690019516263167035">"عمل"</string>
+ <!-- no translation found for resolver_personal_tab_accessibility (5739524949153091224) -->
+ <skip />
+ <!-- no translation found for resolver_work_tab_accessibility (4753168230363802734) -->
+ <skip />
<string name="resolver_cant_share_with_work_apps" msgid="7539495559434146897">"تتعذّر المشاركة مع تطبيقات العمل"</string>
<string name="resolver_cant_share_with_personal_apps" msgid="8020581735267157241">"تتعذّر المشاركة مع التطبيقات الشخصية"</string>
- <string name="resolver_cant_share_cross_profile_explanation" msgid="3536237105241882679">"حظر مشرف تكنولوجيا المعلومات لديك المشاركة بين التطبيقات الشخصية وتطبيقات العمل."</string>
- <string name="resolver_turn_on_work_apps" msgid="8987359079870455469">"تشغيل تطبيقات العمل"</string>
- <string name="resolver_turn_on_work_apps_explanation" msgid="6322467455509618928">"تشغيل تطبيقات العمل للوصول إلى تطبيقات العمل وجهات الاتصال"</string>
+ <!-- no translation found for resolver_cant_share_cross_profile_explanation (5556640604460901386) -->
+ <skip />
+ <!-- no translation found for resolver_cant_access_work_apps (375634344111233790) -->
+ <skip />
+ <!-- no translation found for resolver_cant_access_work_apps_explanation (3958762224516867388) -->
+ <skip />
+ <!-- no translation found for resolver_cant_access_personal_apps (1953215925406474177) -->
+ <skip />
+ <!-- no translation found for resolver_cant_access_personal_apps_explanation (1725572276741281136) -->
+ <skip />
+ <!-- no translation found for resolver_turn_on_work_apps_share (619263911204978175) -->
+ <skip />
+ <!-- no translation found for resolver_turn_on_work_apps_view (3073389230905543680) -->
+ <skip />
<string name="resolver_no_apps_available" msgid="7710339903040989654">"ليس هناك تطبيقات متاحة"</string>
- <string name="resolver_no_apps_available_explanation" msgid="4662694431121196560">"تعذّر العثور على أي تطبيقات"</string>
- <string name="resolver_switch_on_work" msgid="8294542702883688533">"تفعيل الملف الشخصي للعمل"</string>
+ <!-- no translation found for resolver_switch_on_work (2873009160846966379) -->
+ <skip />
<string name="permlab_accessCallAudio" msgid="1682957511874097664">"تسجيل الصوت أو تشغيله في المكالمات الهاتفية"</string>
<string name="permdesc_accessCallAudio" msgid="8448360894684277823">"يسمح الإذن لهذا التطبيق بتسجيل الصوت أو تشغيله في المكالمات الهاتفية عندما يتم تخصيصه كالتطبيق التلقائي لبرنامج الاتصال."</string>
</resources>
diff --git a/core/res/res/values-as/strings.xml b/core/res/res/values-as/strings.xml
index b646b4065c78..75308c0bffd7 100644
--- a/core/res/res/values-as/strings.xml
+++ b/core/res/res/values-as/strings.xml
@@ -249,10 +249,8 @@
<item quantity="one">ত্ৰুটি সম্পর্কীয় অভিযোগৰ বাবে <xliff:g id="NUMBER_1">%d</xliff:g>ছেকেণ্ডৰ ভিতৰত স্ক্ৰীণশ্বট লোৱা হ\'ব।</item>
<item quantity="other">ত্ৰুটি সম্পর্কীয় অভিযোগৰ বাবে <xliff:g id="NUMBER_1">%d</xliff:g>ছেকেণ্ডৰ ভিতৰত স্ক্ৰীণশ্বট লোৱা হ\'ব।</item>
</plurals>
- <!-- no translation found for bugreport_screenshot_success_toast (7986095104151473745) -->
- <skip />
- <!-- no translation found for bugreport_screenshot_failure_toast (6736320861311294294) -->
- <skip />
+ <string name="bugreport_screenshot_success_toast" msgid="7986095104151473745">"বাগ ৰিপ’ৰ্টৰ সৈতে স্ক্ৰীনশ্বট লোৱা হ’ল"</string>
+ <string name="bugreport_screenshot_failure_toast" msgid="6736320861311294294">"বাগ ৰিপ’ৰ্টৰ সৈতে স্ক্ৰীনশ্বট ল’ব পৰা নগ’ল"</string>
<string name="global_action_toggle_silent_mode" msgid="8464352592860372188">"নিঃশব্দ ম\'ড"</string>
<string name="global_action_silent_mode_on_status" msgid="2371892537738632013">"ধ্বনি অফ আছে"</string>
<string name="global_action_silent_mode_off_status" msgid="6608006545950920042">"ধ্বনি অন আছে"</string>
@@ -454,9 +452,11 @@
<string name="permdesc_acceptHandovers" msgid="7129026180128626870">"এপটোক এনে কল কৰিবলৈ দিয়ে যিটোৰ আৰম্ভণি অইন এটা এপত হৈছিল।"</string>
<string name="permlab_readPhoneNumbers" msgid="5668704794723365628">"ফ\'ন নম্বৰসমূহ পঢ়ে"</string>
<string name="permdesc_readPhoneNumbers" msgid="7368652482818338871">"এপটোক ডিভাইচটোৰ ফ\'ন নম্বৰসমূহ চাবলৈ অনুমতি দিয়ে।"</string>
+ <string name="permlab_wakeLock" product="automotive" msgid="1904736682319375676">"গাড়ীৰ স্ক্রীনখন অন কৰি ৰখা"</string>
<string name="permlab_wakeLock" product="tablet" msgid="1527660973931694000">"টে\'বলেট সুপ্ত অৱস্থালৈ যোৱাত বাধা দিয়ক"</string>
<string name="permlab_wakeLock" product="tv" msgid="2856941418123343518">"আপোনাৰ Android TV ডিভাইচটো সুপ্ত অৱস্থালৈ যোৱাত বাধা দিয়ক"</string>
<string name="permlab_wakeLock" product="default" msgid="569409726861695115">"ফ\'ন সুপ্ত অৱস্থালৈ যোৱাত বাধা দিয়ক"</string>
+ <string name="permdesc_wakeLock" product="automotive" msgid="5995045369683254571">"এপ্‌টোক গাড়ীৰ স্ক্রীনখন অন কৰি ৰাখিবলৈ অনুমতি দিয়ে।"</string>
<string name="permdesc_wakeLock" product="tablet" msgid="2441742939101526277">"টে\'বলেট সুপ্ত অৱস্থালৈ যোৱাৰ পৰা প্ৰতিৰোধ কৰিবলৈ এপটোক অনুমতি দিয়ে।"</string>
<string name="permdesc_wakeLock" product="tv" msgid="2329298966735118796">"এপ্‌টোক আপোনাৰ Android TV ডিভাইচটো সুপ্ত অৱস্থালৈ যোৱাত বাধা দিবলৈ অনুমতি দিয়ে।"</string>
<string name="permdesc_wakeLock" product="default" msgid="3689523792074007163">"ফ\'ন সুপ্ত অৱস্থালৈ যোৱাৰ পৰা প্ৰতিৰোধ কৰিবলৈ এপটোক অনুমতি দিয়ে।"</string>
@@ -1631,6 +1631,12 @@
<string name="safe_media_volume_warning" product="default" msgid="3751676824423049994">"অনুমোদিত স্তৰতকৈ ওপৰলৈ ভলিউম বঢ়াব নেকি?\n\nদীৰ্ঘ সময়ৰ বাবে উচ্চ ভলিউমত শুনাৰ ফলত শ্ৰৱণ ক্ষমতাৰ ক্ষতি হ\'ব পাৰে।"</string>
<string name="accessibility_shortcut_warning_dialog_title" msgid="4017995837692622933">"দিব্যাংগসকলৰ সুবিধাৰ শ্বৰ্টকাট ব্যৱহাৰ কৰেনে?"</string>
<string name="accessibility_shortcut_toogle_warning" msgid="4161716521310929544">"শ্বৰ্টকাটটো অন হৈ থকাৰ সময়ত দুয়োটা ভলিউম বুটাম ৩ ছেকেণ্ডৰ বাবে হেঁচি ধৰি ৰাখিলে এটা সাধ্য সুবিধা আৰম্ভ হ’ব।"</string>
+ <!-- no translation found for accessibility_select_shortcut_menu_title (7310194076629867377) -->
+ <skip />
+ <!-- no translation found for accessibility_edit_shortcut_menu_button_title (6096484087245145325) -->
+ <skip />
+ <!-- no translation found for accessibility_edit_shortcut_menu_volume_title (4849108668454490699) -->
+ <skip />
<string name="edit_accessibility_shortcut_menu_button" msgid="8885752738733772935">"শ্বৰ্টকাটসমূহ সম্পাদনা কৰক"</string>
<string name="cancel_accessibility_shortcut_menu_button" msgid="1817413122335452474">"বাতিল কৰক"</string>
<string name="disable_accessibility_shortcut" msgid="5806091378745232383">"শ্বৰ্টকাট অফ কৰক"</string>
@@ -2028,14 +2034,29 @@
<string name="as_app_forced_to_restricted_bucket" msgid="8233871289353898964">"<xliff:g id="PACKAGE_NAME">%1$s</xliff:g>ক সীমাবদ্ধ বাকেটটোত ৰখা হৈছে"</string>
<string name="resolver_personal_tab" msgid="2051260504014442073">"ব্যক্তিগত"</string>
<string name="resolver_work_tab" msgid="2690019516263167035">"কৰ্মস্থান"</string>
+ <!-- no translation found for resolver_personal_tab_accessibility (5739524949153091224) -->
+ <skip />
+ <!-- no translation found for resolver_work_tab_accessibility (4753168230363802734) -->
+ <skip />
<string name="resolver_cant_share_with_work_apps" msgid="7539495559434146897">"কৰ্মস্থানৰ এপ্‌সমূহৰ সৈতে শ্বেয়াৰ কৰিব নোৱাৰি"</string>
<string name="resolver_cant_share_with_personal_apps" msgid="8020581735267157241">"ব্যক্তিগত এপ্‌সমূহৰ সৈতে শ্বেয়াৰ কৰিব নোৱাৰি"</string>
- <string name="resolver_cant_share_cross_profile_explanation" msgid="3536237105241882679">"আপোনাৰ আইটি প্ৰশাসকে ব্যক্তিগত আৰু কৰ্মস্থানৰ এপ্‌সমূহৰ মাজত সমল শ্বেয়াৰ কৰাটো অৱৰোধ কৰিছে"</string>
- <string name="resolver_turn_on_work_apps" msgid="8987359079870455469">"কৰ্মস্থানৰ এপ্‌সমূহ অন কৰক"</string>
- <string name="resolver_turn_on_work_apps_explanation" msgid="6322467455509618928">"কৰ্মস্থানৰ এপ্‌ আৰু সম্পৰ্কসমূহ এক্সেছ কৰিবলৈ কৰ্মস্থানৰ এপ্‌সমূহ অন কৰক"</string>
+ <!-- no translation found for resolver_cant_share_cross_profile_explanation (5556640604460901386) -->
+ <skip />
+ <!-- no translation found for resolver_cant_access_work_apps (375634344111233790) -->
+ <skip />
+ <!-- no translation found for resolver_cant_access_work_apps_explanation (3958762224516867388) -->
+ <skip />
+ <!-- no translation found for resolver_cant_access_personal_apps (1953215925406474177) -->
+ <skip />
+ <!-- no translation found for resolver_cant_access_personal_apps_explanation (1725572276741281136) -->
+ <skip />
+ <!-- no translation found for resolver_turn_on_work_apps_share (619263911204978175) -->
+ <skip />
+ <!-- no translation found for resolver_turn_on_work_apps_view (3073389230905543680) -->
+ <skip />
<string name="resolver_no_apps_available" msgid="7710339903040989654">"কোনো এপ্‌ উপলব্ধ নহয়"</string>
- <string name="resolver_no_apps_available_explanation" msgid="4662694431121196560">"আমি কোনো এপ্‌ বিচাৰি নাপালোঁ"</string>
- <string name="resolver_switch_on_work" msgid="8294542702883688533">"কৰ্মস্থানৰ প্ৰ’ফাইল অন কৰক"</string>
+ <!-- no translation found for resolver_switch_on_work (2873009160846966379) -->
+ <skip />
<string name="permlab_accessCallAudio" msgid="1682957511874097664">"টেলিফ’নী কলসমূহত অডিঅ’ ৰেকৰ্ড অথবা প্লে’ কৰক"</string>
<string name="permdesc_accessCallAudio" msgid="8448360894684277823">"ডিফ’ল্ট ডায়েলাৰ এপ্লিকেশ্বন হিচাপে আবণ্টন কৰিলে, এই এপ্‌টোক টেলিফ’নী কলসমূহত অডিঅ’ ৰেকৰ্ড অথবা প্লে’ কৰিবলৈ অনুমতি দিয়ে।"</string>
</resources>
diff --git a/core/res/res/values-az/strings.xml b/core/res/res/values-az/strings.xml
index fe5e4cf34484..fa3dbf6097b1 100644
--- a/core/res/res/values-az/strings.xml
+++ b/core/res/res/values-az/strings.xml
@@ -249,10 +249,8 @@
<item quantity="other">Baq hesabatı üçün <xliff:g id="NUMBER_1">%d</xliff:g> saniyədə sktinşot çəkilir.</item>
<item quantity="one">Baq hesabatı üçün <xliff:g id="NUMBER_0">%d</xliff:g> saniyədə skrinşot çəkilir.</item>
</plurals>
- <!-- no translation found for bugreport_screenshot_success_toast (7986095104151473745) -->
- <skip />
- <!-- no translation found for bugreport_screenshot_failure_toast (6736320861311294294) -->
- <skip />
+ <string name="bugreport_screenshot_success_toast" msgid="7986095104151473745">"Xəta hesabatı ilə ekran şəkli çəkildi"</string>
+ <string name="bugreport_screenshot_failure_toast" msgid="6736320861311294294">"Xəta hesabatı ilə ekran şəkli çəkmək alınmadı."</string>
<string name="global_action_toggle_silent_mode" msgid="8464352592860372188">"Səssiz rejim"</string>
<string name="global_action_silent_mode_on_status" msgid="2371892537738632013">"Səs qapalıdır"</string>
<string name="global_action_silent_mode_off_status" msgid="6608006545950920042">"Səs Aktivdir"</string>
@@ -454,9 +452,11 @@
<string name="permdesc_acceptHandovers" msgid="7129026180128626870">"Tətbiqə digər tətbiqdə başlayan zəngə davam etmək icazəsi verilir."</string>
<string name="permlab_readPhoneNumbers" msgid="5668704794723365628">"telefon nömrələrini oxuyun"</string>
<string name="permdesc_readPhoneNumbers" msgid="7368652482818338871">"Tətbiqə cihazın telefon nömrələrinə daxil olmağa icazə verir."</string>
+ <string name="permlab_wakeLock" product="automotive" msgid="1904736682319375676">"avtomobilin ekranını aktiv saxlamaq"</string>
<string name="permlab_wakeLock" product="tablet" msgid="1527660973931694000">"planşetin yuxu rejiminin qarşısını almaq"</string>
<string name="permlab_wakeLock" product="tv" msgid="2856941418123343518">"Android TV-nin yuxu rejiminə keçməsinə icazə verməyin"</string>
<string name="permlab_wakeLock" product="default" msgid="569409726861695115">"telefonun yuxu rejiminə keçməsini əngəllə"</string>
+ <string name="permdesc_wakeLock" product="automotive" msgid="5995045369683254571">"Tətbiqə avtomobilin ekranını aktiv saxlamaq icazəsi verir."</string>
<string name="permdesc_wakeLock" product="tablet" msgid="2441742939101526277">"Tətbiqə planşetin yuxu rejimini qadağan etməyə imkan verir."</string>
<string name="permdesc_wakeLock" product="tv" msgid="2329298966735118796">"Tətbiqə Android TV cihazında yuxu sessiyasını deaktiv etmək icazəsi verir."</string>
<string name="permdesc_wakeLock" product="default" msgid="3689523792074007163">"Tətbiqə telefonun yuxu rejimini qadağan etmək imkanı verir."</string>
@@ -1631,6 +1631,12 @@
<string name="safe_media_volume_warning" product="default" msgid="3751676824423049994">"Səsin həcmi tövsiyə olunan səviyyədən artıq olsun?\n\nYüksək səsi uzun zaman dinləmək eşitmə qabiliyyətinizə zərər vura bilər."</string>
<string name="accessibility_shortcut_warning_dialog_title" msgid="4017995837692622933">"Əlçatımlılıq Qısayolu istifadə edilsin?"</string>
<string name="accessibility_shortcut_toogle_warning" msgid="4161716521310929544">"Qısayol aktiv olduqda, hər iki səs düyməsinə 3 saniyə basıb saxlamaqla əlçatımlılıq funksiyası başladılacaq."</string>
+ <!-- no translation found for accessibility_select_shortcut_menu_title (7310194076629867377) -->
+ <skip />
+ <!-- no translation found for accessibility_edit_shortcut_menu_button_title (6096484087245145325) -->
+ <skip />
+ <!-- no translation found for accessibility_edit_shortcut_menu_volume_title (4849108668454490699) -->
+ <skip />
<string name="edit_accessibility_shortcut_menu_button" msgid="8885752738733772935">"Qısayolları redaktə edin"</string>
<string name="cancel_accessibility_shortcut_menu_button" msgid="1817413122335452474">"Ləğv edin"</string>
<string name="disable_accessibility_shortcut" msgid="5806091378745232383">"Qısayolu Deaktiv edin"</string>
@@ -1853,8 +1859,7 @@
<string name="default_notification_channel_label" msgid="3697928973567217330">"Kateqoriyasız"</string>
<string name="importance_from_user" msgid="2782756722448800447">"Bildirişlərin əhəmiyyətini Siz ayarlaryırsınız."</string>
<string name="importance_from_person" msgid="4235804979664465383">"İnsanlar cəlb olunduğu üçün bu vacibdir."</string>
- <!-- no translation found for notification_history_title_placeholder (7748630986182249599) -->
- <skip />
+ <string name="notification_history_title_placeholder" msgid="7748630986182249599">"Fərdi tətbiq bildirişi"</string>
<string name="user_creation_account_exists" msgid="2239146360099708035">"<xliff:g id="APP">%1$s</xliff:g> tətbiqinə <xliff:g id="ACCOUNT">%2$s</xliff:g> (artıq bu hesabı olan İstifadəçi mövcuddur) ilə yeni İstifadəçi yaratmağa icazə verilsin?"</string>
<string name="user_creation_adding" msgid="7305185499667958364">"<xliff:g id="APP">%1$s</xliff:g> tətbiqinə <xliff:g id="ACCOUNT">%2$s</xliff:g> ilə yeni İstifadəçi yartmağa icazə verilsin?"</string>
<string name="language_selection_title" msgid="52674936078683285">"Dil əlavə edin"</string>
@@ -2028,14 +2033,29 @@
<string name="as_app_forced_to_restricted_bucket" msgid="8233871289353898964">"<xliff:g id="PACKAGE_NAME">%1$s</xliff:g> MƏHDUDLAŞDIRILMIŞ səbətinə yerləşdirilib"</string>
<string name="resolver_personal_tab" msgid="2051260504014442073">"Şəxsi"</string>
<string name="resolver_work_tab" msgid="2690019516263167035">"İş"</string>
+ <!-- no translation found for resolver_personal_tab_accessibility (5739524949153091224) -->
+ <skip />
+ <!-- no translation found for resolver_work_tab_accessibility (4753168230363802734) -->
+ <skip />
<string name="resolver_cant_share_with_work_apps" msgid="7539495559434146897">"İş tətbiqləri ilə paylaşmaq olmur"</string>
<string name="resolver_cant_share_with_personal_apps" msgid="8020581735267157241">"Şəxsi tətbiqlərlə paylaşmaq olmur"</string>
- <string name="resolver_cant_share_cross_profile_explanation" msgid="3536237105241882679">"İT admininiz şəxsi və iş tətbiqləri arasında paylaşımı bloklayıb"</string>
- <string name="resolver_turn_on_work_apps" msgid="8987359079870455469">"İş tətbiqlərini aktiv edin"</string>
- <string name="resolver_turn_on_work_apps_explanation" msgid="6322467455509618928">"İş tətbiqləri və kontaktlara giriş üçün iş tətbiqlərini aktiv edin"</string>
+ <!-- no translation found for resolver_cant_share_cross_profile_explanation (5556640604460901386) -->
+ <skip />
+ <!-- no translation found for resolver_cant_access_work_apps (375634344111233790) -->
+ <skip />
+ <!-- no translation found for resolver_cant_access_work_apps_explanation (3958762224516867388) -->
+ <skip />
+ <!-- no translation found for resolver_cant_access_personal_apps (1953215925406474177) -->
+ <skip />
+ <!-- no translation found for resolver_cant_access_personal_apps_explanation (1725572276741281136) -->
+ <skip />
+ <!-- no translation found for resolver_turn_on_work_apps_share (619263911204978175) -->
+ <skip />
+ <!-- no translation found for resolver_turn_on_work_apps_view (3073389230905543680) -->
+ <skip />
<string name="resolver_no_apps_available" msgid="7710339903040989654">"Heç bir tətbiq əlçatan deyil"</string>
- <string name="resolver_no_apps_available_explanation" msgid="4662694431121196560">"Heç bir tətbiq tapılmadı"</string>
- <string name="resolver_switch_on_work" msgid="8294542702883688533">"İş profilini aktiv edin"</string>
+ <!-- no translation found for resolver_switch_on_work (2873009160846966379) -->
+ <skip />
<string name="permlab_accessCallAudio" msgid="1682957511874097664">"Telefon zənglərində audio yazmaq və ya oxutmaq"</string>
<string name="permdesc_accessCallAudio" msgid="8448360894684277823">"Defolt nömrəyığan tətbiq kimi təyin edildikdə, bu tətbiqə telefon zənglərində audio yazmaq və ya oxutmaq üçün icazə verir."</string>
</resources>
diff --git a/core/res/res/values-b+sr+Latn/strings.xml b/core/res/res/values-b+sr+Latn/strings.xml
index 528b11b9ff0d..c1285210c7e6 100644
--- a/core/res/res/values-b+sr+Latn/strings.xml
+++ b/core/res/res/values-b+sr+Latn/strings.xml
@@ -252,10 +252,8 @@
<item quantity="few">Napravićemo snimak ekrana radi izveštaja o grešci za <xliff:g id="NUMBER_1">%d</xliff:g> sekunde.</item>
<item quantity="other">Napravićemo snimak ekrana radi izveštaja o grešci za <xliff:g id="NUMBER_1">%d</xliff:g> sekundi.</item>
</plurals>
- <!-- no translation found for bugreport_screenshot_success_toast (7986095104151473745) -->
- <skip />
- <!-- no translation found for bugreport_screenshot_failure_toast (6736320861311294294) -->
- <skip />
+ <string name="bugreport_screenshot_success_toast" msgid="7986095104151473745">"Ekran sa izveštajem o grešci je snimljen"</string>
+ <string name="bugreport_screenshot_failure_toast" msgid="6736320861311294294">"Snimanje ekrana sa izveštajem o grešci nije uspelo"</string>
<string name="global_action_toggle_silent_mode" msgid="8464352592860372188">"Nečujni režim"</string>
<string name="global_action_silent_mode_on_status" msgid="2371892537738632013">"Zvuk je ISKLJUČEN"</string>
<string name="global_action_silent_mode_off_status" msgid="6608006545950920042">"Zvuk je UKLJUČEN"</string>
@@ -457,9 +455,11 @@
<string name="permdesc_acceptHandovers" msgid="7129026180128626870">"Dozvoljava aplikaciji da nastavi poziv koji je započet u drugoj aplikaciji."</string>
<string name="permlab_readPhoneNumbers" msgid="5668704794723365628">"čitanje brojeva telefona"</string>
<string name="permdesc_readPhoneNumbers" msgid="7368652482818338871">"Dozvoljava aplikaciji da pristupa brojevima telefona na uređaju."</string>
+ <string name="permlab_wakeLock" product="automotive" msgid="1904736682319375676">"ne isključuj ekran u automobilu"</string>
<string name="permlab_wakeLock" product="tablet" msgid="1527660973931694000">"sprečavanje prelaska tableta u stanje spavanja"</string>
<string name="permlab_wakeLock" product="tv" msgid="2856941418123343518">"sprečava Android TV uređaj da pređe u stanje spavanja"</string>
<string name="permlab_wakeLock" product="default" msgid="569409726861695115">"sprečavanje prelaska telefona u stanje spavanja"</string>
+ <string name="permdesc_wakeLock" product="automotive" msgid="5995045369683254571">"Dozvoljava aplikaciji da ne isključuje ekran u automobilu."</string>
<string name="permdesc_wakeLock" product="tablet" msgid="2441742939101526277">"Dozvoljava aplikaciji da spreči tablet da pređe u stanje spavanja."</string>
<string name="permdesc_wakeLock" product="tv" msgid="2329298966735118796">"Dozvoljava aplikaciji da spreči Android TV uređaj da pređe u stanje spavanja."</string>
<string name="permdesc_wakeLock" product="default" msgid="3689523792074007163">"Dozvoljava aplikaciji da spreči telefon da pređe u stanje spavanja."</string>
@@ -1653,6 +1653,12 @@
<string name="safe_media_volume_warning" product="default" msgid="3751676824423049994">"Želite da pojačate zvuk iznad preporučenog nivoa?\n\nSlušanje glasne muzike duže vreme može da vam ošteti sluh."</string>
<string name="accessibility_shortcut_warning_dialog_title" msgid="4017995837692622933">"Želite li da koristite prečicu za pristupačnost?"</string>
<string name="accessibility_shortcut_toogle_warning" msgid="4161716521310929544">"Kada je prečica uključena, pritisnite oba dugmeta za jačinu zvuka da biste pokrenuli funkciju pristupačnosti."</string>
+ <!-- no translation found for accessibility_select_shortcut_menu_title (7310194076629867377) -->
+ <skip />
+ <!-- no translation found for accessibility_edit_shortcut_menu_button_title (6096484087245145325) -->
+ <skip />
+ <!-- no translation found for accessibility_edit_shortcut_menu_volume_title (4849108668454490699) -->
+ <skip />
<string name="edit_accessibility_shortcut_menu_button" msgid="8885752738733772935">"Izmenite prečice"</string>
<string name="cancel_accessibility_shortcut_menu_button" msgid="1817413122335452474">"Otkaži"</string>
<string name="disable_accessibility_shortcut" msgid="5806091378745232383">"Isključi prečicu"</string>
@@ -1885,8 +1891,7 @@
<string name="default_notification_channel_label" msgid="3697928973567217330">"Nekategorizovano"</string>
<string name="importance_from_user" msgid="2782756722448800447">"Vi podešavate važnost ovih obaveštenja."</string>
<string name="importance_from_person" msgid="4235804979664465383">"Ovo je važno zbog ljudi koji učestvuju."</string>
- <!-- no translation found for notification_history_title_placeholder (7748630986182249599) -->
- <skip />
+ <string name="notification_history_title_placeholder" msgid="7748630986182249599">"Prilagođeno obaveštenje o aplikaciji"</string>
<string name="user_creation_account_exists" msgid="2239146360099708035">"Želite li da dozvolite da <xliff:g id="APP">%1$s</xliff:g> napravi novog korisnika sa nalogom <xliff:g id="ACCOUNT">%2$s</xliff:g> (korisnik sa tim nalogom već postoji)?"</string>
<string name="user_creation_adding" msgid="7305185499667958364">"Želite li da dozvolite da <xliff:g id="APP">%1$s</xliff:g> napravi novog korisnika sa nalogom <xliff:g id="ACCOUNT">%2$s</xliff:g>?"</string>
<string name="language_selection_title" msgid="52674936078683285">"Dodajte jezik"</string>
@@ -2062,14 +2067,29 @@
<string name="as_app_forced_to_restricted_bucket" msgid="8233871289353898964">"Paket <xliff:g id="PACKAGE_NAME">%1$s</xliff:g> je dodat u segment OGRANIČENO"</string>
<string name="resolver_personal_tab" msgid="2051260504014442073">"Lični"</string>
<string name="resolver_work_tab" msgid="2690019516263167035">"Poslovni"</string>
+ <!-- no translation found for resolver_personal_tab_accessibility (5739524949153091224) -->
+ <skip />
+ <!-- no translation found for resolver_work_tab_accessibility (4753168230363802734) -->
+ <skip />
<string name="resolver_cant_share_with_work_apps" msgid="7539495559434146897">"Ne možete da delite sadržaj sa aplikacijama za posao"</string>
<string name="resolver_cant_share_with_personal_apps" msgid="8020581735267157241">"Ne možete da delite sadržaj sa ličnim aplikacijama"</string>
- <string name="resolver_cant_share_cross_profile_explanation" msgid="3536237105241882679">"IT administrator je blokirao deljenje između ličnih aplikacija i aplikacija za posao"</string>
- <string name="resolver_turn_on_work_apps" msgid="8987359079870455469">"Uključite aplikacije za posao"</string>
- <string name="resolver_turn_on_work_apps_explanation" msgid="6322467455509618928">"Uključite aplikacije za posao da biste pristupili aplikacijama i kontaktima za posao"</string>
+ <!-- no translation found for resolver_cant_share_cross_profile_explanation (5556640604460901386) -->
+ <skip />
+ <!-- no translation found for resolver_cant_access_work_apps (375634344111233790) -->
+ <skip />
+ <!-- no translation found for resolver_cant_access_work_apps_explanation (3958762224516867388) -->
+ <skip />
+ <!-- no translation found for resolver_cant_access_personal_apps (1953215925406474177) -->
+ <skip />
+ <!-- no translation found for resolver_cant_access_personal_apps_explanation (1725572276741281136) -->
+ <skip />
+ <!-- no translation found for resolver_turn_on_work_apps_share (619263911204978175) -->
+ <skip />
+ <!-- no translation found for resolver_turn_on_work_apps_view (3073389230905543680) -->
+ <skip />
<string name="resolver_no_apps_available" msgid="7710339903040989654">"Nema dostupnih aplikacija"</string>
- <string name="resolver_no_apps_available_explanation" msgid="4662694431121196560">"Nismo pronašli nijednu aplikaciju"</string>
- <string name="resolver_switch_on_work" msgid="8294542702883688533">"Uključi profil za Work"</string>
+ <!-- no translation found for resolver_switch_on_work (2873009160846966379) -->
+ <skip />
<string name="permlab_accessCallAudio" msgid="1682957511874097664">"Snimanje ili puštanje zvuka u telefonskim pozivima"</string>
<string name="permdesc_accessCallAudio" msgid="8448360894684277823">"Omogućava ovoj aplikaciji, kada je dodeljena kao podrazumevana aplikacija za pozivanje, da snima ili pušta zvuk u telefonskim pozivima."</string>
</resources>
diff --git a/core/res/res/values-be/strings.xml b/core/res/res/values-be/strings.xml
index 1303126cacb7..87ccfe532201 100644
--- a/core/res/res/values-be/strings.xml
+++ b/core/res/res/values-be/strings.xml
@@ -91,7 +91,7 @@
<string name="EmergencyCallWarningSummary" msgid="1194185880092805497">"Экстранныя выклікі ў сетцы Wi‑Fi недаступныя"</string>
<string name="notification_channel_network_alert" msgid="4788053066033851841">"Абвесткі"</string>
<string name="notification_channel_call_forward" msgid="8230490317314272406">"Пераадрасацыя выкліку"</string>
- <string name="notification_channel_emergency_callback" msgid="54074839059123159">"Рэжым экстраннага зваротнага выкліку"</string>
+ <string name="notification_channel_emergency_callback" msgid="54074839059123159">"Рэжым экстранных зваротных выклікаў"</string>
<string name="notification_channel_mobile_data_status" msgid="1941911162076442474">"Стан мабільнай перадачы даных"</string>
<string name="notification_channel_sms" msgid="1243384981025535724">"SMS-паведамленні"</string>
<string name="notification_channel_voice_mail" msgid="8457433203106654172">"Паведамленні галасавой пошты"</string>
@@ -255,10 +255,8 @@
<item quantity="many">Здымак экрана для справаздачы пра памылкі будзе зроблены праз <xliff:g id="NUMBER_1">%d</xliff:g> секунд.</item>
<item quantity="other">Здымак экрана для справаздачы пра памылкі будзе зроблены праз <xliff:g id="NUMBER_1">%d</xliff:g> секунды.</item>
</plurals>
- <!-- no translation found for bugreport_screenshot_success_toast (7986095104151473745) -->
- <skip />
- <!-- no translation found for bugreport_screenshot_failure_toast (6736320861311294294) -->
- <skip />
+ <string name="bugreport_screenshot_success_toast" msgid="7986095104151473745">"Зроблены здымак экрана са справаздачай пра памылкі"</string>
+ <string name="bugreport_screenshot_failure_toast" msgid="6736320861311294294">"Не ўдалося зрабіць здымак экрана са справаздачай пра памылкі"</string>
<string name="global_action_toggle_silent_mode" msgid="8464352592860372188">"Бязгучны рэжым"</string>
<string name="global_action_silent_mode_on_status" msgid="2371892537738632013">"Гук выкл."</string>
<string name="global_action_silent_mode_off_status" msgid="6608006545950920042">"Гук уключаны"</string>
@@ -460,9 +458,11 @@
<string name="permdesc_acceptHandovers" msgid="7129026180128626870">"Дазваляе праграме працягваць выклік, які пачаўся ў іншай праграме."</string>
<string name="permlab_readPhoneNumbers" msgid="5668704794723365628">"счытваць нумары тэлефонаў"</string>
<string name="permdesc_readPhoneNumbers" msgid="7368652482818338871">"Дазваляе праграме атрымліваць доступ да нумароў тэлефонаў на прыладзе."</string>
+ <string name="permlab_wakeLock" product="automotive" msgid="1904736682319375676">"пакідаць экран аўтамабіля ўключаным"</string>
<string name="permlab_wakeLock" product="tablet" msgid="1527660973931694000">"прадухіліць планшэт ад пераходу ў рэжым сну"</string>
<string name="permlab_wakeLock" product="tv" msgid="2856941418123343518">"прадухіляць пераход прылады Android TV у рэжым сну"</string>
<string name="permlab_wakeLock" product="default" msgid="569409726861695115">"забараняць тэлефону пераходзіць ў рэжым сну"</string>
+ <string name="permdesc_wakeLock" product="automotive" msgid="5995045369683254571">"Дазваляе праграме пакідаць экран аўтамабіля ўключаным."</string>
<string name="permdesc_wakeLock" product="tablet" msgid="2441742939101526277">"Дазваляе прыкладанням прадухіляць пераход планшэта ў рэжым сну."</string>
<string name="permdesc_wakeLock" product="tv" msgid="2329298966735118796">"Дазваляе праграме прадухіляць пераход прылады Android TV у рэжым сну."</string>
<string name="permdesc_wakeLock" product="default" msgid="3689523792074007163">"Дазваляе прыкладанням прадухіляць тэлефон ад пераходу ў рэжым сну."</string>
@@ -1675,6 +1675,12 @@
<string name="safe_media_volume_warning" product="default" msgid="3751676824423049994">"Павялiчыць гук вышэй рэкамендаванага ўзроўню?\n\nДоўгае праслухоўванне музыкi на вялiкай гучнасцi можа пашкодзiць ваш слых."</string>
<string name="accessibility_shortcut_warning_dialog_title" msgid="4017995837692622933">"Выкарыстоўваць камбінацыю хуткага доступу для спецыяльных магчымасцей?"</string>
<string name="accessibility_shortcut_toogle_warning" msgid="4161716521310929544">"Калі хуткі доступ уключаны, вы можаце націснуць абедзве кнопкі гучнасці і ўтрымліваць іх 3 секунды, каб запусціць функцыю спецыяльных магчымасцей."</string>
+ <!-- no translation found for accessibility_select_shortcut_menu_title (7310194076629867377) -->
+ <skip />
+ <!-- no translation found for accessibility_edit_shortcut_menu_button_title (6096484087245145325) -->
+ <skip />
+ <!-- no translation found for accessibility_edit_shortcut_menu_volume_title (4849108668454490699) -->
+ <skip />
<string name="edit_accessibility_shortcut_menu_button" msgid="8885752738733772935">"Змяніць ярлыкі"</string>
<string name="cancel_accessibility_shortcut_menu_button" msgid="1817413122335452474">"Скасаваць"</string>
<string name="disable_accessibility_shortcut" msgid="5806091378745232383">"Дэактываваць камбінацыю хуткага доступу"</string>
@@ -1917,8 +1923,7 @@
<string name="default_notification_channel_label" msgid="3697928973567217330">"Некатэгарызаванае"</string>
<string name="importance_from_user" msgid="2782756722448800447">"Вы задалі важнасць гэтых апавяшчэнняў."</string>
<string name="importance_from_person" msgid="4235804979664465383">"Гэта важна, бо з гэтым звязаны пэўныя людзі."</string>
- <!-- no translation found for notification_history_title_placeholder (7748630986182249599) -->
- <skip />
+ <string name="notification_history_title_placeholder" msgid="7748630986182249599">"Апавяшчэнне пра карыстальніцкую праграму"</string>
<string name="user_creation_account_exists" msgid="2239146360099708035">"Дазволіць праграме \"<xliff:g id="APP">%1$s</xliff:g>\" стварыць новага Карыстальніка з уліковым запісам <xliff:g id="ACCOUNT">%2$s</xliff:g> (Карыстальнік з гэтым уліковым запісам ужо існуе)?"</string>
<string name="user_creation_adding" msgid="7305185499667958364">"Дазволіць праграме \"<xliff:g id="APP">%1$s</xliff:g>\" стварыць новага Карыстальніка з уліковым запісам <xliff:g id="ACCOUNT">%2$s</xliff:g>?"</string>
<string name="language_selection_title" msgid="52674936078683285">"Дадаць мову"</string>
@@ -2096,14 +2101,29 @@
<string name="as_app_forced_to_restricted_bucket" msgid="8233871289353898964">"Пакет \"<xliff:g id="PACKAGE_NAME">%1$s</xliff:g>\" дададзены ў АБМЕЖАВАНУЮ групу"</string>
<string name="resolver_personal_tab" msgid="2051260504014442073">"Асабістыя"</string>
<string name="resolver_work_tab" msgid="2690019516263167035">"Працоўныя"</string>
+ <!-- no translation found for resolver_personal_tab_accessibility (5739524949153091224) -->
+ <skip />
+ <!-- no translation found for resolver_work_tab_accessibility (4753168230363802734) -->
+ <skip />
<string name="resolver_cant_share_with_work_apps" msgid="7539495559434146897">"Не ўдалося абагуліць з працоўнымі праграмамі"</string>
<string name="resolver_cant_share_with_personal_apps" msgid="8020581735267157241">"Не ўдалося абагуліць з асабістымі праграмамі"</string>
- <string name="resolver_cant_share_cross_profile_explanation" msgid="3536237105241882679">"Ваш ІТ-адміністратар заблакіраваў абагульванне паміж асабістымі і працоўнымі праграмамі"</string>
- <string name="resolver_turn_on_work_apps" msgid="8987359079870455469">"Уключыце працоўныя праграмы"</string>
- <string name="resolver_turn_on_work_apps_explanation" msgid="6322467455509618928">"Уключыце працоўныя праграмы, каб мець доступ да іх і да кантактаў"</string>
+ <!-- no translation found for resolver_cant_share_cross_profile_explanation (5556640604460901386) -->
+ <skip />
+ <!-- no translation found for resolver_cant_access_work_apps (375634344111233790) -->
+ <skip />
+ <!-- no translation found for resolver_cant_access_work_apps_explanation (3958762224516867388) -->
+ <skip />
+ <!-- no translation found for resolver_cant_access_personal_apps (1953215925406474177) -->
+ <skip />
+ <!-- no translation found for resolver_cant_access_personal_apps_explanation (1725572276741281136) -->
+ <skip />
+ <!-- no translation found for resolver_turn_on_work_apps_share (619263911204978175) -->
+ <skip />
+ <!-- no translation found for resolver_turn_on_work_apps_view (3073389230905543680) -->
+ <skip />
<string name="resolver_no_apps_available" msgid="7710339903040989654">"Няма даступных праграм"</string>
- <string name="resolver_no_apps_available_explanation" msgid="4662694431121196560">"Нам не ўдалося знайсці ніводнай праграмы"</string>
- <string name="resolver_switch_on_work" msgid="8294542702883688533">"Пераключыцца на працоўны профіль"</string>
+ <!-- no translation found for resolver_switch_on_work (2873009160846966379) -->
+ <skip />
<string name="permlab_accessCallAudio" msgid="1682957511874097664">"Запісваць або прайграваць аўдыя ў тэлефонных выкліках"</string>
<string name="permdesc_accessCallAudio" msgid="8448360894684277823">"Дазваляе гэтай праграме (калі яна наладжана ў якасці стандартнага набіральніка нумара) запісваць або прайграваць аўдыя ў тэлефонных выкліках."</string>
</resources>
diff --git a/core/res/res/values-bg/strings.xml b/core/res/res/values-bg/strings.xml
index 33e59aa20dab..d6830629d5d8 100644
--- a/core/res/res/values-bg/strings.xml
+++ b/core/res/res/values-bg/strings.xml
@@ -249,10 +249,8 @@
<item quantity="other">Екранната снимка за сигнала за програмна грешка ще бъде направена след <xliff:g id="NUMBER_1">%d</xliff:g> секунди.</item>
<item quantity="one">Екранната снимка за сигнала за програмна грешка ще бъде направена след <xliff:g id="NUMBER_0">%d</xliff:g> секунда.</item>
</plurals>
- <!-- no translation found for bugreport_screenshot_success_toast (7986095104151473745) -->
- <skip />
- <!-- no translation found for bugreport_screenshot_failure_toast (6736320861311294294) -->
- <skip />
+ <string name="bugreport_screenshot_success_toast" msgid="7986095104151473745">"Екранната снимка със сигнал за програмна грешка бе направена"</string>
+ <string name="bugreport_screenshot_failure_toast" msgid="6736320861311294294">"Правенето на екранна снимка със сигнал за програмна грешка не бе успешно"</string>
<string name="global_action_toggle_silent_mode" msgid="8464352592860372188">"Тих режим"</string>
<string name="global_action_silent_mode_on_status" msgid="2371892537738632013">"Звукът е ИЗКЛЮЧЕН"</string>
<string name="global_action_silent_mode_off_status" msgid="6608006545950920042">"Звукът е ВКЛЮЧЕН"</string>
@@ -454,9 +452,11 @@
<string name="permdesc_acceptHandovers" msgid="7129026180128626870">"Разрешава на приложението да продължи обаждане, стартирано в друго приложение."</string>
<string name="permlab_readPhoneNumbers" msgid="5668704794723365628">"четене на телефонните номера"</string>
<string name="permdesc_readPhoneNumbers" msgid="7368652482818338871">"Разрешава на приложението да осъществява достъп до телефонните номера на устройството."</string>
+ <string name="permlab_wakeLock" product="automotive" msgid="1904736682319375676">"постоянно включен екран на автомобила"</string>
<string name="permlab_wakeLock" product="tablet" msgid="1527660973931694000">"предотвратяване на спящия режим на таблета"</string>
<string name="permlab_wakeLock" product="tv" msgid="2856941418123343518">"предотвратяване на активирането на спящия режим на устройството ви с Android TV"</string>
<string name="permlab_wakeLock" product="default" msgid="569409726861695115">"предотвратява спящ режим на телефона"</string>
+ <string name="permdesc_wakeLock" product="automotive" msgid="5995045369683254571">"Дава възможност на приложението да поддържа екрана на автомобила включен."</string>
<string name="permdesc_wakeLock" product="tablet" msgid="2441742939101526277">"Разрешава на приложението да предотвратява преминаването на таблета в спящ режим."</string>
<string name="permdesc_wakeLock" product="tv" msgid="2329298966735118796">"Дава възможност на приложението да предотвратява преминаването в спящ режим на устройството ви с Android TV."</string>
<string name="permdesc_wakeLock" product="default" msgid="3689523792074007163">"Разрешава на приложението да предотвратява преминаването на телефона в спящ режим."</string>
@@ -1631,6 +1631,12 @@
<string name="safe_media_volume_warning" product="default" msgid="3751676824423049994">"Да се увеличи ли силата на звука над препоръчителното ниво?\n\nПродължителното слушане при висока сила на звука може да увреди слуха ви."</string>
<string name="accessibility_shortcut_warning_dialog_title" msgid="4017995837692622933">"Искате ли да използвате пряк път към функцията за достъпност?"</string>
<string name="accessibility_shortcut_toogle_warning" msgid="4161716521310929544">"Когато прекият път е включен, можете да стартирате дадена функция за достъпност, като натиснете двата бутона за силата на звука и ги задържите за 3 секунди."</string>
+ <!-- no translation found for accessibility_select_shortcut_menu_title (7310194076629867377) -->
+ <skip />
+ <!-- no translation found for accessibility_edit_shortcut_menu_button_title (6096484087245145325) -->
+ <skip />
+ <!-- no translation found for accessibility_edit_shortcut_menu_volume_title (4849108668454490699) -->
+ <skip />
<string name="edit_accessibility_shortcut_menu_button" msgid="8885752738733772935">"Редактиране на преките пътища"</string>
<string name="cancel_accessibility_shortcut_menu_button" msgid="1817413122335452474">"Отказ"</string>
<string name="disable_accessibility_shortcut" msgid="5806091378745232383">"Изключване на прекия път"</string>
@@ -1853,8 +1859,7 @@
<string name="default_notification_channel_label" msgid="3697928973567217330">"Некатегоризирани"</string>
<string name="importance_from_user" msgid="2782756722448800447">"Зададохте важността на тези известия."</string>
<string name="importance_from_person" msgid="4235804979664465383">"Това е важно заради участващите хора."</string>
- <!-- no translation found for notification_history_title_placeholder (7748630986182249599) -->
- <skip />
+ <string name="notification_history_title_placeholder" msgid="7748630986182249599">"Персонализирано известие за приложение"</string>
<string name="user_creation_account_exists" msgid="2239146360099708035">"Да се разреши ли на <xliff:g id="APP">%1$s</xliff:g> да създаде нов потребител с профила <xliff:g id="ACCOUNT">%2$s</xliff:g> (вече съществува потребител с този профил)?"</string>
<string name="user_creation_adding" msgid="7305185499667958364">"Да се разреши ли на <xliff:g id="APP">%1$s</xliff:g> да създаде нов потребител с профила <xliff:g id="ACCOUNT">%2$s</xliff:g>?"</string>
<string name="language_selection_title" msgid="52674936078683285">"Добавяне на език"</string>
@@ -2028,14 +2033,29 @@
<string name="as_app_forced_to_restricted_bucket" msgid="8233871289353898964">"Пакетът <xliff:g id="PACKAGE_NAME">%1$s</xliff:g> е поставен в ОГРАНИЧЕНИЯ контейнер"</string>
<string name="resolver_personal_tab" msgid="2051260504014442073">"Лични"</string>
<string name="resolver_work_tab" msgid="2690019516263167035">"Служебни"</string>
+ <!-- no translation found for resolver_personal_tab_accessibility (5739524949153091224) -->
+ <skip />
+ <!-- no translation found for resolver_work_tab_accessibility (4753168230363802734) -->
+ <skip />
<string name="resolver_cant_share_with_work_apps" msgid="7539495559434146897">"Споделянето със служебни приложения не е възможно"</string>
<string name="resolver_cant_share_with_personal_apps" msgid="8020581735267157241">"Споделянето с лични приложения не е възможно"</string>
- <string name="resolver_cant_share_cross_profile_explanation" msgid="3536237105241882679">"Системният ви администратор е блокирал споделянето между лични и служебни приложения"</string>
- <string name="resolver_turn_on_work_apps" msgid="8987359079870455469">"Включете служебните приложения"</string>
- <string name="resolver_turn_on_work_apps_explanation" msgid="6322467455509618928">"Включете служебните приложения, за да имате достъп до тях и служебните контакти"</string>
+ <!-- no translation found for resolver_cant_share_cross_profile_explanation (5556640604460901386) -->
+ <skip />
+ <!-- no translation found for resolver_cant_access_work_apps (375634344111233790) -->
+ <skip />
+ <!-- no translation found for resolver_cant_access_work_apps_explanation (3958762224516867388) -->
+ <skip />
+ <!-- no translation found for resolver_cant_access_personal_apps (1953215925406474177) -->
+ <skip />
+ <!-- no translation found for resolver_cant_access_personal_apps_explanation (1725572276741281136) -->
+ <skip />
+ <!-- no translation found for resolver_turn_on_work_apps_share (619263911204978175) -->
+ <skip />
+ <!-- no translation found for resolver_turn_on_work_apps_view (3073389230905543680) -->
+ <skip />
<string name="resolver_no_apps_available" msgid="7710339903040989654">"Няма приложения"</string>
- <string name="resolver_no_apps_available_explanation" msgid="4662694431121196560">"Не успяхме да намерим приложения"</string>
- <string name="resolver_switch_on_work" msgid="8294542702883688533">"Включване на служебния потребителски профил"</string>
+ <!-- no translation found for resolver_switch_on_work (2873009160846966379) -->
+ <skip />
<string name="permlab_accessCallAudio" msgid="1682957511874097664">"Записване или възпроизвеждане на аудио при телефонни обаждания"</string>
<string name="permdesc_accessCallAudio" msgid="8448360894684277823">"Дава възможност на това приложение да записва или възпроизвежда аудио при телефонни обаждания, когато е зададено като основно приложение за набиране."</string>
</resources>
diff --git a/core/res/res/values-bn/strings.xml b/core/res/res/values-bn/strings.xml
index 386c303338cc..8994e868166e 100644
--- a/core/res/res/values-bn/strings.xml
+++ b/core/res/res/values-bn/strings.xml
@@ -249,10 +249,8 @@
<item quantity="one"><xliff:g id="NUMBER_1">%d</xliff:g> সেকেন্ডের মধ্যে ত্রুটির প্রতিবেদনের জন্য স্ক্রিনশট নেওয়া হচ্ছে৷</item>
<item quantity="other"><xliff:g id="NUMBER_1">%d</xliff:g> সেকেন্ডের মধ্যে ত্রুটির প্রতিবেদনের জন্য স্ক্রিনশট নেওয়া হচ্ছে৷</item>
</plurals>
- <!-- no translation found for bugreport_screenshot_success_toast (7986095104151473745) -->
- <skip />
- <!-- no translation found for bugreport_screenshot_failure_toast (6736320861311294294) -->
- <skip />
+ <string name="bugreport_screenshot_success_toast" msgid="7986095104151473745">"সমস্যা সংক্রান্ত রিপোর্টের স্ক্রিনশট নেওয়া হয়েছে"</string>
+ <string name="bugreport_screenshot_failure_toast" msgid="6736320861311294294">"সমস্যার সংক্রান্ত রিপোর্টের স্ক্রিনশট নেওয়া যায়নি"</string>
<string name="global_action_toggle_silent_mode" msgid="8464352592860372188">"নীরব মোড"</string>
<string name="global_action_silent_mode_on_status" msgid="2371892537738632013">"শব্দ বন্ধ করা আছে"</string>
<string name="global_action_silent_mode_off_status" msgid="6608006545950920042">"শব্দ চালু করা আছে"</string>
@@ -454,9 +452,11 @@
<string name="permdesc_acceptHandovers" msgid="7129026180128626870">"অন্য কোনও অ্যাপ দিয়ে কল করলে এই অ্যাপটিকে সেটি চালিয়ে যেতে দেয়।"</string>
<string name="permlab_readPhoneNumbers" msgid="5668704794723365628">"ফোন নম্বরগুলি পড়া হোক"</string>
<string name="permdesc_readPhoneNumbers" msgid="7368652482818338871">"অ্যাপটিকে এই ডিভাইসের ফোন নম্বরগুলি অ্যাক্সেস করতে দেয়।"</string>
+ <string name="permlab_wakeLock" product="automotive" msgid="1904736682319375676">"গাড়ির স্ক্রিন চালু রাখা আছে"</string>
<string name="permlab_wakeLock" product="tablet" msgid="1527660973931694000">"ঘুমানো থেকে ট্যাবলেটকে প্রতিরোধ করে"</string>
<string name="permlab_wakeLock" product="tv" msgid="2856941418123343518">"আপনার Android TV ডিভাইসকে স্লিপ মোডে চলে যাওয়া থেকে আটকান"</string>
<string name="permlab_wakeLock" product="default" msgid="569409726861695115">"ঘুমানো থেকে ফোনটিকে প্রতিরোধ করে"</string>
+ <string name="permdesc_wakeLock" product="automotive" msgid="5995045369683254571">"গাড়ির স্ক্রিন চালু রাখতে অ্যাপকে অনুমতি দেয়।"</string>
<string name="permdesc_wakeLock" product="tablet" msgid="2441742939101526277">"অ্যাপ্লিকেশানকে ট্যাবলেট নিদ্রায় যাওয়া থেকে প্রতিরোধ করার মঞ্জুরি দেয়৷"</string>
<string name="permdesc_wakeLock" product="tv" msgid="2329298966735118796">"অ্যাপটিকে আপনার Android TV ডিভাইস স্লিপ মোডে চলে যাওয়া থেকে আটকানোর অনুমতি দেয়।"</string>
<string name="permdesc_wakeLock" product="default" msgid="3689523792074007163">"অ্যাপ্লিকেশানকে ফোনকে নিদ্রায় যাওয়া থেকে প্রতিরোধ করার মঞ্জুরি দেয়৷"</string>
@@ -1631,6 +1631,12 @@
<string name="safe_media_volume_warning" product="default" msgid="3751676824423049994">"প্রস্তাবিত স্তরের চেয়ে বেশি উঁচুতে ভলিউম বাড়াবেন?\n\nউঁচু ভলিউমে বেশি সময় ধরে কিছু শুনলে আপনার শ্রবনশক্তির ক্ষতি হতে পারে।"</string>
<string name="accessibility_shortcut_warning_dialog_title" msgid="4017995837692622933">"অ্যাক্সেসযোগ্যতা শর্টকাট ব্যবহার করবেন?"</string>
<string name="accessibility_shortcut_toogle_warning" msgid="4161716521310929544">"শর্টকাট চালু করা থাকাকালীন দুটি ভলিউম বোতাম একসাথে ৩ সেকেন্ড টিপে ধরে রাখলে একটি অ্যাকসেসিবিলিটি ফিচার চালু হবে।"</string>
+ <!-- no translation found for accessibility_select_shortcut_menu_title (7310194076629867377) -->
+ <skip />
+ <!-- no translation found for accessibility_edit_shortcut_menu_button_title (6096484087245145325) -->
+ <skip />
+ <!-- no translation found for accessibility_edit_shortcut_menu_volume_title (4849108668454490699) -->
+ <skip />
<string name="edit_accessibility_shortcut_menu_button" msgid="8885752738733772935">"শর্টকাট এডিট করুন"</string>
<string name="cancel_accessibility_shortcut_menu_button" msgid="1817413122335452474">"বাতিল করুন"</string>
<string name="disable_accessibility_shortcut" msgid="5806091378745232383">"শর্টকাট বন্ধ করুন"</string>
@@ -2028,14 +2034,29 @@
<string name="as_app_forced_to_restricted_bucket" msgid="8233871289353898964">"<xliff:g id="PACKAGE_NAME">%1$s</xliff:g> সীমাবদ্ধ গ্রুপে অন্তর্ভুক্ত করা হয়েছে"</string>
<string name="resolver_personal_tab" msgid="2051260504014442073">"ব্যক্তিগত"</string>
<string name="resolver_work_tab" msgid="2690019516263167035">"অফিস"</string>
+ <!-- no translation found for resolver_personal_tab_accessibility (5739524949153091224) -->
+ <skip />
+ <!-- no translation found for resolver_work_tab_accessibility (4753168230363802734) -->
+ <skip />
<string name="resolver_cant_share_with_work_apps" msgid="7539495559434146897">"অফিস অ্যাপের সাথে শেয়ার করা যাচ্ছে না"</string>
<string name="resolver_cant_share_with_personal_apps" msgid="8020581735267157241">"ব্যক্তিগত অ্যাপের সাথে শেয়ার করা যাচ্ছে না"</string>
- <string name="resolver_cant_share_cross_profile_explanation" msgid="3536237105241882679">"আপনার IT অ্যাডমিন ব্যক্তিগত ও অফিস অ্যাপের মধ্যে শেয়ার করা ব্লক করে রেখেছেন"</string>
- <string name="resolver_turn_on_work_apps" msgid="8987359079870455469">"অফিসের অ্যাপ চালু করুন"</string>
- <string name="resolver_turn_on_work_apps_explanation" msgid="6322467455509618928">"অফিসের অ্যাপ ও পরিচিতি অ্যাক্সেস করার জন্য অফিসের অ্যাপ চালু করুন"</string>
+ <!-- no translation found for resolver_cant_share_cross_profile_explanation (5556640604460901386) -->
+ <skip />
+ <!-- no translation found for resolver_cant_access_work_apps (375634344111233790) -->
+ <skip />
+ <!-- no translation found for resolver_cant_access_work_apps_explanation (3958762224516867388) -->
+ <skip />
+ <!-- no translation found for resolver_cant_access_personal_apps (1953215925406474177) -->
+ <skip />
+ <!-- no translation found for resolver_cant_access_personal_apps_explanation (1725572276741281136) -->
+ <skip />
+ <!-- no translation found for resolver_turn_on_work_apps_share (619263911204978175) -->
+ <skip />
+ <!-- no translation found for resolver_turn_on_work_apps_view (3073389230905543680) -->
+ <skip />
<string name="resolver_no_apps_available" msgid="7710339903040989654">"কোনও অ্যাপ উপলভ্য নেই"</string>
- <string name="resolver_no_apps_available_explanation" msgid="4662694431121196560">"কোনও অ্যাপ খুঁজে পাওয়া যায়নি"</string>
- <string name="resolver_switch_on_work" msgid="8294542702883688533">"অফিস প্রোফাইল চালু করুন"</string>
+ <!-- no translation found for resolver_switch_on_work (2873009160846966379) -->
+ <skip />
<string name="permlab_accessCallAudio" msgid="1682957511874097664">"টেলিফোন কলে অডিও রেকর্ড বা প্লে করুন"</string>
<string name="permdesc_accessCallAudio" msgid="8448360894684277823">"ডিফল্ট ডায়ালার অ্যাপ্লিকেশন হিসেবে বেছে নেওয়া হলে, টেলিফোন কলে অডিও রেকর্ড বা প্লে করার জন্য এই অ্যাপকে অনুমতি দেয়।"</string>
</resources>
diff --git a/core/res/res/values-bs/strings.xml b/core/res/res/values-bs/strings.xml
index 743e8c4fb4ba..724c1c3628ff 100644
--- a/core/res/res/values-bs/strings.xml
+++ b/core/res/res/values-bs/strings.xml
@@ -252,10 +252,8 @@
<item quantity="few">Snimak ekrana za prijavu greške pravim za <xliff:g id="NUMBER_1">%d</xliff:g> sekunde.</item>
<item quantity="other">Snimak ekrana za prijavu greške pravim za <xliff:g id="NUMBER_1">%d</xliff:g> sekundi.</item>
</plurals>
- <!-- no translation found for bugreport_screenshot_success_toast (7986095104151473745) -->
- <skip />
- <!-- no translation found for bugreport_screenshot_failure_toast (6736320861311294294) -->
- <skip />
+ <string name="bugreport_screenshot_success_toast" msgid="7986095104151473745">"Napravljen je snimak ekrana s izvještajem o grešci"</string>
+ <string name="bugreport_screenshot_failure_toast" msgid="6736320861311294294">"Snimanje ekrana s izvještajem o grešci nije uspjelo"</string>
<string name="global_action_toggle_silent_mode" msgid="8464352592860372188">"Nečujni način rada"</string>
<string name="global_action_silent_mode_on_status" msgid="2371892537738632013">"Zvuk je isključen"</string>
<string name="global_action_silent_mode_off_status" msgid="6608006545950920042">"Zvuk je uključen"</string>
@@ -457,9 +455,11 @@
<string name="permdesc_acceptHandovers" msgid="7129026180128626870">"Dozvoljava aplikaciji nastavljanje poziva koji je započet u drugoj aplikaciji."</string>
<string name="permlab_readPhoneNumbers" msgid="5668704794723365628">"čitanje telefonskih brojeva"</string>
<string name="permdesc_readPhoneNumbers" msgid="7368652482818338871">"Dozvoljava aplikaciji pristup telefonskim brojevima uređaja."</string>
+ <string name="permlab_wakeLock" product="automotive" msgid="1904736682319375676">"ostavi ekran automobila uključenim"</string>
<string name="permlab_wakeLock" product="tablet" msgid="1527660973931694000">"sprečavanje tableta da uđe u režim mirovanja"</string>
<string name="permlab_wakeLock" product="tv" msgid="2856941418123343518">"sprečavanje stupanja Android TV uređaja u stanje mirovanja"</string>
<string name="permlab_wakeLock" product="default" msgid="569409726861695115">"sprečavanje telefona da uđe u režim mirovanja"</string>
+ <string name="permdesc_wakeLock" product="automotive" msgid="5995045369683254571">"Dozvoljava aplikaciji da ostavi ekran automobila uključenim."</string>
<string name="permdesc_wakeLock" product="tablet" msgid="2441742939101526277">"Dozvoljava aplikaciji da spriječi tablet da ode u stanje mirovanja."</string>
<string name="permdesc_wakeLock" product="tv" msgid="2329298966735118796">"Omogućava aplikaciji da spriječi stupanje Android TV uređaja u stanje mirovanja."</string>
<string name="permdesc_wakeLock" product="default" msgid="3689523792074007163">"Dozvoljava aplikaciji da spriječi telefon da ode u stanje mirovanja."</string>
@@ -1655,6 +1655,12 @@
<string name="safe_media_volume_warning" product="default" msgid="3751676824423049994">"Želite li pojačati zvuk iznad preporučenog nivoa?\n\nDužim slušanjem glasnog zvuka možete oštetiti sluh."</string>
<string name="accessibility_shortcut_warning_dialog_title" msgid="4017995837692622933">"Želite li koristiti Prečicu za pristupačnost?"</string>
<string name="accessibility_shortcut_toogle_warning" msgid="4161716521310929544">"Kada je prečica uključena, pritiskom i držanjem oba dugmeta za jačinu zvuka u trajanju od 3 sekunde pokrenut će se funkcija pristupačnosti."</string>
+ <!-- no translation found for accessibility_select_shortcut_menu_title (7310194076629867377) -->
+ <skip />
+ <!-- no translation found for accessibility_edit_shortcut_menu_button_title (6096484087245145325) -->
+ <skip />
+ <!-- no translation found for accessibility_edit_shortcut_menu_volume_title (4849108668454490699) -->
+ <skip />
<string name="edit_accessibility_shortcut_menu_button" msgid="8885752738733772935">"Uredi prečice"</string>
<string name="cancel_accessibility_shortcut_menu_button" msgid="1817413122335452474">"Otkaži"</string>
<string name="disable_accessibility_shortcut" msgid="5806091378745232383">"Isključi prečicu"</string>
@@ -1887,8 +1893,7 @@
<string name="default_notification_channel_label" msgid="3697928973567217330">"Nije kategorizirano"</string>
<string name="importance_from_user" msgid="2782756722448800447">"Vi određujete značaj ovih obavještenja."</string>
<string name="importance_from_person" msgid="4235804979664465383">"Ovo je značajno zbog osoba koje su uključene."</string>
- <!-- no translation found for notification_history_title_placeholder (7748630986182249599) -->
- <skip />
+ <string name="notification_history_title_placeholder" msgid="7748630986182249599">"Prilagođeno obavještenje aplikacije"</string>
<string name="user_creation_account_exists" msgid="2239146360099708035">"Dozvoliti aplikaciji <xliff:g id="APP">%1$s</xliff:g> da kreira novog korisnika s računom <xliff:g id="ACCOUNT">%2$s</xliff:g> (korisnik s ovim računom već postoji)?"</string>
<string name="user_creation_adding" msgid="7305185499667958364">"Dozvoliti aplikaciji <xliff:g id="APP">%1$s</xliff:g> da kreira novog korisnika s računom <xliff:g id="ACCOUNT">%2$s</xliff:g>?"</string>
<string name="language_selection_title" msgid="52674936078683285">"Dodajte jezik"</string>
@@ -2064,14 +2069,29 @@
<string name="as_app_forced_to_restricted_bucket" msgid="8233871289353898964">"Paket <xliff:g id="PACKAGE_NAME">%1$s</xliff:g> je stavljen u odjeljak OGRANIČENO"</string>
<string name="resolver_personal_tab" msgid="2051260504014442073">"Lično"</string>
<string name="resolver_work_tab" msgid="2690019516263167035">"Posao"</string>
+ <!-- no translation found for resolver_personal_tab_accessibility (5739524949153091224) -->
+ <skip />
+ <!-- no translation found for resolver_work_tab_accessibility (4753168230363802734) -->
+ <skip />
<string name="resolver_cant_share_with_work_apps" msgid="7539495559434146897">"Nije moguće dijeliti s poslovnim aplikacijama"</string>
<string name="resolver_cant_share_with_personal_apps" msgid="8020581735267157241">"Nije moguće dijeliti s ličnim aplikacijama"</string>
- <string name="resolver_cant_share_cross_profile_explanation" msgid="3536237105241882679">"Vaš IT administrator je blokirao dijeljenje između ličnih i poslovnih aplikacija"</string>
- <string name="resolver_turn_on_work_apps" msgid="8987359079870455469">"Uključite poslovne aplikacije"</string>
- <string name="resolver_turn_on_work_apps_explanation" msgid="6322467455509618928">"Uključite poslovne aplikacije da pristupite poslovnim aplikacijama i kontaktima"</string>
+ <!-- no translation found for resolver_cant_share_cross_profile_explanation (5556640604460901386) -->
+ <skip />
+ <!-- no translation found for resolver_cant_access_work_apps (375634344111233790) -->
+ <skip />
+ <!-- no translation found for resolver_cant_access_work_apps_explanation (3958762224516867388) -->
+ <skip />
+ <!-- no translation found for resolver_cant_access_personal_apps (1953215925406474177) -->
+ <skip />
+ <!-- no translation found for resolver_cant_access_personal_apps_explanation (1725572276741281136) -->
+ <skip />
+ <!-- no translation found for resolver_turn_on_work_apps_share (619263911204978175) -->
+ <skip />
+ <!-- no translation found for resolver_turn_on_work_apps_view (3073389230905543680) -->
+ <skip />
<string name="resolver_no_apps_available" msgid="7710339903040989654">"Nema dostupnih aplikacija"</string>
- <string name="resolver_no_apps_available_explanation" msgid="4662694431121196560">"Nismo pronašli nijednu aplikaciju"</string>
- <string name="resolver_switch_on_work" msgid="8294542702883688533">"Prebaci na radni"</string>
+ <!-- no translation found for resolver_switch_on_work (2873009160846966379) -->
+ <skip />
<string name="permlab_accessCallAudio" msgid="1682957511874097664">"Snimanje ili reproduciranje zvuka u telefonskim pozivima"</string>
<string name="permdesc_accessCallAudio" msgid="8448360894684277823">"Kad je ova aplikacija postavljena kao zadana aplikacija za pozivanje, omogućava joj snimanje ili reproduciranje zvuka u telefonskim pozivima."</string>
</resources>
diff --git a/core/res/res/values-ca/strings.xml b/core/res/res/values-ca/strings.xml
index 481cafd3f245..f3d8c36f1857 100644
--- a/core/res/res/values-ca/strings.xml
+++ b/core/res/res/values-ca/strings.xml
@@ -249,10 +249,8 @@
<item quantity="other">Es farà una captura de pantalla de l\'informe d\'errors d\'aquí a <xliff:g id="NUMBER_1">%d</xliff:g> segons.</item>
<item quantity="one">Es farà una captura de pantalla de l\'informe d\'errors d\'aquí a <xliff:g id="NUMBER_0">%d</xliff:g> segon.</item>
</plurals>
- <!-- no translation found for bugreport_screenshot_success_toast (7986095104151473745) -->
- <skip />
- <!-- no translation found for bugreport_screenshot_failure_toast (6736320861311294294) -->
- <skip />
+ <string name="bugreport_screenshot_success_toast" msgid="7986095104151473745">"S\'ha fet la captura de pantalla amb l\'informe d\'errors"</string>
+ <string name="bugreport_screenshot_failure_toast" msgid="6736320861311294294">"No s\'ha pogut fer la captura de pantalla amb l\'informe d\'errors"</string>
<string name="global_action_toggle_silent_mode" msgid="8464352592860372188">"Mode silenciós"</string>
<string name="global_action_silent_mode_on_status" msgid="2371892537738632013">"So desactivat"</string>
<string name="global_action_silent_mode_off_status" msgid="6608006545950920042">"El so està activat"</string>
@@ -454,9 +452,11 @@
<string name="permdesc_acceptHandovers" msgid="7129026180128626870">"Permet que l\'aplicació continuï una trucada que s\'havia iniciat en una altra aplicació."</string>
<string name="permlab_readPhoneNumbers" msgid="5668704794723365628">"llegir els números de telèfon"</string>
<string name="permdesc_readPhoneNumbers" msgid="7368652482818338871">"Permet que l\'aplicació accedeixi als números de telèfon del dispositiu."</string>
+ <string name="permlab_wakeLock" product="automotive" msgid="1904736682319375676">"mantén la pantalla del cotxe encesa"</string>
<string name="permlab_wakeLock" product="tablet" msgid="1527660973931694000">"evita que la tauleta entri en mode de repòs"</string>
<string name="permlab_wakeLock" product="tv" msgid="2856941418123343518">"evita que el dispositiu Android TV activi el mode en repòs"</string>
<string name="permlab_wakeLock" product="default" msgid="569409726861695115">"impedir que el telèfon entri en mode de repòs"</string>
+ <string name="permdesc_wakeLock" product="automotive" msgid="5995045369683254571">"Permet que l\'aplicació mantingui la pantalla del cotxe encesa."</string>
<string name="permdesc_wakeLock" product="tablet" msgid="2441742939101526277">"Permet que l\'aplicació impedeixi que la tauleta entri en repòs."</string>
<string name="permdesc_wakeLock" product="tv" msgid="2329298966735118796">"Permet que l\'aplicació impedeixi que el dispositiu Android TV entri en repòs."</string>
<string name="permdesc_wakeLock" product="default" msgid="3689523792074007163">"Permet que l\'aplicació impedeixi que el telèfon entri en repòs."</string>
@@ -1631,6 +1631,12 @@
<string name="safe_media_volume_warning" product="default" msgid="3751676824423049994">"Vols apujar el volum per sobre del nivell recomanat?\n\nSi escoltes música a un volum alt durant períodes llargs, pots danyar-te l\'oïda."</string>
<string name="accessibility_shortcut_warning_dialog_title" msgid="4017995837692622933">"Vols fer servir la drecera d\'accessibilitat?"</string>
<string name="accessibility_shortcut_toogle_warning" msgid="4161716521310929544">"Si la drecera està activada, prem els dos botons de volum durant 3 segons per iniciar una funció d\'accessibilitat."</string>
+ <!-- no translation found for accessibility_select_shortcut_menu_title (7310194076629867377) -->
+ <skip />
+ <!-- no translation found for accessibility_edit_shortcut_menu_button_title (6096484087245145325) -->
+ <skip />
+ <!-- no translation found for accessibility_edit_shortcut_menu_volume_title (4849108668454490699) -->
+ <skip />
<string name="edit_accessibility_shortcut_menu_button" msgid="8885752738733772935">"Edita les dreceres"</string>
<string name="cancel_accessibility_shortcut_menu_button" msgid="1817413122335452474">"Cancel·la"</string>
<string name="disable_accessibility_shortcut" msgid="5806091378745232383">"Desactiva la drecera"</string>
@@ -1853,8 +1859,7 @@
<string name="default_notification_channel_label" msgid="3697928973567217330">"Sense classificar"</string>
<string name="importance_from_user" msgid="2782756722448800447">"Has definit la importància d\'aquestes notificacions."</string>
<string name="importance_from_person" msgid="4235804979664465383">"Aquest missatge és important per les persones implicades."</string>
- <!-- no translation found for notification_history_title_placeholder (7748630986182249599) -->
- <skip />
+ <string name="notification_history_title_placeholder" msgid="7748630986182249599">"Notificació d\'aplicació personalitzada"</string>
<string name="user_creation_account_exists" msgid="2239146360099708035">"Concedeixes permís a <xliff:g id="APP">%1$s</xliff:g> per crear un usuari amb el compte <xliff:g id="ACCOUNT">%2$s</xliff:g>? (Ja hi ha un usuari amb aquest compte.)"</string>
<string name="user_creation_adding" msgid="7305185499667958364">"Concedeixes permís a <xliff:g id="APP">%1$s</xliff:g> per crear un usuari amb el compte <xliff:g id="ACCOUNT">%2$s</xliff:g>?"</string>
<string name="language_selection_title" msgid="52674936078683285">"Afegeix un idioma"</string>
@@ -2028,14 +2033,29 @@
<string name="as_app_forced_to_restricted_bucket" msgid="8233871289353898964">"<xliff:g id="PACKAGE_NAME">%1$s</xliff:g> s\'ha transferit al segment RESTRINGIT"</string>
<string name="resolver_personal_tab" msgid="2051260504014442073">"Personal"</string>
<string name="resolver_work_tab" msgid="2690019516263167035">"Feina"</string>
+ <!-- no translation found for resolver_personal_tab_accessibility (5739524949153091224) -->
+ <skip />
+ <!-- no translation found for resolver_work_tab_accessibility (4753168230363802734) -->
+ <skip />
<string name="resolver_cant_share_with_work_apps" msgid="7539495559434146897">"No es pot compartir amb les aplicacions de treball"</string>
<string name="resolver_cant_share_with_personal_apps" msgid="8020581735267157241">"No es pot compartir amb les aplicacions personals"</string>
- <string name="resolver_cant_share_cross_profile_explanation" msgid="3536237105241882679">"L\'administrador de TI ha bloquejat la compartició entre aplicacions personals i de treball"</string>
- <string name="resolver_turn_on_work_apps" msgid="8987359079870455469">"Activa les aplicacions de treball"</string>
- <string name="resolver_turn_on_work_apps_explanation" msgid="6322467455509618928">"Activa les aplicacions de treball per accedir a aquestes aplicacions i als contactes de feina"</string>
+ <!-- no translation found for resolver_cant_share_cross_profile_explanation (5556640604460901386) -->
+ <skip />
+ <!-- no translation found for resolver_cant_access_work_apps (375634344111233790) -->
+ <skip />
+ <!-- no translation found for resolver_cant_access_work_apps_explanation (3958762224516867388) -->
+ <skip />
+ <!-- no translation found for resolver_cant_access_personal_apps (1953215925406474177) -->
+ <skip />
+ <!-- no translation found for resolver_cant_access_personal_apps_explanation (1725572276741281136) -->
+ <skip />
+ <!-- no translation found for resolver_turn_on_work_apps_share (619263911204978175) -->
+ <skip />
+ <!-- no translation found for resolver_turn_on_work_apps_view (3073389230905543680) -->
+ <skip />
<string name="resolver_no_apps_available" msgid="7710339903040989654">"No hi ha cap aplicació disponible"</string>
- <string name="resolver_no_apps_available_explanation" msgid="4662694431121196560">"No hem trobat cap aplicació"</string>
- <string name="resolver_switch_on_work" msgid="8294542702883688533">"Activa el perfil de treball"</string>
+ <!-- no translation found for resolver_switch_on_work (2873009160846966379) -->
+ <skip />
<string name="permlab_accessCallAudio" msgid="1682957511874097664">"Gravar o reproduir àudio en trucades"</string>
<string name="permdesc_accessCallAudio" msgid="8448360894684277823">"Permet que l\'aplicació gravi o reprodueixi àudio en trucades si està assignada com a aplicació de marcador predeterminada."</string>
</resources>
diff --git a/core/res/res/values-cs/strings.xml b/core/res/res/values-cs/strings.xml
index 8594e1f102b6..f4b02f1cace4 100644
--- a/core/res/res/values-cs/strings.xml
+++ b/core/res/res/values-cs/strings.xml
@@ -255,10 +255,8 @@
<item quantity="other">Snímek obrazovky pro zprávu o chybě bude pořízen za <xliff:g id="NUMBER_1">%d</xliff:g> sekund.</item>
<item quantity="one">Snímek obrazovky pro zprávu o chybě bude pořízen za <xliff:g id="NUMBER_0">%d</xliff:g> sekundu.</item>
</plurals>
- <!-- no translation found for bugreport_screenshot_success_toast (7986095104151473745) -->
- <skip />
- <!-- no translation found for bugreport_screenshot_failure_toast (6736320861311294294) -->
- <skip />
+ <string name="bugreport_screenshot_success_toast" msgid="7986095104151473745">"Se zprávou o chybě byl pořízen snímek obrazovky"</string>
+ <string name="bugreport_screenshot_failure_toast" msgid="6736320861311294294">"Pořízení snímku obrazovky se zprávou o chybě se nezdařilo"</string>
<string name="global_action_toggle_silent_mode" msgid="8464352592860372188">"Tichý režim"</string>
<string name="global_action_silent_mode_on_status" msgid="2371892537738632013">"Zvuk je VYPNUTÝ."</string>
<string name="global_action_silent_mode_off_status" msgid="6608006545950920042">"Zvuk je zapnutý"</string>
@@ -460,9 +458,11 @@
<string name="permdesc_acceptHandovers" msgid="7129026180128626870">"Umožňuje aplikace pokračovat v hovoru, který byl zahájen v jiné aplikaci."</string>
<string name="permlab_readPhoneNumbers" msgid="5668704794723365628">"přístup k telefonním číslům"</string>
<string name="permdesc_readPhoneNumbers" msgid="7368652482818338871">"Umožňuje aplikaci přístup k telefonním číslům v zařízení."</string>
+ <string name="permlab_wakeLock" product="automotive" msgid="1904736682319375676">"ponechání zapnuté obrazovky auta"</string>
<string name="permlab_wakeLock" product="tablet" msgid="1527660973931694000">"bránění přechodu tabletu do režimu spánku"</string>
<string name="permlab_wakeLock" product="tv" msgid="2856941418123343518">"bránění přechodu zařízení Android TV do režimu spánku"</string>
<string name="permlab_wakeLock" product="default" msgid="569409726861695115">"bránění přechodu telefonu do režimu spánku"</string>
+ <string name="permdesc_wakeLock" product="automotive" msgid="5995045369683254571">"Umožňuje aplikaci nechat obrazovku auta zapnutou."</string>
<string name="permdesc_wakeLock" product="tablet" msgid="2441742939101526277">"Umožňuje aplikaci zabránit přechodu tabletu do režimu spánku."</string>
<string name="permdesc_wakeLock" product="tv" msgid="2329298966735118796">"Umožňuje aplikaci zabránit přechodu zařízení Android TV do režimu spánku."</string>
<string name="permdesc_wakeLock" product="default" msgid="3689523792074007163">"Umožňuje aplikaci zabránit přechodu telefonu do režimu spánku."</string>
@@ -1675,6 +1675,12 @@
<string name="safe_media_volume_warning" product="default" msgid="3751676824423049994">"Zvýšit hlasitost nad doporučenou úroveň?\n\nDlouhodobý poslech hlasitého zvuku může poškodit sluch."</string>
<string name="accessibility_shortcut_warning_dialog_title" msgid="4017995837692622933">"Použít zkratku přístupnosti?"</string>
<string name="accessibility_shortcut_toogle_warning" msgid="4161716521310929544">"Když je tato zkratka zapnutá, můžete funkci přístupnosti spustit tím, že na tři sekundy podržíte obě tlačítka hlasitosti."</string>
+ <!-- no translation found for accessibility_select_shortcut_menu_title (7310194076629867377) -->
+ <skip />
+ <!-- no translation found for accessibility_edit_shortcut_menu_button_title (6096484087245145325) -->
+ <skip />
+ <!-- no translation found for accessibility_edit_shortcut_menu_volume_title (4849108668454490699) -->
+ <skip />
<string name="edit_accessibility_shortcut_menu_button" msgid="8885752738733772935">"Upravit zkratky"</string>
<string name="cancel_accessibility_shortcut_menu_button" msgid="1817413122335452474">"Zrušit"</string>
<string name="disable_accessibility_shortcut" msgid="5806091378745232383">"Vypnout zkratku"</string>
@@ -1917,8 +1923,7 @@
<string name="default_notification_channel_label" msgid="3697928973567217330">"Neklasifikováno"</string>
<string name="importance_from_user" msgid="2782756722448800447">"Důležitost oznámení určujete vy."</string>
<string name="importance_from_person" msgid="4235804979664465383">"Tato zpráva je důležitá kvůli lidem zapojeným do konverzace."</string>
- <!-- no translation found for notification_history_title_placeholder (7748630986182249599) -->
- <skip />
+ <string name="notification_history_title_placeholder" msgid="7748630986182249599">"Vlastní oznámení aplikace"</string>
<string name="user_creation_account_exists" msgid="2239146360099708035">"Povolit aplikaci <xliff:g id="APP">%1$s</xliff:g> vytvořit nového uživatele s účtem <xliff:g id="ACCOUNT">%2$s</xliff:g>? (Uživatel s tímto účtem již existuje.)"</string>
<string name="user_creation_adding" msgid="7305185499667958364">"Povolit aplikaci <xliff:g id="APP">%1$s</xliff:g> vytvořit nového uživatele s účtem <xliff:g id="ACCOUNT">%2$s</xliff:g>?"</string>
<string name="language_selection_title" msgid="52674936078683285">"Přidat jazyk"</string>
@@ -2096,14 +2101,29 @@
<string name="as_app_forced_to_restricted_bucket" msgid="8233871289353898964">"Balíček <xliff:g id="PACKAGE_NAME">%1$s</xliff:g> byl vložen do sekce OMEZENO"</string>
<string name="resolver_personal_tab" msgid="2051260504014442073">"Osobní"</string>
<string name="resolver_work_tab" msgid="2690019516263167035">"Pracovní"</string>
+ <!-- no translation found for resolver_personal_tab_accessibility (5739524949153091224) -->
+ <skip />
+ <!-- no translation found for resolver_work_tab_accessibility (4753168230363802734) -->
+ <skip />
<string name="resolver_cant_share_with_work_apps" msgid="7539495559434146897">"Sdílení s pracovními aplikacemi je zakázáno"</string>
<string name="resolver_cant_share_with_personal_apps" msgid="8020581735267157241">"Sdílení s osobními aplikacemi je zakázáno"</string>
- <string name="resolver_cant_share_cross_profile_explanation" msgid="3536237105241882679">"Sdílení mezi osobními a pracovními aplikacemi zablokoval váš administrátor IT"</string>
- <string name="resolver_turn_on_work_apps" msgid="8987359079870455469">"Zapnout pracovní aplikace"</string>
- <string name="resolver_turn_on_work_apps_explanation" msgid="6322467455509618928">"Zapnutím pracovních aplikací získáte přístup k pracovním aplikacím a kontaktům"</string>
+ <!-- no translation found for resolver_cant_share_cross_profile_explanation (5556640604460901386) -->
+ <skip />
+ <!-- no translation found for resolver_cant_access_work_apps (375634344111233790) -->
+ <skip />
+ <!-- no translation found for resolver_cant_access_work_apps_explanation (3958762224516867388) -->
+ <skip />
+ <!-- no translation found for resolver_cant_access_personal_apps (1953215925406474177) -->
+ <skip />
+ <!-- no translation found for resolver_cant_access_personal_apps_explanation (1725572276741281136) -->
+ <skip />
+ <!-- no translation found for resolver_turn_on_work_apps_share (619263911204978175) -->
+ <skip />
+ <!-- no translation found for resolver_turn_on_work_apps_view (3073389230905543680) -->
+ <skip />
<string name="resolver_no_apps_available" msgid="7710339903040989654">"Žádné aplikace k dispozici"</string>
- <string name="resolver_no_apps_available_explanation" msgid="4662694431121196560">"Nenalezli jsme žádné aplikace"</string>
- <string name="resolver_switch_on_work" msgid="8294542702883688533">"Zapnout práci"</string>
+ <!-- no translation found for resolver_switch_on_work (2873009160846966379) -->
+ <skip />
<string name="permlab_accessCallAudio" msgid="1682957511874097664">"Záznam a přehrávání zvuků při telefonických hovorech"</string>
<string name="permdesc_accessCallAudio" msgid="8448360894684277823">"Pokud aplikace bude mít toto oprávnění a bude vybrána jako výchozí aplikace pro vytáčení, bude při telefonických hovorech moci přehrávat a zaznamenávat zvuky."</string>
</resources>
diff --git a/core/res/res/values-da/strings.xml b/core/res/res/values-da/strings.xml
index 617bc880b7fc..47fd69d9e6ff 100644
--- a/core/res/res/values-da/strings.xml
+++ b/core/res/res/values-da/strings.xml
@@ -249,10 +249,8 @@
<item quantity="one">Der tages et screenshot til fejlrapporten om <xliff:g id="NUMBER_1">%d</xliff:g> sekund.</item>
<item quantity="other">Der tages et screenshot til fejlrapporten om <xliff:g id="NUMBER_1">%d</xliff:g> sekunder.</item>
</plurals>
- <!-- no translation found for bugreport_screenshot_success_toast (7986095104151473745) -->
- <skip />
- <!-- no translation found for bugreport_screenshot_failure_toast (6736320861311294294) -->
- <skip />
+ <string name="bugreport_screenshot_success_toast" msgid="7986095104151473745">"Der er taget et screenshot af fejlrapporten"</string>
+ <string name="bugreport_screenshot_failure_toast" msgid="6736320861311294294">"Der kunne ikke tages et screenshot af fejlrapporten"</string>
<string name="global_action_toggle_silent_mode" msgid="8464352592860372188">"Lydløs"</string>
<string name="global_action_silent_mode_on_status" msgid="2371892537738632013">"Lyden er slået FRA"</string>
<string name="global_action_silent_mode_off_status" msgid="6608006545950920042">"Lyden er TIL"</string>
@@ -454,9 +452,11 @@
<string name="permdesc_acceptHandovers" msgid="7129026180128626870">"Tillader, at appen fortsætter et opkald, der blev startet i en anden app."</string>
<string name="permlab_readPhoneNumbers" msgid="5668704794723365628">"læse telefonnumre"</string>
<string name="permdesc_readPhoneNumbers" msgid="7368652482818338871">"Tillader, at appen får adgang til telefonnumrene på denne enhed."</string>
+ <string name="permlab_wakeLock" product="automotive" msgid="1904736682319375676">"hold bilens skærm tændt"</string>
<string name="permlab_wakeLock" product="tablet" msgid="1527660973931694000">"afholde tabletcomputeren fra at gå i dvale"</string>
<string name="permlab_wakeLock" product="tv" msgid="2856941418123343518">"undgå, at din Android TV-enhed ikke går i dvale"</string>
<string name="permlab_wakeLock" product="default" msgid="569409726861695115">"afholde telefonen fra at gå i dvale"</string>
+ <string name="permdesc_wakeLock" product="automotive" msgid="5995045369683254571">"Tillader, at appen holder bilens skærm tændt."</string>
<string name="permdesc_wakeLock" product="tablet" msgid="2441742939101526277">"Tillader, at appen kan forhindre tabletten i at gå i dvale."</string>
<string name="permdesc_wakeLock" product="tv" msgid="2329298966735118796">"Tillader, at appen kan forhindre din Android TV-enhed i at gå i dvale."</string>
<string name="permdesc_wakeLock" product="default" msgid="3689523792074007163">"Tillader, at appen kan forhindre, at telefonen går i dvale."</string>
@@ -1631,6 +1631,12 @@
<string name="safe_media_volume_warning" product="default" msgid="3751676824423049994">"Vil du skrue højere op end det anbefalede lydstyrkeniveau?\n\nDu kan skade hørelsen ved at lytte til meget høj musik over længere tid."</string>
<string name="accessibility_shortcut_warning_dialog_title" msgid="4017995837692622933">"Vil du bruge genvejen til Hjælpefunktioner?"</string>
<string name="accessibility_shortcut_toogle_warning" msgid="4161716521310929544">"Når genvejen er aktiveret, kan du starte en hjælpefunktion ved at trykke på begge lydstyrkeknapper i tre sekunder."</string>
+ <!-- no translation found for accessibility_select_shortcut_menu_title (7310194076629867377) -->
+ <skip />
+ <!-- no translation found for accessibility_edit_shortcut_menu_button_title (6096484087245145325) -->
+ <skip />
+ <!-- no translation found for accessibility_edit_shortcut_menu_volume_title (4849108668454490699) -->
+ <skip />
<string name="edit_accessibility_shortcut_menu_button" msgid="8885752738733772935">"Rediger genveje"</string>
<string name="cancel_accessibility_shortcut_menu_button" msgid="1817413122335452474">"Annuller"</string>
<string name="disable_accessibility_shortcut" msgid="5806091378745232383">"Deaktiver genvej"</string>
@@ -1853,8 +1859,7 @@
<string name="default_notification_channel_label" msgid="3697928973567217330">"Uden kategori"</string>
<string name="importance_from_user" msgid="2782756722448800447">"Du angiver, hvor vigtige disse notifikationer er."</string>
<string name="importance_from_person" msgid="4235804979664465383">"Dette er vigtigt på grund af de personer, det handler om."</string>
- <!-- no translation found for notification_history_title_placeholder (7748630986182249599) -->
- <skip />
+ <string name="notification_history_title_placeholder" msgid="7748630986182249599">"Tilpasset appnotifikation"</string>
<string name="user_creation_account_exists" msgid="2239146360099708035">"Vil du give <xliff:g id="APP">%1$s</xliff:g> tilladelse til at oprette en ny bruger med <xliff:g id="ACCOUNT">%2$s</xliff:g> (der findes allerede en bruger med denne konto)?"</string>
<string name="user_creation_adding" msgid="7305185499667958364">"Vil du give <xliff:g id="APP">%1$s</xliff:g> tilladelse til at oprette en nye bruger med <xliff:g id="ACCOUNT">%2$s</xliff:g>?"</string>
<string name="language_selection_title" msgid="52674936078683285">"Tilføj et sprog"</string>
@@ -2028,14 +2033,29 @@
<string name="as_app_forced_to_restricted_bucket" msgid="8233871289353898964">"<xliff:g id="PACKAGE_NAME">%1$s</xliff:g> er blevet placeret i samlingen BEGRÆNSET"</string>
<string name="resolver_personal_tab" msgid="2051260504014442073">"Personlig"</string>
<string name="resolver_work_tab" msgid="2690019516263167035">"Arbejde"</string>
+ <!-- no translation found for resolver_personal_tab_accessibility (5739524949153091224) -->
+ <skip />
+ <!-- no translation found for resolver_work_tab_accessibility (4753168230363802734) -->
+ <skip />
<string name="resolver_cant_share_with_work_apps" msgid="7539495559434146897">"Der kan ikke deles med arbejdsapps"</string>
<string name="resolver_cant_share_with_personal_apps" msgid="8020581735267157241">"Der kan ikke deles med personlige apps"</string>
- <string name="resolver_cant_share_cross_profile_explanation" msgid="3536237105241882679">"Din it-administrator har blokeret deling mellem personlige apps og arbejdsapps"</string>
- <string name="resolver_turn_on_work_apps" msgid="8987359079870455469">"Aktivér arbejdsapps"</string>
- <string name="resolver_turn_on_work_apps_explanation" msgid="6322467455509618928">"Aktivér arbejdsapps for at få adgang til arbejdsapps og -kontakter"</string>
+ <!-- no translation found for resolver_cant_share_cross_profile_explanation (5556640604460901386) -->
+ <skip />
+ <!-- no translation found for resolver_cant_access_work_apps (375634344111233790) -->
+ <skip />
+ <!-- no translation found for resolver_cant_access_work_apps_explanation (3958762224516867388) -->
+ <skip />
+ <!-- no translation found for resolver_cant_access_personal_apps (1953215925406474177) -->
+ <skip />
+ <!-- no translation found for resolver_cant_access_personal_apps_explanation (1725572276741281136) -->
+ <skip />
+ <!-- no translation found for resolver_turn_on_work_apps_share (619263911204978175) -->
+ <skip />
+ <!-- no translation found for resolver_turn_on_work_apps_view (3073389230905543680) -->
+ <skip />
<string name="resolver_no_apps_available" msgid="7710339903040989654">"Ingen tilgængelige apps"</string>
- <string name="resolver_no_apps_available_explanation" msgid="4662694431121196560">"Vi kunne ikke finde nogen apps"</string>
- <string name="resolver_switch_on_work" msgid="8294542702883688533">"Aktivér arbejdsprofil"</string>
+ <!-- no translation found for resolver_switch_on_work (2873009160846966379) -->
+ <skip />
<string name="permlab_accessCallAudio" msgid="1682957511874097664">"Optage eller afspille lyd i telefonopkald"</string>
<string name="permdesc_accessCallAudio" msgid="8448360894684277823">"Tillader, at denne app kan optage og afspille lyd i telefonopkald, når den er angivet som standardapp til opkald."</string>
</resources>
diff --git a/core/res/res/values-de/strings.xml b/core/res/res/values-de/strings.xml
index f211b4019eaf..d61d961eff58 100644
--- a/core/res/res/values-de/strings.xml
+++ b/core/res/res/values-de/strings.xml
@@ -249,10 +249,8 @@
<item quantity="other">Screenshot für den Fehlerbericht wird in <xliff:g id="NUMBER_1">%d</xliff:g> Sekunden aufgenommen.</item>
<item quantity="one">Screenshot für den Fehlerbericht wird in <xliff:g id="NUMBER_0">%d</xliff:g> Sekunde aufgenommen.</item>
</plurals>
- <!-- no translation found for bugreport_screenshot_success_toast (7986095104151473745) -->
- <skip />
- <!-- no translation found for bugreport_screenshot_failure_toast (6736320861311294294) -->
- <skip />
+ <string name="bugreport_screenshot_success_toast" msgid="7986095104151473745">"Screenshot mit Fehlerbericht erstellt"</string>
+ <string name="bugreport_screenshot_failure_toast" msgid="6736320861311294294">"Fehler beim Erstellen eines Screenshots mit Fehlerbericht"</string>
<string name="global_action_toggle_silent_mode" msgid="8464352592860372188">"Lautlos-Modus"</string>
<string name="global_action_silent_mode_on_status" msgid="2371892537738632013">"Ton ist AUS."</string>
<string name="global_action_silent_mode_off_status" msgid="6608006545950920042">"Ton ist AN."</string>
@@ -454,9 +452,11 @@
<string name="permdesc_acceptHandovers" msgid="7129026180128626870">"Ermöglicht der App, einen Anruf weiterzuführen, der in einer anderen App begonnen wurde."</string>
<string name="permlab_readPhoneNumbers" msgid="5668704794723365628">"Telefonnummern vorlesen"</string>
<string name="permdesc_readPhoneNumbers" msgid="7368652482818338871">"Ermöglicht der App, auf die Telefonnummern auf dem Gerät zuzugreifen."</string>
+ <string name="permlab_wakeLock" product="automotive" msgid="1904736682319375676">"Autodisplay eingeschaltet lassen"</string>
<string name="permlab_wakeLock" product="tablet" msgid="1527660973931694000">"Ruhezustand des Tablets deaktivieren"</string>
<string name="permlab_wakeLock" product="tv" msgid="2856941418123343518">"Android TV-Gerät daran hindern, in den Ruhemodus zu wechseln"</string>
<string name="permlab_wakeLock" product="default" msgid="569409726861695115">"Ruhezustand deaktivieren"</string>
+ <string name="permdesc_wakeLock" product="automotive" msgid="5995045369683254571">"Ermöglicht der App, das Autodisplay eingeschaltet zu lassen."</string>
<string name="permdesc_wakeLock" product="tablet" msgid="2441742939101526277">"Ermöglicht der App, den Ruhezustand des Tablets zu deaktivieren"</string>
<string name="permdesc_wakeLock" product="tv" msgid="2329298966735118796">"Ermöglicht der App zu verhindern, dass das Android TV-Gerät in den Ruhemodus wechselt."</string>
<string name="permdesc_wakeLock" product="default" msgid="3689523792074007163">"Ermöglicht der App, den Ruhezustand des Telefons zu deaktivieren"</string>
@@ -1631,6 +1631,12 @@
<string name="safe_media_volume_warning" product="default" msgid="3751676824423049994">"Lautstärke über den Schwellenwert anheben?\n\nWenn du über einen längeren Zeitraum Musik in hoher Lautstärke hörst, kann dies dein Gehör schädigen."</string>
<string name="accessibility_shortcut_warning_dialog_title" msgid="4017995837692622933">"Verknüpfung für Bedienungshilfen verwenden?"</string>
<string name="accessibility_shortcut_toogle_warning" msgid="4161716521310929544">"Wenn die Verknüpfung aktiviert ist, kannst du die beiden Lautstärketasten drei Sekunden lang gedrückt halten, um eine Bedienungshilfe zu starten."</string>
+ <!-- no translation found for accessibility_select_shortcut_menu_title (7310194076629867377) -->
+ <skip />
+ <!-- no translation found for accessibility_edit_shortcut_menu_button_title (6096484087245145325) -->
+ <skip />
+ <!-- no translation found for accessibility_edit_shortcut_menu_volume_title (4849108668454490699) -->
+ <skip />
<string name="edit_accessibility_shortcut_menu_button" msgid="8885752738733772935">"Verknüpfungen bearbeiten"</string>
<string name="cancel_accessibility_shortcut_menu_button" msgid="1817413122335452474">"Abbrechen"</string>
<string name="disable_accessibility_shortcut" msgid="5806091378745232383">"Verknüpfung deaktivieren"</string>
@@ -2028,14 +2034,29 @@
<string name="as_app_forced_to_restricted_bucket" msgid="8233871289353898964">"<xliff:g id="PACKAGE_NAME">%1$s</xliff:g> wurde in den BESCHRÄNKT-Bucket gelegt"</string>
<string name="resolver_personal_tab" msgid="2051260504014442073">"Privat"</string>
<string name="resolver_work_tab" msgid="2690019516263167035">"Geschäftlich"</string>
+ <!-- no translation found for resolver_personal_tab_accessibility (5739524949153091224) -->
+ <skip />
+ <!-- no translation found for resolver_work_tab_accessibility (4753168230363802734) -->
+ <skip />
<string name="resolver_cant_share_with_work_apps" msgid="7539495559434146897">"Teilen mit geschäftlichen Apps nicht möglich"</string>
<string name="resolver_cant_share_with_personal_apps" msgid="8020581735267157241">"Teilen mit privaten Apps nicht möglich"</string>
- <string name="resolver_cant_share_cross_profile_explanation" msgid="3536237105241882679">"Dein IT-Administrator lässt das Teilen zwischen privaten und geschäftlichen Apps nicht zu"</string>
- <string name="resolver_turn_on_work_apps" msgid="8987359079870455469">"Geschäftliche Apps aktivieren"</string>
- <string name="resolver_turn_on_work_apps_explanation" msgid="6322467455509618928">"Für Zugriff auf geschäftliche Apps und Kontakte geschäftliche Apps aktivieren"</string>
+ <!-- no translation found for resolver_cant_share_cross_profile_explanation (5556640604460901386) -->
+ <skip />
+ <!-- no translation found for resolver_cant_access_work_apps (375634344111233790) -->
+ <skip />
+ <!-- no translation found for resolver_cant_access_work_apps_explanation (3958762224516867388) -->
+ <skip />
+ <!-- no translation found for resolver_cant_access_personal_apps (1953215925406474177) -->
+ <skip />
+ <!-- no translation found for resolver_cant_access_personal_apps_explanation (1725572276741281136) -->
+ <skip />
+ <!-- no translation found for resolver_turn_on_work_apps_share (619263911204978175) -->
+ <skip />
+ <!-- no translation found for resolver_turn_on_work_apps_view (3073389230905543680) -->
+ <skip />
<string name="resolver_no_apps_available" msgid="7710339903040989654">"Keine Apps verfügbar"</string>
- <string name="resolver_no_apps_available_explanation" msgid="4662694431121196560">"Keine Apps gefunden"</string>
- <string name="resolver_switch_on_work" msgid="8294542702883688533">"Arbeitsprofil aktivieren"</string>
+ <!-- no translation found for resolver_switch_on_work (2873009160846966379) -->
+ <skip />
<string name="permlab_accessCallAudio" msgid="1682957511874097664">"Audio bei Telefonanrufen aufnehmen oder wiedergeben"</string>
<string name="permdesc_accessCallAudio" msgid="8448360894684277823">"Ermöglicht dieser App das Aufnehmen und Wiedergeben von Audio bei Telefonanrufen, wenn sie als Standard-Telefon-App festgelegt wurde."</string>
</resources>
diff --git a/core/res/res/values-el/strings.xml b/core/res/res/values-el/strings.xml
index c915bba83f3d..16daec8bf7e7 100644
--- a/core/res/res/values-el/strings.xml
+++ b/core/res/res/values-el/strings.xml
@@ -452,9 +452,11 @@
<string name="permdesc_acceptHandovers" msgid="7129026180128626870">"Επιτρέπει στην εφαρμογή να συνεχίσει μια κλήση η οποία ξεκίνησε σε άλλη εφαρμογή."</string>
<string name="permlab_readPhoneNumbers" msgid="5668704794723365628">"ανάγνωση αριθμών τηλεφώνου"</string>
<string name="permdesc_readPhoneNumbers" msgid="7368652482818338871">"Επιτρέπει στην εφαρμογή να αποκτήσει πρόσβαση στους αριθμούς τηλεφώνου της συσκευής"</string>
+ <string name="permlab_wakeLock" product="automotive" msgid="1904736682319375676">"διατήρηση ενεργοποίησης οθόνης αυτοκινήτου"</string>
<string name="permlab_wakeLock" product="tablet" msgid="1527660973931694000">"αποτρέπει την μετάβαση του tablet σε κατάσταση αδράνειας"</string>
<string name="permlab_wakeLock" product="tv" msgid="2856941418123343518">"απαγόρευση μετάβασης της συσκευής Android TV σε κατάσταση αδράνειας"</string>
<string name="permlab_wakeLock" product="default" msgid="569409726861695115">"αποτρέπει το τηλεφώνο να μεταβεί σε κατάσταση αδράνειας"</string>
+ <string name="permdesc_wakeLock" product="automotive" msgid="5995045369683254571">"Επιτρέπει στην εφαρμογή να διατηρεί την οθόνη του αυτοκινήτου ενεργοποιημένη."</string>
<string name="permdesc_wakeLock" product="tablet" msgid="2441742939101526277">"Επιτρέπει στην εφαρμογή την παρεμπόδιση της μετάβασης του tablet σε κατάσταση αδράνειας."</string>
<string name="permdesc_wakeLock" product="tv" msgid="2329298966735118796">"Επιτρέπει στην εφαρμογή να εμποδίζει τη μετάβαση της συσκευής Android TV σε κατάσταση αδράνειας."</string>
<string name="permdesc_wakeLock" product="default" msgid="3689523792074007163">"Επιτρέπει στην εφαρμογή την παρεμπόδιση της μετάβασης του τηλεφώνου σε κατάσταση αδράνειας."</string>
@@ -1629,6 +1631,12 @@
<string name="safe_media_volume_warning" product="default" msgid="3751676824423049994">"Αυξάνετε την ένταση ήχου πάνω από το επίπεδο ασφαλείας;\n\nΑν ακούτε μουσική σε υψηλή ένταση για μεγάλο χρονικό διάστημα ενδέχεται να προκληθεί βλάβη στην ακοή σας."</string>
<string name="accessibility_shortcut_warning_dialog_title" msgid="4017995837692622933">"Να χρησιμοποιείται η συντόμευση προσβασιμότητας;"</string>
<string name="accessibility_shortcut_toogle_warning" msgid="4161716521310929544">"Όταν η συντόμευση είναι ενεργοποιημένη, το πάτημα και των δύο κουμπιών έντασης ήχου για 3 δευτερόλεπτα θα ξεκινήσει μια λειτουργία προσβασιμότητας."</string>
+ <!-- no translation found for accessibility_select_shortcut_menu_title (7310194076629867377) -->
+ <skip />
+ <!-- no translation found for accessibility_edit_shortcut_menu_button_title (6096484087245145325) -->
+ <skip />
+ <!-- no translation found for accessibility_edit_shortcut_menu_volume_title (4849108668454490699) -->
+ <skip />
<string name="edit_accessibility_shortcut_menu_button" msgid="8885752738733772935">"Επεξεργασία συντομεύσεων"</string>
<string name="cancel_accessibility_shortcut_menu_button" msgid="1817413122335452474">"Άκυρο"</string>
<string name="disable_accessibility_shortcut" msgid="5806091378745232383">"Απενεργοποίηση συντόμευσης"</string>
@@ -1851,8 +1859,7 @@
<string name="default_notification_channel_label" msgid="3697928973567217330">"Μη κατηγοριοποιημένο"</string>
<string name="importance_from_user" msgid="2782756722448800447">"Μπορείτε να ρυθμίσετε τη βαρύτητα αυτών των ειδοποιήσεων."</string>
<string name="importance_from_person" msgid="4235804979664465383">"Αυτό είναι σημαντικό λόγω των ατόμων που συμμετέχουν."</string>
- <!-- no translation found for notification_history_title_placeholder (7748630986182249599) -->
- <skip />
+ <string name="notification_history_title_placeholder" msgid="7748630986182249599">"Προσαρμοσμένη ειδοποίηση εφαρμογής"</string>
<string name="user_creation_account_exists" msgid="2239146360099708035">"Επιτρέπετε στην εφαρμογή <xliff:g id="APP">%1$s</xliff:g> να δημιουργήσει έναν νέο χρήστη με τον λογαριασμό <xliff:g id="ACCOUNT">%2$s</xliff:g> (υπάρχει ήδη χρήστης με αυτόν τον λογαριασμό);"</string>
<string name="user_creation_adding" msgid="7305185499667958364">"Επιτρέπετε στην εφαρμογή <xliff:g id="APP">%1$s</xliff:g> να δημιουργήσει έναν νέο χρήστη με τον λογαριασμό <xliff:g id="ACCOUNT">%2$s</xliff:g>;"</string>
<string name="language_selection_title" msgid="52674936078683285">"Προσθήκη γλώσσας"</string>
@@ -2026,14 +2033,29 @@
<string name="as_app_forced_to_restricted_bucket" msgid="8233871289353898964">"Το πακέτο <xliff:g id="PACKAGE_NAME">%1$s</xliff:g> τοποθετήθηκε στον κάδο ΠΕΡΙΟΡΙΣΜΕΝΗΣ ΠΡΟΣΒΑΣΗΣ."</string>
<string name="resolver_personal_tab" msgid="2051260504014442073">"Προσωπικό"</string>
<string name="resolver_work_tab" msgid="2690019516263167035">"Εργασία"</string>
+ <!-- no translation found for resolver_personal_tab_accessibility (5739524949153091224) -->
+ <skip />
+ <!-- no translation found for resolver_work_tab_accessibility (4753168230363802734) -->
+ <skip />
<string name="resolver_cant_share_with_work_apps" msgid="7539495559434146897">"Δεν είναι δυνατή η κοινοποίηση σε εφαρμογές εργασιών"</string>
<string name="resolver_cant_share_with_personal_apps" msgid="8020581735267157241">"Δεν είναι δυνατή η κοινοποίηση σε προσωπικές εφαρμογές"</string>
- <string name="resolver_cant_share_cross_profile_explanation" msgid="3536237105241882679">"Ο διαχειριστής IT απέκλεισε την κοινοποίηση μεταξύ των προσωπικών εφαρμογών και των εφαρμογών εργασιών σας"</string>
- <string name="resolver_turn_on_work_apps" msgid="8987359079870455469">"Ενεργοποίηση εφαρμογών εργασιών"</string>
- <string name="resolver_turn_on_work_apps_explanation" msgid="6322467455509618928">"Ενεργοποίηση εφαρμογών εργασιών για πρόσβαση στις εφαρμογές εργασιών και τις επαφές"</string>
+ <!-- no translation found for resolver_cant_share_cross_profile_explanation (5556640604460901386) -->
+ <skip />
+ <!-- no translation found for resolver_cant_access_work_apps (375634344111233790) -->
+ <skip />
+ <!-- no translation found for resolver_cant_access_work_apps_explanation (3958762224516867388) -->
+ <skip />
+ <!-- no translation found for resolver_cant_access_personal_apps (1953215925406474177) -->
+ <skip />
+ <!-- no translation found for resolver_cant_access_personal_apps_explanation (1725572276741281136) -->
+ <skip />
+ <!-- no translation found for resolver_turn_on_work_apps_share (619263911204978175) -->
+ <skip />
+ <!-- no translation found for resolver_turn_on_work_apps_view (3073389230905543680) -->
+ <skip />
<string name="resolver_no_apps_available" msgid="7710339903040989654">"Δεν υπάρχουν διαθέσιμες εφαρμογές"</string>
- <string name="resolver_no_apps_available_explanation" msgid="4662694431121196560">"Δεν ήταν δυνατή η εύρεση εφαρμογών"</string>
- <string name="resolver_switch_on_work" msgid="8294542702883688533">"Διακόπτης ενεργοποίησης προφίλ εργασίας"</string>
+ <!-- no translation found for resolver_switch_on_work (2873009160846966379) -->
+ <skip />
<string name="permlab_accessCallAudio" msgid="1682957511874097664">"Εγγραφή ή αναπαραγωγή ήχου σε τηλεφωνικές κλήσεις"</string>
<string name="permdesc_accessCallAudio" msgid="8448360894684277823">"Επιτρέπει σε αυτήν την εφαρμογή, όταν ορίζεται ως προεπιλεγμένη εφαρμογή κλήσης, να εγγράφει ή να αναπαράγει ήχο σε τηλεφωνικές κλήσεις."</string>
</resources>
diff --git a/core/res/res/values-en-rAU/strings.xml b/core/res/res/values-en-rAU/strings.xml
index c5259fdaebf0..c8e03c6e42b8 100644
--- a/core/res/res/values-en-rAU/strings.xml
+++ b/core/res/res/values-en-rAU/strings.xml
@@ -452,9 +452,11 @@
<string name="permdesc_acceptHandovers" msgid="7129026180128626870">"Allows the app to continue a call which was started in another app."</string>
<string name="permlab_readPhoneNumbers" msgid="5668704794723365628">"read phone numbers"</string>
<string name="permdesc_readPhoneNumbers" msgid="7368652482818338871">"Allows the app to access the phone numbers of the device."</string>
+ <string name="permlab_wakeLock" product="automotive" msgid="1904736682319375676">"keep car screen turned on"</string>
<string name="permlab_wakeLock" product="tablet" msgid="1527660973931694000">"prevent tablet from sleeping"</string>
<string name="permlab_wakeLock" product="tv" msgid="2856941418123343518">"prevent your Android TV device from sleeping"</string>
<string name="permlab_wakeLock" product="default" msgid="569409726861695115">"prevent phone from sleeping"</string>
+ <string name="permdesc_wakeLock" product="automotive" msgid="5995045369683254571">"Allows the app to keep the car screen turned on."</string>
<string name="permdesc_wakeLock" product="tablet" msgid="2441742939101526277">"Allows the app to prevent the tablet from going to sleep."</string>
<string name="permdesc_wakeLock" product="tv" msgid="2329298966735118796">"Allows the app to prevent your Android TV device from going to sleep."</string>
<string name="permdesc_wakeLock" product="default" msgid="3689523792074007163">"Allows the app to prevent the phone from going to sleep."</string>
@@ -1629,6 +1631,9 @@
<string name="safe_media_volume_warning" product="default" msgid="3751676824423049994">"Raise volume above recommended level?\n\nListening at high volume for long periods may damage your hearing."</string>
<string name="accessibility_shortcut_warning_dialog_title" msgid="4017995837692622933">"Use Accessibility Shortcut?"</string>
<string name="accessibility_shortcut_toogle_warning" msgid="4161716521310929544">"When the shortcut is on, pressing both volume buttons for three seconds will start an accessibility feature."</string>
+ <string name="accessibility_select_shortcut_menu_title" msgid="7310194076629867377">"Tap the accessibility app that you want to use"</string>
+ <string name="accessibility_edit_shortcut_menu_button_title" msgid="6096484087245145325">"Choose apps that you want to use with Accessibility button"</string>
+ <string name="accessibility_edit_shortcut_menu_volume_title" msgid="4849108668454490699">"Choose apps that you want to use with volume key shortcut"</string>
<string name="edit_accessibility_shortcut_menu_button" msgid="8885752738733772935">"Edit shortcuts"</string>
<string name="cancel_accessibility_shortcut_menu_button" msgid="1817413122335452474">"Cancel"</string>
<string name="disable_accessibility_shortcut" msgid="5806091378745232383">"Turn off Shortcut"</string>
@@ -1851,8 +1856,7 @@
<string name="default_notification_channel_label" msgid="3697928973567217330">"Uncategorised"</string>
<string name="importance_from_user" msgid="2782756722448800447">"You set the importance of these notifications."</string>
<string name="importance_from_person" msgid="4235804979664465383">"This is important because of the people involved."</string>
- <!-- no translation found for notification_history_title_placeholder (7748630986182249599) -->
- <skip />
+ <string name="notification_history_title_placeholder" msgid="7748630986182249599">"Custom app notification"</string>
<string name="user_creation_account_exists" msgid="2239146360099708035">"Allow <xliff:g id="APP">%1$s</xliff:g> to create a new User with <xliff:g id="ACCOUNT">%2$s</xliff:g> (a User with this account already exists)?"</string>
<string name="user_creation_adding" msgid="7305185499667958364">"Allow <xliff:g id="APP">%1$s</xliff:g> to create a new User with <xliff:g id="ACCOUNT">%2$s</xliff:g>?"</string>
<string name="language_selection_title" msgid="52674936078683285">"Add a language"</string>
@@ -2026,14 +2030,19 @@
<string name="as_app_forced_to_restricted_bucket" msgid="8233871289353898964">"<xliff:g id="PACKAGE_NAME">%1$s</xliff:g> has been put into the RESTRICTED bucket"</string>
<string name="resolver_personal_tab" msgid="2051260504014442073">"Personal"</string>
<string name="resolver_work_tab" msgid="2690019516263167035">"Work"</string>
+ <string name="resolver_personal_tab_accessibility" msgid="5739524949153091224">"Personal view"</string>
+ <string name="resolver_work_tab_accessibility" msgid="4753168230363802734">"Work view"</string>
<string name="resolver_cant_share_with_work_apps" msgid="7539495559434146897">"Can’t share with work apps"</string>
<string name="resolver_cant_share_with_personal_apps" msgid="8020581735267157241">"Can’t share with personal apps"</string>
- <string name="resolver_cant_share_cross_profile_explanation" msgid="3536237105241882679">"Your IT admin blocked sharing between personal and work apps"</string>
- <string name="resolver_turn_on_work_apps" msgid="8987359079870455469">"Turn on work apps"</string>
- <string name="resolver_turn_on_work_apps_explanation" msgid="6322467455509618928">"Turn on work apps to access work apps and contacts"</string>
+ <string name="resolver_cant_share_cross_profile_explanation" msgid="5556640604460901386">"Your IT admin blocked sharing between personal and work profiles"</string>
+ <string name="resolver_cant_access_work_apps" msgid="375634344111233790">"Can’t access work apps"</string>
+ <string name="resolver_cant_access_work_apps_explanation" msgid="3958762224516867388">"Your IT admin doesn’t let you view personal content in work apps"</string>
+ <string name="resolver_cant_access_personal_apps" msgid="1953215925406474177">"Can’t access personal apps"</string>
+ <string name="resolver_cant_access_personal_apps_explanation" msgid="1725572276741281136">"Your IT admin doesn’t let you view work content in personal apps"</string>
+ <string name="resolver_turn_on_work_apps_share" msgid="619263911204978175">"Turn on work profile to share content"</string>
+ <string name="resolver_turn_on_work_apps_view" msgid="3073389230905543680">"Turn on work profile to view content"</string>
<string name="resolver_no_apps_available" msgid="7710339903040989654">"No apps available"</string>
- <string name="resolver_no_apps_available_explanation" msgid="4662694431121196560">"We couldn’t find any apps"</string>
- <string name="resolver_switch_on_work" msgid="8294542702883688533">"Switch on work"</string>
+ <string name="resolver_switch_on_work" msgid="2873009160846966379">"Turn on"</string>
<string name="permlab_accessCallAudio" msgid="1682957511874097664">"Record or play audio in telephony calls"</string>
<string name="permdesc_accessCallAudio" msgid="8448360894684277823">"Allows this app, when assigned as a default dialler application, to record or play audio in telephony calls."</string>
</resources>
diff --git a/core/res/res/values-en-rCA/strings.xml b/core/res/res/values-en-rCA/strings.xml
index 78db7589a22e..07d1862f23f9 100644
--- a/core/res/res/values-en-rCA/strings.xml
+++ b/core/res/res/values-en-rCA/strings.xml
@@ -452,9 +452,11 @@
<string name="permdesc_acceptHandovers" msgid="7129026180128626870">"Allows the app to continue a call which was started in another app."</string>
<string name="permlab_readPhoneNumbers" msgid="5668704794723365628">"read phone numbers"</string>
<string name="permdesc_readPhoneNumbers" msgid="7368652482818338871">"Allows the app to access the phone numbers of the device."</string>
+ <string name="permlab_wakeLock" product="automotive" msgid="1904736682319375676">"keep car screen turned on"</string>
<string name="permlab_wakeLock" product="tablet" msgid="1527660973931694000">"prevent tablet from sleeping"</string>
<string name="permlab_wakeLock" product="tv" msgid="2856941418123343518">"prevent your Android TV device from sleeping"</string>
<string name="permlab_wakeLock" product="default" msgid="569409726861695115">"prevent phone from sleeping"</string>
+ <string name="permdesc_wakeLock" product="automotive" msgid="5995045369683254571">"Allows the app to keep the car screen turned on."</string>
<string name="permdesc_wakeLock" product="tablet" msgid="2441742939101526277">"Allows the app to prevent the tablet from going to sleep."</string>
<string name="permdesc_wakeLock" product="tv" msgid="2329298966735118796">"Allows the app to prevent your Android TV device from going to sleep."</string>
<string name="permdesc_wakeLock" product="default" msgid="3689523792074007163">"Allows the app to prevent the phone from going to sleep."</string>
@@ -1629,6 +1631,9 @@
<string name="safe_media_volume_warning" product="default" msgid="3751676824423049994">"Raise volume above recommended level?\n\nListening at high volume for long periods may damage your hearing."</string>
<string name="accessibility_shortcut_warning_dialog_title" msgid="4017995837692622933">"Use Accessibility Shortcut?"</string>
<string name="accessibility_shortcut_toogle_warning" msgid="4161716521310929544">"When the shortcut is on, pressing both volume buttons for three seconds will start an accessibility feature."</string>
+ <string name="accessibility_select_shortcut_menu_title" msgid="7310194076629867377">"Tap the accessibility app that you want to use"</string>
+ <string name="accessibility_edit_shortcut_menu_button_title" msgid="6096484087245145325">"Choose apps that you want to use with Accessibility button"</string>
+ <string name="accessibility_edit_shortcut_menu_volume_title" msgid="4849108668454490699">"Choose apps that you want to use with volume key shortcut"</string>
<string name="edit_accessibility_shortcut_menu_button" msgid="8885752738733772935">"Edit shortcuts"</string>
<string name="cancel_accessibility_shortcut_menu_button" msgid="1817413122335452474">"Cancel"</string>
<string name="disable_accessibility_shortcut" msgid="5806091378745232383">"Turn off Shortcut"</string>
@@ -1851,8 +1856,7 @@
<string name="default_notification_channel_label" msgid="3697928973567217330">"Uncategorised"</string>
<string name="importance_from_user" msgid="2782756722448800447">"You set the importance of these notifications."</string>
<string name="importance_from_person" msgid="4235804979664465383">"This is important because of the people involved."</string>
- <!-- no translation found for notification_history_title_placeholder (7748630986182249599) -->
- <skip />
+ <string name="notification_history_title_placeholder" msgid="7748630986182249599">"Custom app notification"</string>
<string name="user_creation_account_exists" msgid="2239146360099708035">"Allow <xliff:g id="APP">%1$s</xliff:g> to create a new User with <xliff:g id="ACCOUNT">%2$s</xliff:g> (a User with this account already exists)?"</string>
<string name="user_creation_adding" msgid="7305185499667958364">"Allow <xliff:g id="APP">%1$s</xliff:g> to create a new User with <xliff:g id="ACCOUNT">%2$s</xliff:g>?"</string>
<string name="language_selection_title" msgid="52674936078683285">"Add a language"</string>
@@ -2026,14 +2030,19 @@
<string name="as_app_forced_to_restricted_bucket" msgid="8233871289353898964">"<xliff:g id="PACKAGE_NAME">%1$s</xliff:g> has been put into the RESTRICTED bucket"</string>
<string name="resolver_personal_tab" msgid="2051260504014442073">"Personal"</string>
<string name="resolver_work_tab" msgid="2690019516263167035">"Work"</string>
+ <string name="resolver_personal_tab_accessibility" msgid="5739524949153091224">"Personal view"</string>
+ <string name="resolver_work_tab_accessibility" msgid="4753168230363802734">"Work view"</string>
<string name="resolver_cant_share_with_work_apps" msgid="7539495559434146897">"Can’t share with work apps"</string>
<string name="resolver_cant_share_with_personal_apps" msgid="8020581735267157241">"Can’t share with personal apps"</string>
- <string name="resolver_cant_share_cross_profile_explanation" msgid="3536237105241882679">"Your IT admin blocked sharing between personal and work apps"</string>
- <string name="resolver_turn_on_work_apps" msgid="8987359079870455469">"Turn on work apps"</string>
- <string name="resolver_turn_on_work_apps_explanation" msgid="6322467455509618928">"Turn on work apps to access work apps and contacts"</string>
+ <string name="resolver_cant_share_cross_profile_explanation" msgid="5556640604460901386">"Your IT admin blocked sharing between personal and work profiles"</string>
+ <string name="resolver_cant_access_work_apps" msgid="375634344111233790">"Can’t access work apps"</string>
+ <string name="resolver_cant_access_work_apps_explanation" msgid="3958762224516867388">"Your IT admin doesn’t let you view personal content in work apps"</string>
+ <string name="resolver_cant_access_personal_apps" msgid="1953215925406474177">"Can’t access personal apps"</string>
+ <string name="resolver_cant_access_personal_apps_explanation" msgid="1725572276741281136">"Your IT admin doesn’t let you view work content in personal apps"</string>
+ <string name="resolver_turn_on_work_apps_share" msgid="619263911204978175">"Turn on work profile to share content"</string>
+ <string name="resolver_turn_on_work_apps_view" msgid="3073389230905543680">"Turn on work profile to view content"</string>
<string name="resolver_no_apps_available" msgid="7710339903040989654">"No apps available"</string>
- <string name="resolver_no_apps_available_explanation" msgid="4662694431121196560">"We couldn’t find any apps"</string>
- <string name="resolver_switch_on_work" msgid="8294542702883688533">"Switch on work"</string>
+ <string name="resolver_switch_on_work" msgid="2873009160846966379">"Turn on"</string>
<string name="permlab_accessCallAudio" msgid="1682957511874097664">"Record or play audio in telephony calls"</string>
<string name="permdesc_accessCallAudio" msgid="8448360894684277823">"Allows this app, when assigned as a default dialler application, to record or play audio in telephony calls."</string>
</resources>
diff --git a/core/res/res/values-en-rGB/strings.xml b/core/res/res/values-en-rGB/strings.xml
index c5259fdaebf0..c8e03c6e42b8 100644
--- a/core/res/res/values-en-rGB/strings.xml
+++ b/core/res/res/values-en-rGB/strings.xml
@@ -452,9 +452,11 @@
<string name="permdesc_acceptHandovers" msgid="7129026180128626870">"Allows the app to continue a call which was started in another app."</string>
<string name="permlab_readPhoneNumbers" msgid="5668704794723365628">"read phone numbers"</string>
<string name="permdesc_readPhoneNumbers" msgid="7368652482818338871">"Allows the app to access the phone numbers of the device."</string>
+ <string name="permlab_wakeLock" product="automotive" msgid="1904736682319375676">"keep car screen turned on"</string>
<string name="permlab_wakeLock" product="tablet" msgid="1527660973931694000">"prevent tablet from sleeping"</string>
<string name="permlab_wakeLock" product="tv" msgid="2856941418123343518">"prevent your Android TV device from sleeping"</string>
<string name="permlab_wakeLock" product="default" msgid="569409726861695115">"prevent phone from sleeping"</string>
+ <string name="permdesc_wakeLock" product="automotive" msgid="5995045369683254571">"Allows the app to keep the car screen turned on."</string>
<string name="permdesc_wakeLock" product="tablet" msgid="2441742939101526277">"Allows the app to prevent the tablet from going to sleep."</string>
<string name="permdesc_wakeLock" product="tv" msgid="2329298966735118796">"Allows the app to prevent your Android TV device from going to sleep."</string>
<string name="permdesc_wakeLock" product="default" msgid="3689523792074007163">"Allows the app to prevent the phone from going to sleep."</string>
@@ -1629,6 +1631,9 @@
<string name="safe_media_volume_warning" product="default" msgid="3751676824423049994">"Raise volume above recommended level?\n\nListening at high volume for long periods may damage your hearing."</string>
<string name="accessibility_shortcut_warning_dialog_title" msgid="4017995837692622933">"Use Accessibility Shortcut?"</string>
<string name="accessibility_shortcut_toogle_warning" msgid="4161716521310929544">"When the shortcut is on, pressing both volume buttons for three seconds will start an accessibility feature."</string>
+ <string name="accessibility_select_shortcut_menu_title" msgid="7310194076629867377">"Tap the accessibility app that you want to use"</string>
+ <string name="accessibility_edit_shortcut_menu_button_title" msgid="6096484087245145325">"Choose apps that you want to use with Accessibility button"</string>
+ <string name="accessibility_edit_shortcut_menu_volume_title" msgid="4849108668454490699">"Choose apps that you want to use with volume key shortcut"</string>
<string name="edit_accessibility_shortcut_menu_button" msgid="8885752738733772935">"Edit shortcuts"</string>
<string name="cancel_accessibility_shortcut_menu_button" msgid="1817413122335452474">"Cancel"</string>
<string name="disable_accessibility_shortcut" msgid="5806091378745232383">"Turn off Shortcut"</string>
@@ -1851,8 +1856,7 @@
<string name="default_notification_channel_label" msgid="3697928973567217330">"Uncategorised"</string>
<string name="importance_from_user" msgid="2782756722448800447">"You set the importance of these notifications."</string>
<string name="importance_from_person" msgid="4235804979664465383">"This is important because of the people involved."</string>
- <!-- no translation found for notification_history_title_placeholder (7748630986182249599) -->
- <skip />
+ <string name="notification_history_title_placeholder" msgid="7748630986182249599">"Custom app notification"</string>
<string name="user_creation_account_exists" msgid="2239146360099708035">"Allow <xliff:g id="APP">%1$s</xliff:g> to create a new User with <xliff:g id="ACCOUNT">%2$s</xliff:g> (a User with this account already exists)?"</string>
<string name="user_creation_adding" msgid="7305185499667958364">"Allow <xliff:g id="APP">%1$s</xliff:g> to create a new User with <xliff:g id="ACCOUNT">%2$s</xliff:g>?"</string>
<string name="language_selection_title" msgid="52674936078683285">"Add a language"</string>
@@ -2026,14 +2030,19 @@
<string name="as_app_forced_to_restricted_bucket" msgid="8233871289353898964">"<xliff:g id="PACKAGE_NAME">%1$s</xliff:g> has been put into the RESTRICTED bucket"</string>
<string name="resolver_personal_tab" msgid="2051260504014442073">"Personal"</string>
<string name="resolver_work_tab" msgid="2690019516263167035">"Work"</string>
+ <string name="resolver_personal_tab_accessibility" msgid="5739524949153091224">"Personal view"</string>
+ <string name="resolver_work_tab_accessibility" msgid="4753168230363802734">"Work view"</string>
<string name="resolver_cant_share_with_work_apps" msgid="7539495559434146897">"Can’t share with work apps"</string>
<string name="resolver_cant_share_with_personal_apps" msgid="8020581735267157241">"Can’t share with personal apps"</string>
- <string name="resolver_cant_share_cross_profile_explanation" msgid="3536237105241882679">"Your IT admin blocked sharing between personal and work apps"</string>
- <string name="resolver_turn_on_work_apps" msgid="8987359079870455469">"Turn on work apps"</string>
- <string name="resolver_turn_on_work_apps_explanation" msgid="6322467455509618928">"Turn on work apps to access work apps and contacts"</string>
+ <string name="resolver_cant_share_cross_profile_explanation" msgid="5556640604460901386">"Your IT admin blocked sharing between personal and work profiles"</string>
+ <string name="resolver_cant_access_work_apps" msgid="375634344111233790">"Can’t access work apps"</string>
+ <string name="resolver_cant_access_work_apps_explanation" msgid="3958762224516867388">"Your IT admin doesn’t let you view personal content in work apps"</string>
+ <string name="resolver_cant_access_personal_apps" msgid="1953215925406474177">"Can’t access personal apps"</string>
+ <string name="resolver_cant_access_personal_apps_explanation" msgid="1725572276741281136">"Your IT admin doesn’t let you view work content in personal apps"</string>
+ <string name="resolver_turn_on_work_apps_share" msgid="619263911204978175">"Turn on work profile to share content"</string>
+ <string name="resolver_turn_on_work_apps_view" msgid="3073389230905543680">"Turn on work profile to view content"</string>
<string name="resolver_no_apps_available" msgid="7710339903040989654">"No apps available"</string>
- <string name="resolver_no_apps_available_explanation" msgid="4662694431121196560">"We couldn’t find any apps"</string>
- <string name="resolver_switch_on_work" msgid="8294542702883688533">"Switch on work"</string>
+ <string name="resolver_switch_on_work" msgid="2873009160846966379">"Turn on"</string>
<string name="permlab_accessCallAudio" msgid="1682957511874097664">"Record or play audio in telephony calls"</string>
<string name="permdesc_accessCallAudio" msgid="8448360894684277823">"Allows this app, when assigned as a default dialler application, to record or play audio in telephony calls."</string>
</resources>
diff --git a/core/res/res/values-en-rIN/strings.xml b/core/res/res/values-en-rIN/strings.xml
index c5259fdaebf0..c8e03c6e42b8 100644
--- a/core/res/res/values-en-rIN/strings.xml
+++ b/core/res/res/values-en-rIN/strings.xml
@@ -452,9 +452,11 @@
<string name="permdesc_acceptHandovers" msgid="7129026180128626870">"Allows the app to continue a call which was started in another app."</string>
<string name="permlab_readPhoneNumbers" msgid="5668704794723365628">"read phone numbers"</string>
<string name="permdesc_readPhoneNumbers" msgid="7368652482818338871">"Allows the app to access the phone numbers of the device."</string>
+ <string name="permlab_wakeLock" product="automotive" msgid="1904736682319375676">"keep car screen turned on"</string>
<string name="permlab_wakeLock" product="tablet" msgid="1527660973931694000">"prevent tablet from sleeping"</string>
<string name="permlab_wakeLock" product="tv" msgid="2856941418123343518">"prevent your Android TV device from sleeping"</string>
<string name="permlab_wakeLock" product="default" msgid="569409726861695115">"prevent phone from sleeping"</string>
+ <string name="permdesc_wakeLock" product="automotive" msgid="5995045369683254571">"Allows the app to keep the car screen turned on."</string>
<string name="permdesc_wakeLock" product="tablet" msgid="2441742939101526277">"Allows the app to prevent the tablet from going to sleep."</string>
<string name="permdesc_wakeLock" product="tv" msgid="2329298966735118796">"Allows the app to prevent your Android TV device from going to sleep."</string>
<string name="permdesc_wakeLock" product="default" msgid="3689523792074007163">"Allows the app to prevent the phone from going to sleep."</string>
@@ -1629,6 +1631,9 @@
<string name="safe_media_volume_warning" product="default" msgid="3751676824423049994">"Raise volume above recommended level?\n\nListening at high volume for long periods may damage your hearing."</string>
<string name="accessibility_shortcut_warning_dialog_title" msgid="4017995837692622933">"Use Accessibility Shortcut?"</string>
<string name="accessibility_shortcut_toogle_warning" msgid="4161716521310929544">"When the shortcut is on, pressing both volume buttons for three seconds will start an accessibility feature."</string>
+ <string name="accessibility_select_shortcut_menu_title" msgid="7310194076629867377">"Tap the accessibility app that you want to use"</string>
+ <string name="accessibility_edit_shortcut_menu_button_title" msgid="6096484087245145325">"Choose apps that you want to use with Accessibility button"</string>
+ <string name="accessibility_edit_shortcut_menu_volume_title" msgid="4849108668454490699">"Choose apps that you want to use with volume key shortcut"</string>
<string name="edit_accessibility_shortcut_menu_button" msgid="8885752738733772935">"Edit shortcuts"</string>
<string name="cancel_accessibility_shortcut_menu_button" msgid="1817413122335452474">"Cancel"</string>
<string name="disable_accessibility_shortcut" msgid="5806091378745232383">"Turn off Shortcut"</string>
@@ -1851,8 +1856,7 @@
<string name="default_notification_channel_label" msgid="3697928973567217330">"Uncategorised"</string>
<string name="importance_from_user" msgid="2782756722448800447">"You set the importance of these notifications."</string>
<string name="importance_from_person" msgid="4235804979664465383">"This is important because of the people involved."</string>
- <!-- no translation found for notification_history_title_placeholder (7748630986182249599) -->
- <skip />
+ <string name="notification_history_title_placeholder" msgid="7748630986182249599">"Custom app notification"</string>
<string name="user_creation_account_exists" msgid="2239146360099708035">"Allow <xliff:g id="APP">%1$s</xliff:g> to create a new User with <xliff:g id="ACCOUNT">%2$s</xliff:g> (a User with this account already exists)?"</string>
<string name="user_creation_adding" msgid="7305185499667958364">"Allow <xliff:g id="APP">%1$s</xliff:g> to create a new User with <xliff:g id="ACCOUNT">%2$s</xliff:g>?"</string>
<string name="language_selection_title" msgid="52674936078683285">"Add a language"</string>
@@ -2026,14 +2030,19 @@
<string name="as_app_forced_to_restricted_bucket" msgid="8233871289353898964">"<xliff:g id="PACKAGE_NAME">%1$s</xliff:g> has been put into the RESTRICTED bucket"</string>
<string name="resolver_personal_tab" msgid="2051260504014442073">"Personal"</string>
<string name="resolver_work_tab" msgid="2690019516263167035">"Work"</string>
+ <string name="resolver_personal_tab_accessibility" msgid="5739524949153091224">"Personal view"</string>
+ <string name="resolver_work_tab_accessibility" msgid="4753168230363802734">"Work view"</string>
<string name="resolver_cant_share_with_work_apps" msgid="7539495559434146897">"Can’t share with work apps"</string>
<string name="resolver_cant_share_with_personal_apps" msgid="8020581735267157241">"Can’t share with personal apps"</string>
- <string name="resolver_cant_share_cross_profile_explanation" msgid="3536237105241882679">"Your IT admin blocked sharing between personal and work apps"</string>
- <string name="resolver_turn_on_work_apps" msgid="8987359079870455469">"Turn on work apps"</string>
- <string name="resolver_turn_on_work_apps_explanation" msgid="6322467455509618928">"Turn on work apps to access work apps and contacts"</string>
+ <string name="resolver_cant_share_cross_profile_explanation" msgid="5556640604460901386">"Your IT admin blocked sharing between personal and work profiles"</string>
+ <string name="resolver_cant_access_work_apps" msgid="375634344111233790">"Can’t access work apps"</string>
+ <string name="resolver_cant_access_work_apps_explanation" msgid="3958762224516867388">"Your IT admin doesn’t let you view personal content in work apps"</string>
+ <string name="resolver_cant_access_personal_apps" msgid="1953215925406474177">"Can’t access personal apps"</string>
+ <string name="resolver_cant_access_personal_apps_explanation" msgid="1725572276741281136">"Your IT admin doesn’t let you view work content in personal apps"</string>
+ <string name="resolver_turn_on_work_apps_share" msgid="619263911204978175">"Turn on work profile to share content"</string>
+ <string name="resolver_turn_on_work_apps_view" msgid="3073389230905543680">"Turn on work profile to view content"</string>
<string name="resolver_no_apps_available" msgid="7710339903040989654">"No apps available"</string>
- <string name="resolver_no_apps_available_explanation" msgid="4662694431121196560">"We couldn’t find any apps"</string>
- <string name="resolver_switch_on_work" msgid="8294542702883688533">"Switch on work"</string>
+ <string name="resolver_switch_on_work" msgid="2873009160846966379">"Turn on"</string>
<string name="permlab_accessCallAudio" msgid="1682957511874097664">"Record or play audio in telephony calls"</string>
<string name="permdesc_accessCallAudio" msgid="8448360894684277823">"Allows this app, when assigned as a default dialler application, to record or play audio in telephony calls."</string>
</resources>
diff --git a/core/res/res/values-en-rXC/strings.xml b/core/res/res/values-en-rXC/strings.xml
index eb546534f94c..c30c10e8c5fa 100644
--- a/core/res/res/values-en-rXC/strings.xml
+++ b/core/res/res/values-en-rXC/strings.xml
@@ -452,9 +452,11 @@
<string name="permdesc_acceptHandovers" msgid="7129026180128626870">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‏‎‎‎‏‎‏‏‏‎‏‏‏‏‎‏‏‎‎‎‏‏‏‎‎‎‏‎‏‎‎‎‏‎‎‏‎‏‎‎‎‎‎‏‏‎‏‏‎‏‏‎‎‎‏‎‏‏‎‏‏‎‎Allows the app to continue a call which was started in another app.‎‏‎‎‏‎"</string>
<string name="permlab_readPhoneNumbers" msgid="5668704794723365628">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‎‎‏‏‏‎‏‎‏‎‏‎‏‏‎‏‎‎‏‎‎‎‏‏‏‏‏‎‏‎‎‎‎‎‏‎‏‎‎‎‎‎‏‎‏‎‎‎‏‏‎‎‏‎‏‏‏‏‏‏‎‎‎read phone numbers‎‏‎‎‏‎"</string>
<string name="permdesc_readPhoneNumbers" msgid="7368652482818338871">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‏‎‎‏‏‎‎‏‎‎‎‎‏‎‏‎‏‏‎‏‏‎‎‏‏‎‎‏‎‎‎‏‏‎‏‏‏‏‏‎‏‎‏‏‏‏‏‏‏‏‎‎‎‎‎‎‏‏‎‏‏‏‎Allows the app to access the phone numbers of the device.‎‏‎‎‏‎"</string>
+ <string name="permlab_wakeLock" product="automotive" msgid="1904736682319375676">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‎‏‏‏‎‏‎‎‏‏‎‏‏‏‎‏‏‏‏‏‎‏‏‏‏‏‎‏‎‏‏‏‎‏‏‏‏‎‎‎‏‎‎‏‏‎‏‎‏‏‎‏‏‎‏‎‎‏‏‏‏‎‎‎keep car screen turned on‎‏‎‎‏‎"</string>
<string name="permlab_wakeLock" product="tablet" msgid="1527660973931694000">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‎‏‏‎‏‎‏‎‎‏‏‎‎‏‏‎‏‎‏‎‏‏‏‏‎‎‎‏‏‏‏‏‏‎‏‏‎‎‎‎‏‏‎‏‏‎‏‎‎‎‎‎‏‏‏‏‎‏‏‎‎‎‎‎prevent tablet from sleeping‎‏‎‎‏‎"</string>
<string name="permlab_wakeLock" product="tv" msgid="2856941418123343518">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‎‏‎‎‏‏‏‏‎‏‎‎‏‎‏‏‏‏‎‎‏‎‏‎‎‎‏‎‏‎‏‎‏‎‎‎‎‏‏‎‏‎‏‎‏‏‏‏‎‏‏‎‏‏‎‏‎‎‏‏‏‏‎‎prevent your Android TV device from sleeping‎‏‎‎‏‎"</string>
<string name="permlab_wakeLock" product="default" msgid="569409726861695115">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‎‏‏‏‏‏‏‏‏‎‎‏‏‎‏‏‏‏‎‎‏‏‎‎‏‎‎‎‎‏‎‎‏‏‎‏‎‏‎‎‏‏‏‏‏‎‎‏‎‏‏‎‎‎‏‎‎‎‏‎‏‏‎prevent phone from sleeping‎‏‎‎‏‎"</string>
+ <string name="permdesc_wakeLock" product="automotive" msgid="5995045369683254571">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‎‏‎‎‏‏‎‎‏‏‎‎‏‎‏‎‏‎‏‏‏‎‎‎‎‎‎‎‎‎‎‎‏‎‏‎‎‎‎‏‎‏‎‎‏‎‎‎‎‏‏‏‎‏‎‎‏‎‏‎‏‏‎Allows the app to keep the car screen turned on.‎‏‎‎‏‎"</string>
<string name="permdesc_wakeLock" product="tablet" msgid="2441742939101526277">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‎‏‎‎‎‎‏‏‏‏‎‎‎‏‎‏‏‎‏‎‎‎‎‎‏‎‎‎‏‎‎‎‎‏‎‎‏‎‏‏‏‏‏‎‏‏‎‏‏‏‏‏‎‎‏‎‎‎‎‎‏‎‏‎Allows the app to prevent the tablet from going to sleep.‎‏‎‎‏‎"</string>
<string name="permdesc_wakeLock" product="tv" msgid="2329298966735118796">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‎‏‎‎‎‎‎‎‏‎‏‎‎‏‏‎‏‎‏‎‏‎‏‎‎‎‏‎‎‎‏‏‎‏‎‏‏‏‏‏‏‏‎‏‏‏‎‎‏‏‎‎‎‎‏‏‏‎‎‏‏‎‎‎Allows the app to prevent your Android TV device from going to sleep.‎‏‎‎‏‎"</string>
<string name="permdesc_wakeLock" product="default" msgid="3689523792074007163">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‎‏‏‎‎‏‏‎‎‏‏‎‎‏‏‏‏‎‏‎‎‏‎‎‏‎‏‎‏‏‏‎‏‎‎‏‎‎‎‏‏‏‎‏‏‎‎‎‏‏‎‎‎‏‎‎‏‏‏‏‎‏‏‎Allows the app to prevent the phone from going to sleep.‎‏‎‎‏‎"</string>
@@ -1629,6 +1631,9 @@
<string name="safe_media_volume_warning" product="default" msgid="3751676824423049994">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‎‏‏‎‏‎‎‎‎‎‏‎‎‎‎‏‎‏‎‎‎‏‎‎‎‏‏‎‎‎‏‏‏‎‎‏‏‏‏‏‏‎‎‏‏‎‏‎‎‏‎‏‎‏‏‎‎‎‎‏‎‏‎‎Raise volume above recommended level?‎‏‎‎‏‏‎\n‎‏‎‎‏‏‏‎‎‏‎‎‏‏‎\n‎‏‎‎‏‏‏‎Listening at high volume for long periods may damage your hearing.‎‏‎‎‏‎"</string>
<string name="accessibility_shortcut_warning_dialog_title" msgid="4017995837692622933">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‎‏‏‎‏‏‏‏‏‎‎‎‎‏‎‏‏‎‎‏‎‎‏‏‏‏‎‏‏‎‏‎‎‎‏‎‏‏‎‏‎‏‎‏‎‏‎‏‎‏‏‏‎‎‎‎‏‎‏‎‏‎‏‎Use Accessibility Shortcut?‎‏‎‎‏‎"</string>
<string name="accessibility_shortcut_toogle_warning" msgid="4161716521310929544">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‎‏‏‏‎‎‏‏‏‎‎‎‎‎‏‎‏‏‎‎‎‏‏‎‎‏‎‎‎‎‎‎‏‎‏‏‏‎‎‏‎‎‏‏‏‎‎‏‏‎‎‎‎‏‎‏‎‎‎‏‎‎‎‎When the shortcut is on, pressing both volume buttons for 3 seconds will start an accessibility feature.‎‏‎‎‏‎"</string>
+ <string name="accessibility_select_shortcut_menu_title" msgid="7310194076629867377">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‏‎‎‏‎‏‎‏‏‏‎‎‏‏‎‎‎‎‎‏‏‎‏‏‎‎‏‎‎‎‎‎‎‏‏‎‎‎‏‎‏‏‎‎‎‎‎‎‎‏‏‎‏‏‎‏‏‏‎‎‎‏‎Tap the accessibility app you want to use‎‏‎‎‏‎"</string>
+ <string name="accessibility_edit_shortcut_menu_button_title" msgid="6096484087245145325">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‎‏‎‏‎‎‏‎‎‏‏‎‏‏‎‎‎‎‏‏‏‏‏‏‏‏‏‎‏‎‎‎‎‎‏‏‏‏‎‎‎‏‎‎‎‏‏‎‎‎‎‏‎‎‏‏‏‎‏‏‎‏‎Choose apps you want to use with accessibility button‎‏‎‎‏‎"</string>
+ <string name="accessibility_edit_shortcut_menu_volume_title" msgid="4849108668454490699">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‎‎‎‎‏‏‎‏‎‎‏‎‏‏‎‏‏‏‏‏‏‎‏‎‏‎‎‏‎‎‎‏‏‎‏‏‎‎‎‏‏‏‏‏‏‏‎‏‎‏‎‎‏‎‎‏‎‎‏‎‏‏‎Choose apps you want to use with volume key shortcut‎‏‎‎‏‎"</string>
<string name="edit_accessibility_shortcut_menu_button" msgid="8885752738733772935">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‏‏‏‎‏‏‎‏‎‏‎‎‎‎‏‎‎‎‏‎‎‏‎‎‎‎‏‎‎‏‏‎‎‎‎‎‏‎‎‎‏‎‏‏‏‎‎‏‎‏‎‎‎‎‏‎‎‎‎‏‏‏‎Edit shortcuts‎‏‎‎‏‎"</string>
<string name="cancel_accessibility_shortcut_menu_button" msgid="1817413122335452474">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‎‏‏‏‎‎‏‎‎‏‏‏‎‎‎‏‎‏‏‏‏‏‏‏‎‎‏‏‎‏‏‎‎‎‎‏‏‏‎‏‏‏‏‎‎‎‎‎‎‏‎‏‏‎‏‎‎‏‏‏‎‏‎‎Cancel‎‏‎‎‏‎"</string>
<string name="disable_accessibility_shortcut" msgid="5806091378745232383">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‎‏‎‎‎‎‏‎‎‏‎‎‏‏‎‏‏‎‎‎‎‏‎‏‎‏‏‎‎‎‏‏‎‏‎‎‏‏‏‎‎‏‎‎‎‏‎‏‎‎‏‎‏‏‏‏‏‏‏‏‏‏‎Turn off Shortcut‎‏‎‎‏‎"</string>
@@ -1851,8 +1856,7 @@
<string name="default_notification_channel_label" msgid="3697928973567217330">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‎‏‏‎‎‏‏‎‏‎‏‎‎‎‏‏‎‏‎‏‏‏‎‏‏‎‎‏‏‏‏‎‎‎‏‏‎‏‎‎‎‎‏‏‎‎‏‎‏‎‎‏‏‏‎‏‎‏‏‎‎‏‎‎Uncategorized‎‏‎‎‏‎"</string>
<string name="importance_from_user" msgid="2782756722448800447">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‎‏‎‎‏‏‎‏‎‎‏‏‏‏‎‎‏‎‏‎‏‏‎‎‏‏‏‏‏‏‎‏‏‎‏‎‎‎‏‏‏‏‎‎‏‎‎‎‎‎‏‏‎‏‎‏‎‏‏‏‏‏‏‎You set the importance of these notifications.‎‏‎‎‏‎"</string>
<string name="importance_from_person" msgid="4235804979664465383">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‎‏‏‏‎‏‎‏‏‎‎‏‎‎‎‏‎‎‏‏‎‏‎‎‎‏‎‏‏‏‏‏‏‎‎‏‏‏‎‏‎‏‏‏‎‏‏‎‎‏‎‏‏‎‏‏‏‏‎‎‏‏‏‎This is important because of the people involved.‎‏‎‎‏‎"</string>
- <!-- no translation found for notification_history_title_placeholder (7748630986182249599) -->
- <skip />
+ <string name="notification_history_title_placeholder" msgid="7748630986182249599">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‏‎‏‎‏‏‏‎‎‎‏‎‎‎‏‎‏‎‏‎‏‎‏‏‎‏‎‎‏‏‏‏‏‏‎‎‏‎‏‏‏‏‏‎‏‎‎‏‎‎‏‏‎‎‎‏‏‏‏‏‏‏‎Custom app notification‎‏‎‎‏‎"</string>
<string name="user_creation_account_exists" msgid="2239146360099708035">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‎‏‏‏‏‏‏‎‎‎‏‎‎‏‏‎‎‎‎‏‎‏‏‏‏‎‎‎‎‎‎‎‏‎‎‎‎‎‏‏‏‎‏‏‎‏‎‎‎‎‏‏‏‎‎‏‎‎‎‎‎‏‏‎Allow ‎‏‎‎‏‏‎<xliff:g id="APP">%1$s</xliff:g>‎‏‎‎‏‏‏‎ to create a new User with ‎‏‎‎‏‏‎<xliff:g id="ACCOUNT">%2$s</xliff:g>‎‏‎‎‏‏‏‎ (a User with this account already exists) ?‎‏‎‎‏‎"</string>
<string name="user_creation_adding" msgid="7305185499667958364">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‏‎‎‏‎‏‎‏‏‎‎‎‎‏‎‎‏‏‏‎‏‏‏‎‎‎‎‎‎‏‏‏‏‎‎‏‏‎‎‎‎‎‏‎‏‏‎‎‎‎‏‎‏‎‎‏‎‏‏‏‎‎‎Allow ‎‏‎‎‏‏‎<xliff:g id="APP">%1$s</xliff:g>‎‏‎‎‏‏‏‎ to create a new User with ‎‏‎‎‏‏‎<xliff:g id="ACCOUNT">%2$s</xliff:g>‎‏‎‎‏‏‏‎ ?‎‏‎‎‏‎"</string>
<string name="language_selection_title" msgid="52674936078683285">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‎‎‎‏‎‏‏‏‎‏‏‎‎‏‎‎‎‏‏‏‎‎‏‎‎‏‏‎‏‎‎‎‏‎‏‏‎‎‎‏‎‎‏‎‏‎‎‏‏‎‎‏‎‎‏‎‏‎‏‎Add a language‎‏‎‎‏‎"</string>
@@ -2026,14 +2030,19 @@
<string name="as_app_forced_to_restricted_bucket" msgid="8233871289353898964">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‏‏‎‎‏‎‎‏‎‎‎‏‎‎‏‎‎‏‎‏‏‎‎‏‎‏‎‎‎‎‎‎‎‏‎‎‎‎‎‎‏‏‏‎‏‎‎‎‎‎‏‎‏‏‏‏‎‏‎‏‎‎‎‎‏‎‎‏‏‎<xliff:g id="PACKAGE_NAME">%1$s</xliff:g>‎‏‎‎‏‏‏‎ has been put into the RESTRICTED bucket‎‏‎‎‏‎"</string>
<string name="resolver_personal_tab" msgid="2051260504014442073">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‎‏‏‏‏‎‎‎‏‏‏‎‏‏‏‏‎‎‎‏‎‏‎‏‎‎‎‏‏‏‏‎‏‏‏‎‎‏‏‏‎‎‏‎‎‎‏‏‏‎‎‏‏‏‎‎‏‎‏‏‎‎‏‎Personal‎‏‎‎‏‎"</string>
<string name="resolver_work_tab" msgid="2690019516263167035">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‎‏‎‎‏‎‏‎‏‎‏‎‏‎‎‏‏‎‏‏‏‏‎‎‏‏‏‏‏‏‏‎‏‏‎‏‎‎‏‏‎‏‏‏‎‏‏‏‏‏‏‎‏‎‎‎‎‏‏‏‎‏‏‎Work‎‏‎‎‏‎"</string>
+ <string name="resolver_personal_tab_accessibility" msgid="5739524949153091224">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‎‎‏‏‏‏‏‎‏‎‎‏‏‎‏‏‏‎‎‎‏‏‏‎‎‎‏‎‎‎‎‎‏‎‏‏‎‏‏‏‎‎‎‎‏‏‎‎‎‎‏‏‏‎‏‎‎‏‏‎‎‎‎Personal view‎‏‎‎‏‎"</string>
+ <string name="resolver_work_tab_accessibility" msgid="4753168230363802734">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‎‎‎‎‎‏‏‏‏‏‎‏‏‎‏‎‏‎‎‏‎‏‎‏‎‏‎‎‏‎‎‏‏‏‏‎‎‎‏‎‎‎‎‎‎‏‏‎‏‎‏‏‎‎‎‏‏‎‏‏‏‎‎Work view‎‏‎‎‏‎"</string>
<string name="resolver_cant_share_with_work_apps" msgid="7539495559434146897">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‏‎‏‎‎‎‏‎‏‎‎‎‎‏‏‎‏‎‏‎‏‏‎‏‎‎‎‎‏‏‏‏‏‎‏‏‎‏‏‎‏‏‎‏‎‏‎‎‎‏‎‏‎‎‎‏‎‏‎‎‎‏‎Can’t share with work apps‎‏‎‎‏‎"</string>
<string name="resolver_cant_share_with_personal_apps" msgid="8020581735267157241">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‏‎‏‏‏‏‎‏‎‎‏‏‏‎‏‏‎‏‎‏‎‎‏‎‎‏‎‏‏‏‏‏‏‎‎‏‏‎‏‎‎‏‎‏‎‏‏‏‎‎‎‏‎‎‏‏‏‏‏‎‎‏‎Can’t share with personal apps‎‏‎‎‏‎"</string>
- <string name="resolver_cant_share_cross_profile_explanation" msgid="3536237105241882679">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‎‏‏‎‎‎‏‎‎‎‏‎‎‏‏‎‎‏‏‏‏‎‎‏‏‏‎‏‎‎‏‎‏‎‏‎‎‏‏‎‏‏‏‏‏‏‏‏‎‎‎‎‎‎‎‎‎‏‏‎‏‏‏‎Your IT admin blocked sharing between personal and work apps‎‏‎‎‏‎"</string>
- <string name="resolver_turn_on_work_apps" msgid="8987359079870455469">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‏‏‏‏‎‎‏‎‏‏‏‎‎‏‏‎‎‎‎‎‏‏‎‏‏‏‎‏‏‏‎‏‎‏‎‎‎‎‏‎‎‎‏‏‏‏‎‏‎‏‏‏‏‎‏‎‏‎‏‏‎‏‎Turn on work apps‎‏‎‎‏‎"</string>
- <string name="resolver_turn_on_work_apps_explanation" msgid="6322467455509618928">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‎‏‎‏‏‏‏‎‏‏‏‏‎‏‏‏‏‎‏‎‏‎‏‎‏‎‎‏‏‏‎‎‏‎‎‏‎‏‏‎‎‏‏‏‏‎‎‏‏‎‎‎‎‎‏‏‏‏‎‎‎‎‎Turn on work apps to access work apps &amp; contacts‎‏‎‎‏‎"</string>
+ <string name="resolver_cant_share_cross_profile_explanation" msgid="5556640604460901386">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‎‎‏‏‎‏‎‎‎‏‏‏‎‏‎‎‏‎‎‏‏‏‎‎‏‏‎‎‎‎‎‏‏‏‏‏‎‏‎‏‏‎‎‏‏‏‎‏‏‎‎‏‎‎‎‎‎‎‏‎‏‎‎Your IT admin blocked sharing between personal and work profiles‎‏‎‎‏‎"</string>
+ <string name="resolver_cant_access_work_apps" msgid="375634344111233790">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‎‏‏‏‎‏‎‎‏‏‎‏‏‎‏‎‎‎‎‏‎‏‎‏‏‏‎‎‏‎‎‎‎‏‏‏‏‎‎‎‏‎‏‏‏‏‏‏‎‏‏‎‏‎‏‏‏‏‏‏‏‎‎Can’t access work apps‎‏‎‎‏‎"</string>
+ <string name="resolver_cant_access_work_apps_explanation" msgid="3958762224516867388">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‎‏‏‎‏‏‎‏‏‏‏‎‎‎‎‎‏‎‏‏‎‎‏‎‏‎‎‎‏‎‎‏‏‎‎‏‏‏‎‏‎‎‏‎‎‎‎‎‎‏‎‎‏‎‏‎‎‏‏‏‏‎‎‎Your IT admin doesn’t let you view personal content in work apps‎‏‎‎‏‎"</string>
+ <string name="resolver_cant_access_personal_apps" msgid="1953215925406474177">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‎‏‏‏‎‏‏‎‎‎‏‏‎‏‏‎‎‏‏‎‏‏‏‏‎‎‎‏‎‎‏‎‎‎‏‏‎‏‏‎‏‏‏‏‏‎‏‎‎‎‏‏‏‏‏‏‏‎‎‎‎‎‏‎Can’t access personal apps‎‏‎‎‏‎"</string>
+ <string name="resolver_cant_access_personal_apps_explanation" msgid="1725572276741281136">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‎‏‏‎‏‏‏‏‏‏‏‎‎‏‎‎‏‏‏‎‏‏‎‏‏‎‏‎‏‏‏‏‏‎‏‏‏‎‏‎‏‏‎‏‏‎‏‎‎‎‏‎‏‎‏‎‏‏‏‎‎‎‎‎Your IT admin doesn’t let you view work content in personal apps‎‏‎‎‏‎"</string>
+ <string name="resolver_turn_on_work_apps_share" msgid="619263911204978175">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‎‎‏‎‎‎‏‎‎‏‏‎‎‎‎‎‎‏‎‎‎‏‎‎‏‏‏‏‏‏‎‎‎‎‏‎‎‏‏‎‎‏‎‏‏‏‎‏‏‏‏‏‎‏‏‏‏‏‏‏‏‏‎Turn on work profile to share content‎‏‎‎‏‎"</string>
+ <string name="resolver_turn_on_work_apps_view" msgid="3073389230905543680">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‎‏‎‏‎‏‎‏‎‏‎‎‏‏‎‏‏‎‏‏‏‏‏‎‎‏‏‏‎‎‎‏‏‎‏‎‏‎‎‏‎‏‎‎‎‏‎‏‏‎‎‏‏‎‎‎‎‎‎‎‎‎‎‎Turn on work profile to view content‎‏‎‎‏‎"</string>
<string name="resolver_no_apps_available" msgid="7710339903040989654">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‏‎‏‎‏‏‎‎‎‎‎‎‎‎‏‎‏‎‎‎‎‏‎‏‎‎‏‎‏‎‎‏‏‎‏‎‏‎‎‏‎‎‎‏‏‏‎‎‏‎‏‎‎‏‏‏‎‏‎‏‏‎‎No apps available‎‏‎‎‏‎"</string>
- <string name="resolver_no_apps_available_explanation" msgid="4662694431121196560">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‎‎‎‎‎‎‏‎‏‏‎‏‎‏‎‎‏‏‎‏‏‏‏‏‏‎‎‎‎‏‏‎‎‎‏‏‏‏‎‎‏‎‏‎‏‏‏‏‎‎‎‏‏‎‎‎‎‏‎‎‎‎‎We couldn’t find any apps‎‏‎‎‏‎"</string>
- <string name="resolver_switch_on_work" msgid="8294542702883688533">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‏‏‎‎‏‏‎‎‎‏‏‏‎‎‎‎‏‎‎‎‏‎‏‎‏‎‎‏‎‎‎‏‎‏‎‎‏‏‏‎‏‏‎‎‎‎‏‏‎‏‎‎‎‎‎‏‎‏‎‏‎‏‎Switch on work‎‏‎‎‏‎"</string>
+ <string name="resolver_switch_on_work" msgid="2873009160846966379">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‎‏‎‎‏‏‏‏‏‎‏‏‏‏‎‏‏‏‏‏‎‏‎‏‎‎‏‏‏‎‎‎‎‏‎‎‏‎‎‏‎‏‏‏‎‎‏‏‏‏‏‏‏‏‎‎‏‏‎‏‎‏‏‎Turn on‎‏‎‎‏‎"</string>
<string name="permlab_accessCallAudio" msgid="1682957511874097664">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‎‏‏‎‏‏‏‎‏‎‏‏‎‏‏‎‎‎‏‎‎‎‎‏‏‏‏‎‎‎‎‏‎‏‏‏‎‏‏‎‏‎‏‎‏‎‎‏‎‏‏‎‎‏‎‎‎‎‎‎‎‎‎‎Record or play audio in telephony calls‎‏‎‎‏‎"</string>
<string name="permdesc_accessCallAudio" msgid="8448360894684277823">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‏‏‎‏‎‏‎‎‏‏‏‏‏‎‏‎‎‏‏‎‏‏‎‏‏‏‏‎‎‎‏‏‏‎‏‏‎‏‏‏‏‏‎‏‎‏‎‎‏‎‏‏‎‎‎‎‏‏‏‏‏‏‎Allows this app, when assigned as default dialer application, to record or play audio in telephony calls.‎‏‎‎‏‎"</string>
</resources>
diff --git a/core/res/res/values-es-rUS/strings.xml b/core/res/res/values-es-rUS/strings.xml
index 7933f68c2e48..af4b577f9b85 100644
--- a/core/res/res/values-es-rUS/strings.xml
+++ b/core/res/res/values-es-rUS/strings.xml
@@ -249,10 +249,8 @@
<item quantity="other">Se tomará una captura de pantalla para el informe de errores en <xliff:g id="NUMBER_1">%d</xliff:g> segundos.</item>
<item quantity="one">Se tomará una captura de pantalla para el informe de errores en <xliff:g id="NUMBER_0">%d</xliff:g> segundo.</item>
</plurals>
- <!-- no translation found for bugreport_screenshot_success_toast (7986095104151473745) -->
- <skip />
- <!-- no translation found for bugreport_screenshot_failure_toast (6736320861311294294) -->
- <skip />
+ <string name="bugreport_screenshot_success_toast" msgid="7986095104151473745">"Se tomó la captura de pantalla con el informe de errores"</string>
+ <string name="bugreport_screenshot_failure_toast" msgid="6736320861311294294">"No se pudo tomar la captura de pantalla con el informe de errores"</string>
<string name="global_action_toggle_silent_mode" msgid="8464352592860372188">"Modo silencioso"</string>
<string name="global_action_silent_mode_on_status" msgid="2371892537738632013">"El sonido está Desactivado"</string>
<string name="global_action_silent_mode_off_status" msgid="6608006545950920042">"El sonido está Activado"</string>
@@ -454,9 +452,11 @@
<string name="permdesc_acceptHandovers" msgid="7129026180128626870">"Permite que la app continúe con una llamada que se inició en otra app."</string>
<string name="permlab_readPhoneNumbers" msgid="5668704794723365628">"leer números de teléfono"</string>
<string name="permdesc_readPhoneNumbers" msgid="7368652482818338871">"Le permite a la app acceder a los números de teléfono del dispositivo."</string>
+ <string name="permlab_wakeLock" product="automotive" msgid="1904736682319375676">"mantener la pantalla del vehículo encendida"</string>
<string name="permlab_wakeLock" product="tablet" msgid="1527660973931694000">"evitar que el tablet entre en estado de inactividad"</string>
<string name="permlab_wakeLock" product="tv" msgid="2856941418123343518">"evita que se suspenda el dispositivo Android TV"</string>
<string name="permlab_wakeLock" product="default" msgid="569409726861695115">"evitar que el dispositivo entre en estado de inactividad"</string>
+ <string name="permdesc_wakeLock" product="automotive" msgid="5995045369683254571">"Permite que la app mantenga la pantalla del vehículo encendida."</string>
<string name="permdesc_wakeLock" product="tablet" msgid="2441742939101526277">"Permite que la aplicación evite que la tablet entre en estado de inactividad."</string>
<string name="permdesc_wakeLock" product="tv" msgid="2329298966735118796">"Permite que la app evite que se suspenda tu dispositivo Android TV."</string>
<string name="permdesc_wakeLock" product="default" msgid="3689523792074007163">"Permite que la aplicación evite que el dispositivo entre en estado de inactividad."</string>
@@ -1631,6 +1631,12 @@
<string name="safe_media_volume_warning" product="default" msgid="3751676824423049994">"¿Quieres subir el volumen por encima del nivel recomendado?\n\nEscuchar a un alto volumen durante largos períodos puede dañar tu audición."</string>
<string name="accessibility_shortcut_warning_dialog_title" msgid="4017995837692622933">"¿Usar acceso directo de accesibilidad?"</string>
<string name="accessibility_shortcut_toogle_warning" msgid="4161716521310929544">"Cuando la combinación de teclas está activada, puedes presionar los botones de volumen durante 3 segundos para iniciar una función de accesibilidad."</string>
+ <!-- no translation found for accessibility_select_shortcut_menu_title (7310194076629867377) -->
+ <skip />
+ <!-- no translation found for accessibility_edit_shortcut_menu_button_title (6096484087245145325) -->
+ <skip />
+ <!-- no translation found for accessibility_edit_shortcut_menu_volume_title (4849108668454490699) -->
+ <skip />
<string name="edit_accessibility_shortcut_menu_button" msgid="8885752738733772935">"Editar accesos directos"</string>
<string name="cancel_accessibility_shortcut_menu_button" msgid="1817413122335452474">"Cancelar"</string>
<string name="disable_accessibility_shortcut" msgid="5806091378745232383">"Desactivar acceso directo"</string>
@@ -1853,8 +1859,7 @@
<string name="default_notification_channel_label" msgid="3697928973567217330">"Sin categoría"</string>
<string name="importance_from_user" msgid="2782756722448800447">"Estableciste la importancia de estas notificaciones."</string>
<string name="importance_from_person" msgid="4235804979664465383">"Es importante debido a las personas involucradas."</string>
- <!-- no translation found for notification_history_title_placeholder (7748630986182249599) -->
- <skip />
+ <string name="notification_history_title_placeholder" msgid="7748630986182249599">"Notificación de app personalizada"</string>
<string name="user_creation_account_exists" msgid="2239146360099708035">"¿Quieres permitir que <xliff:g id="APP">%1$s</xliff:g> cree un usuario nuevo con <xliff:g id="ACCOUNT">%2$s</xliff:g>? (Ya existe un usuario con esta cuenta)"</string>
<string name="user_creation_adding" msgid="7305185499667958364">"¿Deseas permitir que <xliff:g id="APP">%1$s</xliff:g> cree un usuario nuevo con <xliff:g id="ACCOUNT">%2$s</xliff:g>?"</string>
<string name="language_selection_title" msgid="52674936078683285">"Agregar un idioma"</string>
@@ -2028,14 +2033,29 @@
<string name="as_app_forced_to_restricted_bucket" msgid="8233871289353898964">"Se colocó <xliff:g id="PACKAGE_NAME">%1$s</xliff:g> en el depósito RESTRICTED"</string>
<string name="resolver_personal_tab" msgid="2051260504014442073">"Personal"</string>
<string name="resolver_work_tab" msgid="2690019516263167035">"Trabajo"</string>
+ <!-- no translation found for resolver_personal_tab_accessibility (5739524949153091224) -->
+ <skip />
+ <!-- no translation found for resolver_work_tab_accessibility (4753168230363802734) -->
+ <skip />
<string name="resolver_cant_share_with_work_apps" msgid="7539495559434146897">"No se puede compartir con apps de trabajo"</string>
<string name="resolver_cant_share_with_personal_apps" msgid="8020581735267157241">"No se puede compartir con apps personales"</string>
- <string name="resolver_cant_share_cross_profile_explanation" msgid="3536237105241882679">"Tu administrador de TI bloqueó el uso compartido entre las apps personales y de trabajo"</string>
- <string name="resolver_turn_on_work_apps" msgid="8987359079870455469">"Activa las apps de trabajo"</string>
- <string name="resolver_turn_on_work_apps_explanation" msgid="6322467455509618928">"Activa las apps de trabajo para acceder a apps y contactos de trabajo"</string>
+ <!-- no translation found for resolver_cant_share_cross_profile_explanation (5556640604460901386) -->
+ <skip />
+ <!-- no translation found for resolver_cant_access_work_apps (375634344111233790) -->
+ <skip />
+ <!-- no translation found for resolver_cant_access_work_apps_explanation (3958762224516867388) -->
+ <skip />
+ <!-- no translation found for resolver_cant_access_personal_apps (1953215925406474177) -->
+ <skip />
+ <!-- no translation found for resolver_cant_access_personal_apps_explanation (1725572276741281136) -->
+ <skip />
+ <!-- no translation found for resolver_turn_on_work_apps_share (619263911204978175) -->
+ <skip />
+ <!-- no translation found for resolver_turn_on_work_apps_view (3073389230905543680) -->
+ <skip />
<string name="resolver_no_apps_available" msgid="7710339903040989654">"No hay apps disponibles"</string>
- <string name="resolver_no_apps_available_explanation" msgid="4662694431121196560">"No se pudo encontrar ninguna app"</string>
- <string name="resolver_switch_on_work" msgid="8294542702883688533">"Activar perfil de trabajo"</string>
+ <!-- no translation found for resolver_switch_on_work (2873009160846966379) -->
+ <skip />
<string name="permlab_accessCallAudio" msgid="1682957511874097664">"Graba o reproduce audio en llamadas de telefonía"</string>
<string name="permdesc_accessCallAudio" msgid="8448360894684277823">"Permite que esta app grabe o reproduzca audio en llamadas de telefonía cuando se la asigna como aplicación de teléfono predeterminada."</string>
</resources>
diff --git a/core/res/res/values-es/strings.xml b/core/res/res/values-es/strings.xml
index 7bbfcae2fe2e..518b13279c3a 100644
--- a/core/res/res/values-es/strings.xml
+++ b/core/res/res/values-es/strings.xml
@@ -249,10 +249,8 @@
<item quantity="other">La captura de pantalla para el informe de errores se realizará en <xliff:g id="NUMBER_1">%d</xliff:g> segundos.</item>
<item quantity="one">La captura de pantalla para el informe de errores se realizará en <xliff:g id="NUMBER_0">%d</xliff:g> segundo.</item>
</plurals>
- <!-- no translation found for bugreport_screenshot_success_toast (7986095104151473745) -->
- <skip />
- <!-- no translation found for bugreport_screenshot_failure_toast (6736320861311294294) -->
- <skip />
+ <string name="bugreport_screenshot_success_toast" msgid="7986095104151473745">"Se ha hecho la captura de pantalla con el informe de errores"</string>
+ <string name="bugreport_screenshot_failure_toast" msgid="6736320861311294294">"No se ha podido hacer la captura de pantalla con el informe de errores"</string>
<string name="global_action_toggle_silent_mode" msgid="8464352592860372188">"Modo silencio"</string>
<string name="global_action_silent_mode_on_status" msgid="2371892537738632013">"El sonido está desactivado. Activar"</string>
<string name="global_action_silent_mode_off_status" msgid="6608006545950920042">"El sonido está activado. Desactivar"</string>
@@ -454,9 +452,11 @@
<string name="permdesc_acceptHandovers" msgid="7129026180128626870">"Permite que la aplicación continúe una llamada que se ha iniciado en otra aplicación."</string>
<string name="permlab_readPhoneNumbers" msgid="5668704794723365628">"leer números de teléfono"</string>
<string name="permdesc_readPhoneNumbers" msgid="7368652482818338871">"Permite que la aplicación acceda a los números de teléfono del dispositivo."</string>
+ <string name="permlab_wakeLock" product="automotive" msgid="1904736682319375676">"mantener la pantalla del coche encendida"</string>
<string name="permlab_wakeLock" product="tablet" msgid="1527660973931694000">"impedir que el tablet entre en modo de suspensión"</string>
<string name="permlab_wakeLock" product="tv" msgid="2856941418123343518">"evitar que tu dispositivo Android TV entre en modo de suspensión"</string>
<string name="permlab_wakeLock" product="default" msgid="569409726861695115">"impedir que el teléfono entre en modo de suspensión"</string>
+ <string name="permdesc_wakeLock" product="automotive" msgid="5995045369683254571">"Permite que la aplicación deje la pantalla del coche encendida."</string>
<string name="permdesc_wakeLock" product="tablet" msgid="2441742939101526277">"Permite que la aplicación impida que el tablet entre en modo de suspensión."</string>
<string name="permdesc_wakeLock" product="tv" msgid="2329298966735118796">"Permite que la aplicación impida que tu dispositivo Android TV entre en modo de suspensión."</string>
<string name="permdesc_wakeLock" product="default" msgid="3689523792074007163">"Permite que la aplicación impida que el teléfono entre en modo de suspensión."</string>
@@ -1631,6 +1631,12 @@
<string name="safe_media_volume_warning" product="default" msgid="3751676824423049994">"¿Quieres subir el volumen por encima del nivel recomendado?\n\nEscuchar sonidos fuertes durante mucho tiempo puede dañar los oídos."</string>
<string name="accessibility_shortcut_warning_dialog_title" msgid="4017995837692622933">"¿Utilizar acceso directo de accesibilidad?"</string>
<string name="accessibility_shortcut_toogle_warning" msgid="4161716521310929544">"Si el acceso directo está activado, pulsa los dos botones de volumen durante 3 segundos para iniciar una función de accesibilidad."</string>
+ <!-- no translation found for accessibility_select_shortcut_menu_title (7310194076629867377) -->
+ <skip />
+ <!-- no translation found for accessibility_edit_shortcut_menu_button_title (6096484087245145325) -->
+ <skip />
+ <!-- no translation found for accessibility_edit_shortcut_menu_volume_title (4849108668454490699) -->
+ <skip />
<string name="edit_accessibility_shortcut_menu_button" msgid="8885752738733772935">"Editar accesos directos"</string>
<string name="cancel_accessibility_shortcut_menu_button" msgid="1817413122335452474">"Cancelar"</string>
<string name="disable_accessibility_shortcut" msgid="5806091378745232383">"Desactivar acceso directo"</string>
@@ -1853,8 +1859,7 @@
<string name="default_notification_channel_label" msgid="3697928973567217330">"Sin clasificar"</string>
<string name="importance_from_user" msgid="2782756722448800447">"Tú determinas la importancia de estas notificaciones."</string>
<string name="importance_from_person" msgid="4235804979664465383">"Esto es importante por los usuarios implicados."</string>
- <!-- no translation found for notification_history_title_placeholder (7748630986182249599) -->
- <skip />
+ <string name="notification_history_title_placeholder" msgid="7748630986182249599">"Notificación de aplicación personalizada"</string>
<string name="user_creation_account_exists" msgid="2239146360099708035">"¿Permitir que <xliff:g id="APP">%1$s</xliff:g> cree otro usuario con la cuenta <xliff:g id="ACCOUNT">%2$s</xliff:g>, que ya tiene uno?"</string>
<string name="user_creation_adding" msgid="7305185499667958364">"¿Permitir que <xliff:g id="APP">%1$s</xliff:g> cree otro usuario con la cuenta <xliff:g id="ACCOUNT">%2$s</xliff:g>?"</string>
<string name="language_selection_title" msgid="52674936078683285">"Añadir un idioma"</string>
@@ -2028,14 +2033,29 @@
<string name="as_app_forced_to_restricted_bucket" msgid="8233871289353898964">"<xliff:g id="PACKAGE_NAME">%1$s</xliff:g> se ha incluido en el grupo de restringidos"</string>
<string name="resolver_personal_tab" msgid="2051260504014442073">"Personal"</string>
<string name="resolver_work_tab" msgid="2690019516263167035">"Trabajo"</string>
+ <!-- no translation found for resolver_personal_tab_accessibility (5739524949153091224) -->
+ <skip />
+ <!-- no translation found for resolver_work_tab_accessibility (4753168230363802734) -->
+ <skip />
<string name="resolver_cant_share_with_work_apps" msgid="7539495559434146897">"No se puede compartir con las aplicaciones de trabajo"</string>
<string name="resolver_cant_share_with_personal_apps" msgid="8020581735267157241">"No se puede compartir con las aplicaciones personales"</string>
- <string name="resolver_cant_share_cross_profile_explanation" msgid="3536237105241882679">"No se puede compartir contenido entre las aplicaciones personales y las de trabajo porque el administrador de TI ha bloqueado esta función"</string>
- <string name="resolver_turn_on_work_apps" msgid="8987359079870455469">"Activa las aplicaciones de trabajo"</string>
- <string name="resolver_turn_on_work_apps_explanation" msgid="6322467455509618928">"Activa las aplicaciones de trabajo para acceder a ellas y a los contactos"</string>
+ <!-- no translation found for resolver_cant_share_cross_profile_explanation (5556640604460901386) -->
+ <skip />
+ <!-- no translation found for resolver_cant_access_work_apps (375634344111233790) -->
+ <skip />
+ <!-- no translation found for resolver_cant_access_work_apps_explanation (3958762224516867388) -->
+ <skip />
+ <!-- no translation found for resolver_cant_access_personal_apps (1953215925406474177) -->
+ <skip />
+ <!-- no translation found for resolver_cant_access_personal_apps_explanation (1725572276741281136) -->
+ <skip />
+ <!-- no translation found for resolver_turn_on_work_apps_share (619263911204978175) -->
+ <skip />
+ <!-- no translation found for resolver_turn_on_work_apps_view (3073389230905543680) -->
+ <skip />
<string name="resolver_no_apps_available" msgid="7710339903040989654">"No hay ninguna aplicación disponible"</string>
- <string name="resolver_no_apps_available_explanation" msgid="4662694431121196560">"No se ha podido encontrar ninguna aplicación"</string>
- <string name="resolver_switch_on_work" msgid="8294542702883688533">"Switch on work"</string>
+ <!-- no translation found for resolver_switch_on_work (2873009160846966379) -->
+ <skip />
<string name="permlab_accessCallAudio" msgid="1682957511874097664">"Grabar o reproducir audio en llamadas telefónicas"</string>
<string name="permdesc_accessCallAudio" msgid="8448360894684277823">"Permite que la aplicación grabe o reproduzca audio en las llamadas telefónicas si está asignada como aplicación Teléfono predeterminada."</string>
</resources>
diff --git a/core/res/res/values-et/strings.xml b/core/res/res/values-et/strings.xml
index 34f3a6a51e22..a0ccf68f82d2 100644
--- a/core/res/res/values-et/strings.xml
+++ b/core/res/res/values-et/strings.xml
@@ -249,10 +249,8 @@
<item quantity="other">Veaaruande jaoks ekraanipildi jäädvustamine <xliff:g id="NUMBER_1">%d</xliff:g> sekundi pärast.</item>
<item quantity="one">Veaaruande jaoks ekraanipildi jäädvustamine <xliff:g id="NUMBER_0">%d</xliff:g> sekundi pärast.</item>
</plurals>
- <!-- no translation found for bugreport_screenshot_success_toast (7986095104151473745) -->
- <skip />
- <!-- no translation found for bugreport_screenshot_failure_toast (6736320861311294294) -->
- <skip />
+ <string name="bugreport_screenshot_success_toast" msgid="7986095104151473745">"Veaaruandega koos jäädvustati ekraanipilt"</string>
+ <string name="bugreport_screenshot_failure_toast" msgid="6736320861311294294">"Ekraanipildi jäädvustamine koos veaaruandega ebaõnnestus"</string>
<string name="global_action_toggle_silent_mode" msgid="8464352592860372188">"Hääletu režiim"</string>
<string name="global_action_silent_mode_on_status" msgid="2371892537738632013">"Heli on VÄLJAS"</string>
<string name="global_action_silent_mode_off_status" msgid="6608006545950920042">"Heli on SEES"</string>
@@ -454,9 +452,11 @@
<string name="permdesc_acceptHandovers" msgid="7129026180128626870">"Lubab rakendusel jätkata kõnet, mida alustati teises rakenduses."</string>
<string name="permlab_readPhoneNumbers" msgid="5668704794723365628">"lugeda telefoninumbreid"</string>
<string name="permdesc_readPhoneNumbers" msgid="7368652482818338871">"Rakendusel lubatakse juurde pääseda seadme telefoninumbritele."</string>
+ <string name="permlab_wakeLock" product="automotive" msgid="1904736682319375676">"hoida auto ekraani sisselülitatuna"</string>
<string name="permlab_wakeLock" product="tablet" msgid="1527660973931694000">"tahvelarvuti uinumise vältimine"</string>
<string name="permlab_wakeLock" product="tv" msgid="2856941418123343518">"takistada Android TV seadme unerežiimi lülitumist"</string>
<string name="permlab_wakeLock" product="default" msgid="569409726861695115">"väldi telefoni uinumist"</string>
+ <string name="permdesc_wakeLock" product="automotive" msgid="5995045369683254571">"Lubab rakendusel auto ekraani sisselülitatuna hoida."</string>
<string name="permdesc_wakeLock" product="tablet" msgid="2441742939101526277">"Võimaldab rakendusel vältida tahvelarvuti uinumist."</string>
<string name="permdesc_wakeLock" product="tv" msgid="2329298966735118796">"Võimaldab rakendusel takistada Android TV seadme unerežiimi aktiveerumist."</string>
<string name="permdesc_wakeLock" product="default" msgid="3689523792074007163">"Võimaldab rakendusel vältida telefoni uinumist."</string>
@@ -1631,6 +1631,12 @@
<string name="safe_media_volume_warning" product="default" msgid="3751676824423049994">"Kas suurendada helitugevuse taset üle soovitatud taseme?\n\nPikaajaline valju helitugevusega kuulamine võib kuulmist kahjustada."</string>
<string name="accessibility_shortcut_warning_dialog_title" msgid="4017995837692622933">"Kas kasutada juurdepääsetavuse otseteed?"</string>
<string name="accessibility_shortcut_toogle_warning" msgid="4161716521310929544">"Kui otsetee on sisse lülitatud, käivitab mõlema helitugevuse nupu kolm sekundit all hoidmine juurdepääsetavuse funktsiooni."</string>
+ <!-- no translation found for accessibility_select_shortcut_menu_title (7310194076629867377) -->
+ <skip />
+ <!-- no translation found for accessibility_edit_shortcut_menu_button_title (6096484087245145325) -->
+ <skip />
+ <!-- no translation found for accessibility_edit_shortcut_menu_volume_title (4849108668454490699) -->
+ <skip />
<string name="edit_accessibility_shortcut_menu_button" msgid="8885752738733772935">"Muuda otseteid"</string>
<string name="cancel_accessibility_shortcut_menu_button" msgid="1817413122335452474">"Tühista"</string>
<string name="disable_accessibility_shortcut" msgid="5806091378745232383">"Lülita otsetee välja"</string>
@@ -1853,8 +1859,7 @@
<string name="default_notification_channel_label" msgid="3697928973567217330">"Kategoriseerimata"</string>
<string name="importance_from_user" msgid="2782756722448800447">"Teie määrasite nende märguannete tähtsuse."</string>
<string name="importance_from_person" msgid="4235804979664465383">"See on tähtis osalevate inimeste tõttu."</string>
- <!-- no translation found for notification_history_title_placeholder (7748630986182249599) -->
- <skip />
+ <string name="notification_history_title_placeholder" msgid="7748630986182249599">"Rakenduse kohandatud märguanne"</string>
<string name="user_creation_account_exists" msgid="2239146360099708035">"Kas lubada rakendusel <xliff:g id="APP">%1$s</xliff:g> luua uus kasutaja kontoga <xliff:g id="ACCOUNT">%2$s</xliff:g> (selle kontoga kasutaja on juba olemas)?"</string>
<string name="user_creation_adding" msgid="7305185499667958364">"Kas lubada rakendusel <xliff:g id="APP">%1$s</xliff:g> luua uus kasutaja kontoga <xliff:g id="ACCOUNT">%2$s</xliff:g>?"</string>
<string name="language_selection_title" msgid="52674936078683285">"Keele lisamine"</string>
@@ -2028,14 +2033,29 @@
<string name="as_app_forced_to_restricted_bucket" msgid="8233871289353898964">"<xliff:g id="PACKAGE_NAME">%1$s</xliff:g> on lisatud salve PIIRANGUTEGA"</string>
<string name="resolver_personal_tab" msgid="2051260504014442073">"Isiklik"</string>
<string name="resolver_work_tab" msgid="2690019516263167035">"Töö"</string>
+ <!-- no translation found for resolver_personal_tab_accessibility (5739524949153091224) -->
+ <skip />
+ <!-- no translation found for resolver_work_tab_accessibility (4753168230363802734) -->
+ <skip />
<string name="resolver_cant_share_with_work_apps" msgid="7539495559434146897">"Töörakendustega ei saa jagada"</string>
<string name="resolver_cant_share_with_personal_apps" msgid="8020581735267157241">"Isiklike rakendustega ei saa jagada"</string>
- <string name="resolver_cant_share_cross_profile_explanation" msgid="3536237105241882679">"Teie IT-administraator blokeeris isiklike ja töörakenduste vahel jagamise"</string>
- <string name="resolver_turn_on_work_apps" msgid="8987359079870455469">"Lülita sisse töörakendused"</string>
- <string name="resolver_turn_on_work_apps_explanation" msgid="6322467455509618928">"Lülitage sisse töörakendused, et töörakendustele ja -kontaktidele juurde pääseda"</string>
+ <!-- no translation found for resolver_cant_share_cross_profile_explanation (5556640604460901386) -->
+ <skip />
+ <!-- no translation found for resolver_cant_access_work_apps (375634344111233790) -->
+ <skip />
+ <!-- no translation found for resolver_cant_access_work_apps_explanation (3958762224516867388) -->
+ <skip />
+ <!-- no translation found for resolver_cant_access_personal_apps (1953215925406474177) -->
+ <skip />
+ <!-- no translation found for resolver_cant_access_personal_apps_explanation (1725572276741281136) -->
+ <skip />
+ <!-- no translation found for resolver_turn_on_work_apps_share (619263911204978175) -->
+ <skip />
+ <!-- no translation found for resolver_turn_on_work_apps_view (3073389230905543680) -->
+ <skip />
<string name="resolver_no_apps_available" msgid="7710339903040989654">"Ühtegi rakendust pole saadaval"</string>
- <string name="resolver_no_apps_available_explanation" msgid="4662694431121196560">"Me ei leidnud ühtegi rakendust"</string>
- <string name="resolver_switch_on_work" msgid="8294542702883688533">"Lülita sisse tööprofiil"</string>
+ <!-- no translation found for resolver_switch_on_work (2873009160846966379) -->
+ <skip />
<string name="permlab_accessCallAudio" msgid="1682957511874097664">"Telefonikõnede heli salvestamine ja esitamine"</string>
<string name="permdesc_accessCallAudio" msgid="8448360894684277823">"Kui see rakendus on määratud helistamise vaikerakenduseks, lubatakse sellel salvestada ja esitada telefonikõnede heli."</string>
</resources>
diff --git a/core/res/res/values-eu/strings.xml b/core/res/res/values-eu/strings.xml
index 34cb6fbe8d3d..047e998bd489 100644
--- a/core/res/res/values-eu/strings.xml
+++ b/core/res/res/values-eu/strings.xml
@@ -249,10 +249,8 @@
<item quantity="other">Akatsen txostenaren argazkia aterako da <xliff:g id="NUMBER_1">%d</xliff:g> segundo barru.</item>
<item quantity="one">Akatsen txostenaren argazkia aterako da <xliff:g id="NUMBER_0">%d</xliff:g> segundo barru.</item>
</plurals>
- <!-- no translation found for bugreport_screenshot_success_toast (7986095104151473745) -->
- <skip />
- <!-- no translation found for bugreport_screenshot_failure_toast (6736320861311294294) -->
- <skip />
+ <string name="bugreport_screenshot_success_toast" msgid="7986095104151473745">"Pantaila-argazkia egin da akatsen txostenarekin"</string>
+ <string name="bugreport_screenshot_failure_toast" msgid="6736320861311294294">"Ezin izan da egin pantaila-argazkia akatsen txostenarekin"</string>
<string name="global_action_toggle_silent_mode" msgid="8464352592860372188">"Isilik modua"</string>
<string name="global_action_silent_mode_on_status" msgid="2371892537738632013">"Soinua DESAKTIBATUTA dago"</string>
<string name="global_action_silent_mode_off_status" msgid="6608006545950920042">"Soinua AKTIBATUTA dago"</string>
@@ -454,9 +452,11 @@
<string name="permdesc_acceptHandovers" msgid="7129026180128626870">"Beste aplikazio batean hasitako dei bat jarraitzea baimentzen dio aplikazioari."</string>
<string name="permlab_readPhoneNumbers" msgid="5668704794723365628">"irakurri telefono-zenbakiak"</string>
<string name="permdesc_readPhoneNumbers" msgid="7368652482818338871">"Gailuaren telefono-zenbakiak atzitzeko baimena ematen die aplikazioei."</string>
+ <string name="permlab_wakeLock" product="automotive" msgid="1904736682319375676">"mantendu piztuta autoko pantaila"</string>
<string name="permlab_wakeLock" product="tablet" msgid="1527660973931694000">"eragotzi tableta inaktibo ezartzea"</string>
<string name="permlab_wakeLock" product="tv" msgid="2856941418123343518">"Android TV gailua inaktibo ezar dadin eragotzi"</string>
<string name="permlab_wakeLock" product="default" msgid="569409726861695115">"eragotzi telefonoa inaktibo ezartzea"</string>
+ <string name="permdesc_wakeLock" product="automotive" msgid="5995045369683254571">"Autoko pantaila piztuta mantentzeko baimena ematen dio aplikazioari."</string>
<string name="permdesc_wakeLock" product="tablet" msgid="2441742939101526277">"Tableta inaktibo ezartzea galaraztea baimentzen die aplikazioei."</string>
<string name="permdesc_wakeLock" product="tv" msgid="2329298966735118796">"Android TV gailua inaktibo ezartzea eragozteko baimena ematen die aplikazioei."</string>
<string name="permdesc_wakeLock" product="default" msgid="3689523792074007163">"Telefonoa inaktibo ezartzea galaraztea baimentzen die aplikazioei."</string>
@@ -492,7 +492,7 @@
<string name="permdesc_changeWifiMulticastState" product="tablet" msgid="191079868596433554">"Wi-Fi sarearen bidez gailu guztiei bidalitako paketeak jasotzeko baimena ematen die aplikazioei multidifusio-helbideak erabilita, ez tableta soilik. Multidifusiokoa ez den moduak baino bateria gehiago erabiltzen du."</string>
<string name="permdesc_changeWifiMulticastState" product="tv" msgid="1336952358450652595">"Multidifusio-helbideak erabiliz wifi-sare bateko gailu guztiei (ez bakarrik Android TV gailuari) bidalitako paketeak jasotzeko baimena ematen die aplikazioei. Multidifusiokoa ez den moduak baino bateria gehiago erabiltzen du."</string>
<string name="permdesc_changeWifiMulticastState" product="default" msgid="8296627590220222740">"Wi-Fi sarearen bidez gailu guztiei bidalitako paketeak jasotzeko baimena ematen die aplikazioei multidifusio-helbideak erabilita, ez telefonoa soilik. Multidifusiokoa ez den moduak baino bateria gehiago erabiltzen du."</string>
- <string name="permlab_bluetoothAdmin" msgid="6490373569441946064">"atzitu Bluetooth ezarpenak"</string>
+ <string name="permlab_bluetoothAdmin" msgid="6490373569441946064">"atzitu Bluetooth-aren ezarpenak"</string>
<string name="permdesc_bluetoothAdmin" product="tablet" msgid="5370837055438574863">"Tokiko Bluetooth tableta konfiguratzea eta urruneko gailuak detektatzea eta haiekin parekatzea baimentzen die aplikazioei."</string>
<string name="permdesc_bluetoothAdmin" product="tv" msgid="1623992984547014588">"Android TV gailuan Bluetooth-a konfiguratzeko eta urruneko gailuak hautemateko eta haiekin parekatzeko baimena ematen die aplikazioei."</string>
<string name="permdesc_bluetoothAdmin" product="default" msgid="7381341743021234863">"Tokiko Bluetooth telefonoa konfiguratzea eta urruneko gailuak detektatzea eta haiekin parekatzea baimentzen die aplikazioei."</string>
@@ -1631,6 +1631,12 @@
<string name="safe_media_volume_warning" product="default" msgid="3751676824423049994">"Bolumena gomendatutako mailatik gora igo nahi duzu?\n\nMusika bolumen handian eta denbora luzez entzuteak entzumena kalte diezazuke."</string>
<string name="accessibility_shortcut_warning_dialog_title" msgid="4017995837692622933">"Erabilerraztasun-lasterbidea erabili nahi duzu?"</string>
<string name="accessibility_shortcut_toogle_warning" msgid="4161716521310929544">"Lasterbidea aktibatuta dagoenean, bi bolumen-botoiak hiru segundoz sakatuta abiaraziko da erabilerraztasun-eginbidea."</string>
+ <!-- no translation found for accessibility_select_shortcut_menu_title (7310194076629867377) -->
+ <skip />
+ <!-- no translation found for accessibility_edit_shortcut_menu_button_title (6096484087245145325) -->
+ <skip />
+ <!-- no translation found for accessibility_edit_shortcut_menu_volume_title (4849108668454490699) -->
+ <skip />
<string name="edit_accessibility_shortcut_menu_button" msgid="8885752738733772935">"Editatu lasterbideak"</string>
<string name="cancel_accessibility_shortcut_menu_button" msgid="1817413122335452474">"Utzi"</string>
<string name="disable_accessibility_shortcut" msgid="5806091378745232383">"Desaktibatu lasterbidea"</string>
@@ -1853,8 +1859,7 @@
<string name="default_notification_channel_label" msgid="3697928973567217330">"Kategoriarik gabea"</string>
<string name="importance_from_user" msgid="2782756722448800447">"Zuk ezarri duzu jakinarazpen hauen garrantzia."</string>
<string name="importance_from_person" msgid="4235804979664465383">"Garrantzitsua da eragiten dien pertsonengatik."</string>
- <!-- no translation found for notification_history_title_placeholder (7748630986182249599) -->
- <skip />
+ <string name="notification_history_title_placeholder" msgid="7748630986182249599">"Aplikazio-jakinarazpen pertsonalizatua"</string>
<string name="user_creation_account_exists" msgid="2239146360099708035">"<xliff:g id="ACCOUNT">%2$s</xliff:g> kontua duen erabiltzailea sortzeko baimena eman nahi diozu <xliff:g id="APP">%1$s</xliff:g> aplikazioari? (Badago kontu hori duen erabiltzaile bat)"</string>
<string name="user_creation_adding" msgid="7305185499667958364">"<xliff:g id="ACCOUNT">%2$s</xliff:g> kontua duen erabiltzailea sortzeko baimena eman nahi diozu <xliff:g id="APP">%1$s</xliff:g> aplikazioari?"</string>
<string name="language_selection_title" msgid="52674936078683285">"Gehitu hizkuntza"</string>
@@ -2028,14 +2033,29 @@
<string name="as_app_forced_to_restricted_bucket" msgid="8233871289353898964">"Murriztuen edukiontzian ezarri da <xliff:g id="PACKAGE_NAME">%1$s</xliff:g>"</string>
<string name="resolver_personal_tab" msgid="2051260504014442073">"Pertsonala"</string>
<string name="resolver_work_tab" msgid="2690019516263167035">"Lanekoa"</string>
+ <!-- no translation found for resolver_personal_tab_accessibility (5739524949153091224) -->
+ <skip />
+ <!-- no translation found for resolver_work_tab_accessibility (4753168230363802734) -->
+ <skip />
<string name="resolver_cant_share_with_work_apps" msgid="7539495559434146897">"Ezin da partekatu laneko aplikazioekin"</string>
<string name="resolver_cant_share_with_personal_apps" msgid="8020581735267157241">"Ezin da partekatu aplikazio pertsonalekin"</string>
- <string name="resolver_cant_share_cross_profile_explanation" msgid="3536237105241882679">"IKT administratzaileak blokeatu egin du edukia aplikazio pertsonalen eta laneko aplikazioen artean partekatzeko aukera"</string>
- <string name="resolver_turn_on_work_apps" msgid="8987359079870455469">"Aktibatu laneko aplikazioak"</string>
- <string name="resolver_turn_on_work_apps_explanation" msgid="6322467455509618928">"Aktibatu laneko aplikazioak, haiek eta kontaktuak atzitzeko"</string>
+ <!-- no translation found for resolver_cant_share_cross_profile_explanation (5556640604460901386) -->
+ <skip />
+ <!-- no translation found for resolver_cant_access_work_apps (375634344111233790) -->
+ <skip />
+ <!-- no translation found for resolver_cant_access_work_apps_explanation (3958762224516867388) -->
+ <skip />
+ <!-- no translation found for resolver_cant_access_personal_apps (1953215925406474177) -->
+ <skip />
+ <!-- no translation found for resolver_cant_access_personal_apps_explanation (1725572276741281136) -->
+ <skip />
+ <!-- no translation found for resolver_turn_on_work_apps_share (619263911204978175) -->
+ <skip />
+ <!-- no translation found for resolver_turn_on_work_apps_view (3073389230905543680) -->
+ <skip />
<string name="resolver_no_apps_available" msgid="7710339903040989654">"Ez dago aplikaziorik erabilgarri"</string>
- <string name="resolver_no_apps_available_explanation" msgid="4662694431121196560">"Ezin izan dugu aurkitu aplikaziorik"</string>
- <string name="resolver_switch_on_work" msgid="8294542702883688533">"Aktibatu laneko profila"</string>
+ <!-- no translation found for resolver_switch_on_work (2873009160846966379) -->
+ <skip />
<string name="permlab_accessCallAudio" msgid="1682957511874097664">"Grabatu edo erreproduzitu telefono-deietako audioa"</string>
<string name="permdesc_accessCallAudio" msgid="8448360894684277823">"Aplikazio hau markagailu lehenetsia denean, telefono-deietako audioa grabatu edo erreproduzitzeko aukera ematen dio."</string>
</resources>
diff --git a/core/res/res/values-fa/strings.xml b/core/res/res/values-fa/strings.xml
index 472bd0f1a64f..f3572dc91e6b 100644
--- a/core/res/res/values-fa/strings.xml
+++ b/core/res/res/values-fa/strings.xml
@@ -249,10 +249,8 @@
<item quantity="one">تا <xliff:g id="NUMBER_1">%d</xliff:g> ثانیه دیگر عکس صفحه‌نمایش برای گزارش اشکال گرفته می‌شود.</item>
<item quantity="other">تا <xliff:g id="NUMBER_1">%d</xliff:g> ثانیه دیگر عکس صفحه‌نمایش برای گزارش اشکال گرفته می‌شود.</item>
</plurals>
- <!-- no translation found for bugreport_screenshot_success_toast (7986095104151473745) -->
- <skip />
- <!-- no translation found for bugreport_screenshot_failure_toast (6736320861311294294) -->
- <skip />
+ <string name="bugreport_screenshot_success_toast" msgid="7986095104151473745">"نماگرفت با گزارش اشکال گرفته شد"</string>
+ <string name="bugreport_screenshot_failure_toast" msgid="6736320861311294294">"نماگرفت با گزارش اشکال گرفته نشد"</string>
<string name="global_action_toggle_silent_mode" msgid="8464352592860372188">"حالت ساکت"</string>
<string name="global_action_silent_mode_on_status" msgid="2371892537738632013">"صدا خاموش است"</string>
<string name="global_action_silent_mode_off_status" msgid="6608006545950920042">"صدا روشن است"</string>
@@ -454,9 +452,11 @@
<string name="permdesc_acceptHandovers" msgid="7129026180128626870">"به برنامه اجازه می‌دهد تماسی را که در برنامه دیگری شروع شده ادامه دهد."</string>
<string name="permlab_readPhoneNumbers" msgid="5668704794723365628">"خواندن شماره تلفن‌ها"</string>
<string name="permdesc_readPhoneNumbers" msgid="7368652482818338871">"به برنامه امکان می‌دهد به شماره تلفن‌های دستگاه دسترسی داشته باشد."</string>
+ <string name="permlab_wakeLock" product="automotive" msgid="1904736682319375676">"روشن نگه داشتن صفحه‌نمایش خودرو"</string>
<string name="permlab_wakeLock" product="tablet" msgid="1527660973931694000">"ممانعت از به خواب رفتن رایانهٔ لوحی"</string>
<string name="permlab_wakeLock" product="tv" msgid="2856941418123343518">"‏مانع از خوابیدن دستگاه Android TV می‌شود"</string>
<string name="permlab_wakeLock" product="default" msgid="569409726861695115">"ممانعت از به خواب رفتن تلفن"</string>
+ <string name="permdesc_wakeLock" product="automotive" msgid="5995045369683254571">"به برنامه اجازه می‌دهد صفحه‌نمایش خودرو را روشن نگه دارد."</string>
<string name="permdesc_wakeLock" product="tablet" msgid="2441742939101526277">"‏به برنامه اجازه می‎دهد تا از غیرفعال شدن رایانهٔ لوحی جلوگیری کند."</string>
<string name="permdesc_wakeLock" product="tv" msgid="2329298966735118796">"‏به برنامه اجازه می‎دهد مانع از به‌خواب رفتن دستگاه Android TV شود."</string>
<string name="permdesc_wakeLock" product="default" msgid="3689523792074007163">"‏به برنامه اجازه می‎دهد تا از غیرفعال شدن تلفن جلوگیری کند."</string>
@@ -1631,6 +1631,12 @@
<string name="safe_media_volume_warning" product="default" msgid="3751676824423049994">"میزان صدا را به بالاتر از حد توصیه شده افزایش می‌دهید؟\n\nگوش دادن به صداهای بلند برای مدت طولانی می‌تواند به شنوایی‌تان آسیب وارد کند."</string>
<string name="accessibility_shortcut_warning_dialog_title" msgid="4017995837692622933">"از میان‌بر دسترس‌پذیری استفاده شود؟"</string>
<string name="accessibility_shortcut_toogle_warning" msgid="4161716521310929544">"وقتی میان‌بر روشن باشد، با فشار دادن هردو دکمه صدا به‌مدت ۳ ثانیه ویژگی دسترس‌پذیری فعال می‌شود."</string>
+ <!-- no translation found for accessibility_select_shortcut_menu_title (7310194076629867377) -->
+ <skip />
+ <!-- no translation found for accessibility_edit_shortcut_menu_button_title (6096484087245145325) -->
+ <skip />
+ <!-- no translation found for accessibility_edit_shortcut_menu_volume_title (4849108668454490699) -->
+ <skip />
<string name="edit_accessibility_shortcut_menu_button" msgid="8885752738733772935">"ویرایش میان‌برها"</string>
<string name="cancel_accessibility_shortcut_menu_button" msgid="1817413122335452474">"لغو"</string>
<string name="disable_accessibility_shortcut" msgid="5806091378745232383">"خاموش کردن میان‌بر"</string>
@@ -1853,8 +1859,7 @@
<string name="default_notification_channel_label" msgid="3697928973567217330">"دسته‌بندی‌نشده"</string>
<string name="importance_from_user" msgid="2782756722448800447">"شما اهمیت این اعلان‌ها را تنظیم می‌کنید."</string>
<string name="importance_from_person" msgid="4235804979664465383">"به دلیل افراد درگیر مهم است."</string>
- <!-- no translation found for notification_history_title_placeholder (7748630986182249599) -->
- <skip />
+ <string name="notification_history_title_placeholder" msgid="7748630986182249599">"اعلان برنامه سفارشی"</string>
<string name="user_creation_account_exists" msgid="2239146360099708035">"به<xliff:g id="APP">%1$s</xliff:g> اجازه می‌دهید با <xliff:g id="ACCOUNT">%2$s</xliff:g> (کاربری با این حساب درحال‌حاضر وجود دارد) کاربری جدید ایجاد کند؟"</string>
<string name="user_creation_adding" msgid="7305185499667958364">"به <xliff:g id="APP">%1$s</xliff:g> اجازه می‌دهید با <xliff:g id="ACCOUNT">%2$s</xliff:g> کاربری جدید ایجاد کند؟"</string>
<string name="language_selection_title" msgid="52674936078683285">"افزودن زبان"</string>
@@ -2028,14 +2033,29 @@
<string name="as_app_forced_to_restricted_bucket" msgid="8233871289353898964">"<xliff:g id="PACKAGE_NAME">%1$s</xliff:g> در سطل «محدودشده» قرار گرفت"</string>
<string name="resolver_personal_tab" msgid="2051260504014442073">"شخصی"</string>
<string name="resolver_work_tab" msgid="2690019516263167035">"کاری"</string>
+ <!-- no translation found for resolver_personal_tab_accessibility (5739524949153091224) -->
+ <skip />
+ <!-- no translation found for resolver_work_tab_accessibility (4753168230363802734) -->
+ <skip />
<string name="resolver_cant_share_with_work_apps" msgid="7539495559434146897">"هم‌رسانی بااستفاده از «برنامه‌های کاری» امکان‌پذیر نیست"</string>
<string name="resolver_cant_share_with_personal_apps" msgid="8020581735267157241">"هم‌رسانی بااستفاده از برنامه‌های شخصی امکان‌پذیر نیست"</string>
- <string name="resolver_cant_share_cross_profile_explanation" msgid="3536237105241882679">"سرپرست فناوری اطلاعات شما هم‌رسانی بین برنامه‌های شخصی و کاری را مسدود کرده است"</string>
- <string name="resolver_turn_on_work_apps" msgid="8987359079870455469">"روشن کردن «برنامه‌های کاری»"</string>
- <string name="resolver_turn_on_work_apps_explanation" msgid="6322467455509618928">"برای دسترسی به برنامه‌های کاری و مخاطبین، «برنامه‌های کاری» را روشن کنید"</string>
+ <!-- no translation found for resolver_cant_share_cross_profile_explanation (5556640604460901386) -->
+ <skip />
+ <!-- no translation found for resolver_cant_access_work_apps (375634344111233790) -->
+ <skip />
+ <!-- no translation found for resolver_cant_access_work_apps_explanation (3958762224516867388) -->
+ <skip />
+ <!-- no translation found for resolver_cant_access_personal_apps (1953215925406474177) -->
+ <skip />
+ <!-- no translation found for resolver_cant_access_personal_apps_explanation (1725572276741281136) -->
+ <skip />
+ <!-- no translation found for resolver_turn_on_work_apps_share (619263911204978175) -->
+ <skip />
+ <!-- no translation found for resolver_turn_on_work_apps_view (3073389230905543680) -->
+ <skip />
<string name="resolver_no_apps_available" msgid="7710339903040989654">"هیچ برنامه‌ای در دسترس نیست"</string>
- <string name="resolver_no_apps_available_explanation" msgid="4662694431121196560">"هیچ برنامه‌ای پیدا نکردیم"</string>
- <string name="resolver_switch_on_work" msgid="8294542702883688533">"فعال کردن نمایه کاری"</string>
+ <!-- no translation found for resolver_switch_on_work (2873009160846966379) -->
+ <skip />
<string name="permlab_accessCallAudio" msgid="1682957511874097664">"ضبط یا پخش صدا در تماس‌های تلفنی"</string>
<string name="permdesc_accessCallAudio" msgid="8448360894684277823">"به این برنامه اجازه می‌دهد وقتی به‌عنوان برنامه شماره‌گیر پیش‌فرض تنظیم شده است، در تماس‌های تلفنی صدا ضبط یا پخش کند."</string>
</resources>
diff --git a/core/res/res/values-fi/strings.xml b/core/res/res/values-fi/strings.xml
index 6aa1a9bccbd5..a70d9a4d1a0a 100644
--- a/core/res/res/values-fi/strings.xml
+++ b/core/res/res/values-fi/strings.xml
@@ -249,10 +249,8 @@
<item quantity="other">Virheraporttiin otetaan kuvakaappaus <xliff:g id="NUMBER_1">%d</xliff:g> sekunnin kuluttua.</item>
<item quantity="one">Virheraporttiin otetaan kuvakaappaus <xliff:g id="NUMBER_0">%d</xliff:g> sekunnin kuluttua.</item>
</plurals>
- <!-- no translation found for bugreport_screenshot_success_toast (7986095104151473745) -->
- <skip />
- <!-- no translation found for bugreport_screenshot_failure_toast (6736320861311294294) -->
- <skip />
+ <string name="bugreport_screenshot_success_toast" msgid="7986095104151473745">"Kuvakaappaus otettu virheraportin kanssa"</string>
+ <string name="bugreport_screenshot_failure_toast" msgid="6736320861311294294">"Kuvakaappauksen ottaminen virheraportin kanssa epäonnistui"</string>
<string name="global_action_toggle_silent_mode" msgid="8464352592860372188">"Äänetön tila"</string>
<string name="global_action_silent_mode_on_status" msgid="2371892537738632013">"Äänet ovat POISSA KÄYTÖSTÄ"</string>
<string name="global_action_silent_mode_off_status" msgid="6608006545950920042">"Äänet ovat KÄYTÖSSÄ"</string>
@@ -454,9 +452,11 @@
<string name="permdesc_acceptHandovers" msgid="7129026180128626870">"Antaa sovelluksen jatkaa puhelua, joka aloitettiin toisessa sovelluksessa."</string>
<string name="permlab_readPhoneNumbers" msgid="5668704794723365628">"lukea puhelinnumeroita"</string>
<string name="permdesc_readPhoneNumbers" msgid="7368652482818338871">"Anna sovelluksen käyttää laitteella olevia puhelinnumeroita."</string>
+ <string name="permlab_wakeLock" product="automotive" msgid="1904736682319375676">"pitää auton näytön päällä"</string>
<string name="permlab_wakeLock" product="tablet" msgid="1527660973931694000">"estä tablet-laitetta menemästä virransäästötilaan"</string>
<string name="permlab_wakeLock" product="tv" msgid="2856941418123343518">"estää Android TV ‑laitetta siirtymästä virransäästötilaan"</string>
<string name="permlab_wakeLock" product="default" msgid="569409726861695115">"estä puhelinta menemästä virransäästötilaan"</string>
+ <string name="permdesc_wakeLock" product="automotive" msgid="5995045369683254571">"Sallii sovelluksen pitää auton näytön päällä."</string>
<string name="permdesc_wakeLock" product="tablet" msgid="2441742939101526277">"Antaa sovelluksen estää tablet-laitetta siirtymästä virransäästötilaan."</string>
<string name="permdesc_wakeLock" product="tv" msgid="2329298966735118796">"Antaa sovelluksen estää Android TV ‑laitetta siirtymästä virransäästötilaan."</string>
<string name="permdesc_wakeLock" product="default" msgid="3689523792074007163">"Antaa sovelluksen estää puhelinta siirtymästä virransäästötilaan."</string>
@@ -1631,6 +1631,12 @@
<string name="safe_media_volume_warning" product="default" msgid="3751676824423049994">"Nostetaanko äänenvoimakkuus suositellun tason yläpuolelle?\n\nPitkäkestoinen kova äänenvoimakkuus saattaa heikentää kuuloa."</string>
<string name="accessibility_shortcut_warning_dialog_title" msgid="4017995837692622933">"Käytetäänkö esteettömyyden pikanäppäintä?"</string>
<string name="accessibility_shortcut_toogle_warning" msgid="4161716521310929544">"Kun pikanäppäin on käytössä, voit käynnistää esteettömyystoiminnon pitämällä molempia äänenvoimakkuuspainikkeita painettuna kolmen sekunnin ajan."</string>
+ <!-- no translation found for accessibility_select_shortcut_menu_title (7310194076629867377) -->
+ <skip />
+ <!-- no translation found for accessibility_edit_shortcut_menu_button_title (6096484087245145325) -->
+ <skip />
+ <!-- no translation found for accessibility_edit_shortcut_menu_volume_title (4849108668454490699) -->
+ <skip />
<string name="edit_accessibility_shortcut_menu_button" msgid="8885752738733772935">"Muokkaa pikakuvakkeita"</string>
<string name="cancel_accessibility_shortcut_menu_button" msgid="1817413122335452474">"Peruuta"</string>
<string name="disable_accessibility_shortcut" msgid="5806091378745232383">"Poista pikanäppäin käytöstä"</string>
@@ -1853,8 +1859,7 @@
<string name="default_notification_channel_label" msgid="3697928973567217330">"Luokittelematon"</string>
<string name="importance_from_user" msgid="2782756722448800447">"Voit valita näiden ilmoitusten tärkeyden."</string>
<string name="importance_from_person" msgid="4235804979664465383">"Tämä on tärkeää siihen liittyvien ihmisten perusteella."</string>
- <!-- no translation found for notification_history_title_placeholder (7748630986182249599) -->
- <skip />
+ <string name="notification_history_title_placeholder" msgid="7748630986182249599">"Oma sovellusilmoitus"</string>
<string name="user_creation_account_exists" msgid="2239146360099708035">"Saako <xliff:g id="APP">%1$s</xliff:g> luoda uuden käyttäjän (<xliff:g id="ACCOUNT">%2$s</xliff:g>) – tällä käyttäjällä on jo tili?"</string>
<string name="user_creation_adding" msgid="7305185499667958364">"Saako <xliff:g id="APP">%1$s</xliff:g> luoda uuden käyttäjän (<xliff:g id="ACCOUNT">%2$s</xliff:g>)?"</string>
<string name="language_selection_title" msgid="52674936078683285">"Lisää kieli"</string>
@@ -2028,14 +2033,29 @@
<string name="as_app_forced_to_restricted_bucket" msgid="8233871289353898964">"<xliff:g id="PACKAGE_NAME">%1$s</xliff:g> on nyt rajoitettujen ryhmässä"</string>
<string name="resolver_personal_tab" msgid="2051260504014442073">"Henkilökohtainen"</string>
<string name="resolver_work_tab" msgid="2690019516263167035">"Työ"</string>
+ <!-- no translation found for resolver_personal_tab_accessibility (5739524949153091224) -->
+ <skip />
+ <!-- no translation found for resolver_work_tab_accessibility (4753168230363802734) -->
+ <skip />
<string name="resolver_cant_share_with_work_apps" msgid="7539495559434146897">"Ei voi jakaa työsovellusten kanssa"</string>
<string name="resolver_cant_share_with_personal_apps" msgid="8020581735267157241">"Ei voi jakaa henkilökohtaisten sovellusten kanssa"</string>
- <string name="resolver_cant_share_cross_profile_explanation" msgid="3536237105241882679">"IT-järjestelmänvalvojasi esti jakamisen henkilökohtaisten ja työsovellusten välillä"</string>
- <string name="resolver_turn_on_work_apps" msgid="8987359079870455469">"Ota työsovellukset käyttöön"</string>
- <string name="resolver_turn_on_work_apps_explanation" msgid="6322467455509618928">"Ota työsovellukset käyttöön päästäksesi työsovelluksiin ja yhteystietoihin"</string>
+ <!-- no translation found for resolver_cant_share_cross_profile_explanation (5556640604460901386) -->
+ <skip />
+ <!-- no translation found for resolver_cant_access_work_apps (375634344111233790) -->
+ <skip />
+ <!-- no translation found for resolver_cant_access_work_apps_explanation (3958762224516867388) -->
+ <skip />
+ <!-- no translation found for resolver_cant_access_personal_apps (1953215925406474177) -->
+ <skip />
+ <!-- no translation found for resolver_cant_access_personal_apps_explanation (1725572276741281136) -->
+ <skip />
+ <!-- no translation found for resolver_turn_on_work_apps_share (619263911204978175) -->
+ <skip />
+ <!-- no translation found for resolver_turn_on_work_apps_view (3073389230905543680) -->
+ <skip />
<string name="resolver_no_apps_available" msgid="7710339903040989654">"Sovelluksia ei ole käytettävissä"</string>
- <string name="resolver_no_apps_available_explanation" msgid="4662694431121196560">"Sovelluksia ei löytynyt"</string>
- <string name="resolver_switch_on_work" msgid="8294542702883688533">"Ota työprofiili käyttöön"</string>
+ <!-- no translation found for resolver_switch_on_work (2873009160846966379) -->
+ <skip />
<string name="permlab_accessCallAudio" msgid="1682957511874097664">"Äänen tallentaminen tai toistaminen puheluiden aikana"</string>
<string name="permdesc_accessCallAudio" msgid="8448360894684277823">"Sallii tämän sovelluksen tallentaa tai toistaa ääntä puheluiden aikana, kun sovellus on valittu oletuspuhelusovellukseksi."</string>
</resources>
diff --git a/core/res/res/values-fr-rCA/strings.xml b/core/res/res/values-fr-rCA/strings.xml
index 6f47049851d9..af4be33a76cb 100644
--- a/core/res/res/values-fr-rCA/strings.xml
+++ b/core/res/res/values-fr-rCA/strings.xml
@@ -249,10 +249,8 @@
<item quantity="one">Saisie d\'écran pour le rapport de bogue dans <xliff:g id="NUMBER_1">%d</xliff:g> seconde.</item>
<item quantity="other">Saisie d\'écran pour le rapport de bogue dans <xliff:g id="NUMBER_1">%d</xliff:g> secondes.</item>
</plurals>
- <!-- no translation found for bugreport_screenshot_success_toast (7986095104151473745) -->
- <skip />
- <!-- no translation found for bugreport_screenshot_failure_toast (6736320861311294294) -->
- <skip />
+ <string name="bugreport_screenshot_success_toast" msgid="7986095104151473745">"Capture d\'écran prise avec le rapport de bogue"</string>
+ <string name="bugreport_screenshot_failure_toast" msgid="6736320861311294294">"Échec de la prise de capture d\'écran avec le rapport de bogue"</string>
<string name="global_action_toggle_silent_mode" msgid="8464352592860372188">"Mode silencieux"</string>
<string name="global_action_silent_mode_on_status" msgid="2371892537738632013">"Le son est désactivé."</string>
<string name="global_action_silent_mode_off_status" msgid="6608006545950920042">"Le son est activé."</string>
@@ -454,9 +452,11 @@
<string name="permdesc_acceptHandovers" msgid="7129026180128626870">"Permet à l\'application de continuer un appel commencé dans une autre application."</string>
<string name="permlab_readPhoneNumbers" msgid="5668704794723365628">"lire les numéros de téléphone"</string>
<string name="permdesc_readPhoneNumbers" msgid="7368652482818338871">"Permet à l\'application d\'accéder aux numéros de téléphone de l\'appareil."</string>
+ <string name="permlab_wakeLock" product="automotive" msgid="1904736682319375676">"garder l\'écran de la voiture allumé"</string>
<string name="permlab_wakeLock" product="tablet" msgid="1527660973931694000">"empêcher la tablette de passer en mode veille"</string>
<string name="permlab_wakeLock" product="tv" msgid="2856941418123343518">"Empêcher votre appareil Android TV de passer en mode Veille"</string>
<string name="permlab_wakeLock" product="default" msgid="569409726861695115">"empêcher le téléphone de passer en mode veille"</string>
+ <string name="permdesc_wakeLock" product="automotive" msgid="5995045369683254571">"Permet à l\'application de garder l\'écran de la voiture allumé."</string>
<string name="permdesc_wakeLock" product="tablet" msgid="2441742939101526277">"Permet à l\'application d\'empêcher la tablette de passer en mode veille."</string>
<string name="permdesc_wakeLock" product="tv" msgid="2329298966735118796">"Permet à l\'application d\'empêcher votre appareil Android TV de passer en mode Veille."</string>
<string name="permdesc_wakeLock" product="default" msgid="3689523792074007163">"Permet à l\'application d\'empêcher le téléphone de passer en mode veille."</string>
@@ -1631,6 +1631,12 @@
<string name="safe_media_volume_warning" product="default" msgid="3751676824423049994">"Augmenter le volume au-dessus du niveau recommandé?\n\nL\'écoute prolongée à un volume élevé peut endommager vos facultés auditives."</string>
<string name="accessibility_shortcut_warning_dialog_title" msgid="4017995837692622933">"Utiliser le raccourci d\'accessibilité?"</string>
<string name="accessibility_shortcut_toogle_warning" msgid="4161716521310929544">"Quand le raccourci est activé, appuyez sur les deux boutons de volume pendant trois secondes pour lancer une fonctionnalité d\'accessibilité."</string>
+ <!-- no translation found for accessibility_select_shortcut_menu_title (7310194076629867377) -->
+ <skip />
+ <!-- no translation found for accessibility_edit_shortcut_menu_button_title (6096484087245145325) -->
+ <skip />
+ <!-- no translation found for accessibility_edit_shortcut_menu_volume_title (4849108668454490699) -->
+ <skip />
<string name="edit_accessibility_shortcut_menu_button" msgid="8885752738733772935">"Modifier les raccourcis"</string>
<string name="cancel_accessibility_shortcut_menu_button" msgid="1817413122335452474">"Annuler"</string>
<string name="disable_accessibility_shortcut" msgid="5806091378745232383">"Désactiver le raccourci"</string>
@@ -1853,8 +1859,7 @@
<string name="default_notification_channel_label" msgid="3697928973567217330">"Sans catégorie"</string>
<string name="importance_from_user" msgid="2782756722448800447">"Vous définissez l\'importance de ces notifications."</string>
<string name="importance_from_person" msgid="4235804979664465383">"Ces notifications sont importantes en raison des participants."</string>
- <!-- no translation found for notification_history_title_placeholder (7748630986182249599) -->
- <skip />
+ <string name="notification_history_title_placeholder" msgid="7748630986182249599">"Notification d\'application personnalisée"</string>
<string name="user_creation_account_exists" msgid="2239146360099708035">"Autoriser <xliff:g id="APP">%1$s</xliff:g> à créer un utilisateur <xliff:g id="ACCOUNT">%2$s</xliff:g>? (Un utilisateur est déjà associé à ce compte)"</string>
<string name="user_creation_adding" msgid="7305185499667958364">"Autoriser <xliff:g id="APP">%1$s</xliff:g> à créer un profil d\'utilisateur avec le compte <xliff:g id="ACCOUNT">%2$s</xliff:g>?"</string>
<string name="language_selection_title" msgid="52674936078683285">"Ajouter une langue"</string>
@@ -2028,14 +2033,29 @@
<string name="as_app_forced_to_restricted_bucket" msgid="8233871289353898964">"<xliff:g id="PACKAGE_NAME">%1$s</xliff:g> a été placé dans le compartiment RESTREINT"</string>
<string name="resolver_personal_tab" msgid="2051260504014442073">"Personnel"</string>
<string name="resolver_work_tab" msgid="2690019516263167035">"Bureau"</string>
+ <!-- no translation found for resolver_personal_tab_accessibility (5739524949153091224) -->
+ <skip />
+ <!-- no translation found for resolver_work_tab_accessibility (4753168230363802734) -->
+ <skip />
<string name="resolver_cant_share_with_work_apps" msgid="7539495559434146897">"Partage impossible avec les applications professionnelles"</string>
<string name="resolver_cant_share_with_personal_apps" msgid="8020581735267157241">"Partage impossible avec les applications personnelles"</string>
- <string name="resolver_cant_share_cross_profile_explanation" msgid="3536237105241882679">"Votre administrateur informatique a bloqué le partage entre vos applications personnelles et professionnelles"</string>
- <string name="resolver_turn_on_work_apps" msgid="8987359079870455469">"Activer les applications professionnelles"</string>
- <string name="resolver_turn_on_work_apps_explanation" msgid="6322467455509618928">"Activez les applications professionnelles pour accéder à celles-ci ainsi qu\'à vos contacts professionnels"</string>
+ <!-- no translation found for resolver_cant_share_cross_profile_explanation (5556640604460901386) -->
+ <skip />
+ <!-- no translation found for resolver_cant_access_work_apps (375634344111233790) -->
+ <skip />
+ <!-- no translation found for resolver_cant_access_work_apps_explanation (3958762224516867388) -->
+ <skip />
+ <!-- no translation found for resolver_cant_access_personal_apps (1953215925406474177) -->
+ <skip />
+ <!-- no translation found for resolver_cant_access_personal_apps_explanation (1725572276741281136) -->
+ <skip />
+ <!-- no translation found for resolver_turn_on_work_apps_share (619263911204978175) -->
+ <skip />
+ <!-- no translation found for resolver_turn_on_work_apps_view (3073389230905543680) -->
+ <skip />
<string name="resolver_no_apps_available" msgid="7710339903040989654">"Aucune application disponible"</string>
- <string name="resolver_no_apps_available_explanation" msgid="4662694431121196560">"Nous n\'avons trouvé aucune application"</string>
- <string name="resolver_switch_on_work" msgid="8294542702883688533">"Activer le profil professionnel"</string>
+ <!-- no translation found for resolver_switch_on_work (2873009160846966379) -->
+ <skip />
<string name="permlab_accessCallAudio" msgid="1682957511874097664">"Enregistrer ou lire du contenu audio lors des appels téléphoniques"</string>
<string name="permdesc_accessCallAudio" msgid="8448360894684277823">"Permet à cette application, lorsqu\'elle est définie comme composeur par défaut, d\'enregistrer ou de lire du contenu audio lors des appels téléphoniques."</string>
</resources>
diff --git a/core/res/res/values-fr/strings.xml b/core/res/res/values-fr/strings.xml
index 20f0406ebb7a..f4309baef826 100644
--- a/core/res/res/values-fr/strings.xml
+++ b/core/res/res/values-fr/strings.xml
@@ -249,10 +249,8 @@
<item quantity="one">Capture d\'écran pour le rapport de bug dans <xliff:g id="NUMBER_1">%d</xliff:g> seconde</item>
<item quantity="other">Capture d\'écran pour le rapport de bug dans <xliff:g id="NUMBER_1">%d</xliff:g> secondes</item>
</plurals>
- <!-- no translation found for bugreport_screenshot_success_toast (7986095104151473745) -->
- <skip />
- <!-- no translation found for bugreport_screenshot_failure_toast (6736320861311294294) -->
- <skip />
+ <string name="bugreport_screenshot_success_toast" msgid="7986095104151473745">"Capture d\'écran avec rapport de bug effectuée"</string>
+ <string name="bugreport_screenshot_failure_toast" msgid="6736320861311294294">"Échec de la capture d\'écran avec le rapport de bug"</string>
<string name="global_action_toggle_silent_mode" msgid="8464352592860372188">"Mode silencieux"</string>
<string name="global_action_silent_mode_on_status" msgid="2371892537738632013">"Le son est désactivé."</string>
<string name="global_action_silent_mode_off_status" msgid="6608006545950920042">"Le son est activé."</string>
@@ -454,9 +452,11 @@
<string name="permdesc_acceptHandovers" msgid="7129026180128626870">"Autorise l\'application à continuer un appel qui a été démarré dans une autre application."</string>
<string name="permlab_readPhoneNumbers" msgid="5668704794723365628">"lire les numéros de téléphone"</string>
<string name="permdesc_readPhoneNumbers" msgid="7368652482818338871">"Permet à l\'application d\'accéder aux numéros de téléphone de l\'appareil."</string>
+ <string name="permlab_wakeLock" product="automotive" msgid="1904736682319375676">"laisser l\'écran de la voiture allumé"</string>
<string name="permlab_wakeLock" product="tablet" msgid="1527660973931694000">"empêcher la tablette de passer en mode veille"</string>
<string name="permlab_wakeLock" product="tv" msgid="2856941418123343518">"Empêcher votre appareil Android TV de passer en mode veille"</string>
<string name="permlab_wakeLock" product="default" msgid="569409726861695115">"empêcher le téléphone de passer en mode veille"</string>
+ <string name="permdesc_wakeLock" product="automotive" msgid="5995045369683254571">"Permet à l\'application de laisser l\'écran de la voiture allumé."</string>
<string name="permdesc_wakeLock" product="tablet" msgid="2441742939101526277">"Permet à l\'application d\'empêcher la tablette de passer en mode veille."</string>
<string name="permdesc_wakeLock" product="tv" msgid="2329298966735118796">"Permet à l\'application d\'empêcher votre appareil Android TV de passer en mode veille."</string>
<string name="permdesc_wakeLock" product="default" msgid="3689523792074007163">"Permet à l\'application d\'empêcher le téléphone de passer en mode veille."</string>
@@ -1631,6 +1631,12 @@
<string name="safe_media_volume_warning" product="default" msgid="3751676824423049994">"Augmenter le volume au dessus du niveau recommandé ?\n\nL\'écoute prolongée à un volume élevé peut endommager vos facultés auditives."</string>
<string name="accessibility_shortcut_warning_dialog_title" msgid="4017995837692622933">"Utiliser le raccourci d\'accessibilité ?"</string>
<string name="accessibility_shortcut_toogle_warning" msgid="4161716521310929544">"Quand le raccourci est activé, appuyez sur les deux boutons de volume pendant trois secondes pour démarrer une fonctionnalité d\'accessibilité."</string>
+ <!-- no translation found for accessibility_select_shortcut_menu_title (7310194076629867377) -->
+ <skip />
+ <!-- no translation found for accessibility_edit_shortcut_menu_button_title (6096484087245145325) -->
+ <skip />
+ <!-- no translation found for accessibility_edit_shortcut_menu_volume_title (4849108668454490699) -->
+ <skip />
<string name="edit_accessibility_shortcut_menu_button" msgid="8885752738733772935">"Modifier les raccourcis"</string>
<string name="cancel_accessibility_shortcut_menu_button" msgid="1817413122335452474">"Annuler"</string>
<string name="disable_accessibility_shortcut" msgid="5806091378745232383">"Désactiver le raccourci"</string>
@@ -1853,8 +1859,7 @@
<string name="default_notification_channel_label" msgid="3697928973567217330">"Sans catégorie"</string>
<string name="importance_from_user" msgid="2782756722448800447">"Vous définissez l\'importance de ces notifications."</string>
<string name="importance_from_person" msgid="4235804979664465383">"Ces notifications sont importantes en raison des participants."</string>
- <!-- no translation found for notification_history_title_placeholder (7748630986182249599) -->
- <skip />
+ <string name="notification_history_title_placeholder" msgid="7748630986182249599">"Notification d\'application personnalisée"</string>
<string name="user_creation_account_exists" msgid="2239146360099708035">"Autoriser <xliff:g id="APP">%1$s</xliff:g> à créer un profil utilisateur avec le compte <xliff:g id="ACCOUNT">%2$s</xliff:g> (un utilisateur associé à ce compte existe déjà) ?"</string>
<string name="user_creation_adding" msgid="7305185499667958364">"Autoriser <xliff:g id="APP">%1$s</xliff:g> à créer un profil utilisateur avec le compte <xliff:g id="ACCOUNT">%2$s</xliff:g> ?"</string>
<string name="language_selection_title" msgid="52674936078683285">"Ajouter une langue"</string>
@@ -2028,14 +2033,29 @@
<string name="as_app_forced_to_restricted_bucket" msgid="8233871289353898964">"<xliff:g id="PACKAGE_NAME">%1$s</xliff:g> a été placé dans le bucket RESTRICTED"</string>
<string name="resolver_personal_tab" msgid="2051260504014442073">"Personnel"</string>
<string name="resolver_work_tab" msgid="2690019516263167035">"Professionnel"</string>
+ <!-- no translation found for resolver_personal_tab_accessibility (5739524949153091224) -->
+ <skip />
+ <!-- no translation found for resolver_work_tab_accessibility (4753168230363802734) -->
+ <skip />
<string name="resolver_cant_share_with_work_apps" msgid="7539495559434146897">"Partage impossible avec les applications professionnelles"</string>
<string name="resolver_cant_share_with_personal_apps" msgid="8020581735267157241">"Partage impossible avec les applications personnelles"</string>
- <string name="resolver_cant_share_cross_profile_explanation" msgid="3536237105241882679">"Votre administrateur informatique a bloqué le partage entre vos applications personnelles et professionnelles"</string>
- <string name="resolver_turn_on_work_apps" msgid="8987359079870455469">"Activer les applications professionnelles"</string>
- <string name="resolver_turn_on_work_apps_explanation" msgid="6322467455509618928">"Activez les applications professionnelles pour accéder à celles-ci ainsi qu\'à vos contacts pour le travail"</string>
+ <!-- no translation found for resolver_cant_share_cross_profile_explanation (5556640604460901386) -->
+ <skip />
+ <!-- no translation found for resolver_cant_access_work_apps (375634344111233790) -->
+ <skip />
+ <!-- no translation found for resolver_cant_access_work_apps_explanation (3958762224516867388) -->
+ <skip />
+ <!-- no translation found for resolver_cant_access_personal_apps (1953215925406474177) -->
+ <skip />
+ <!-- no translation found for resolver_cant_access_personal_apps_explanation (1725572276741281136) -->
+ <skip />
+ <!-- no translation found for resolver_turn_on_work_apps_share (619263911204978175) -->
+ <skip />
+ <!-- no translation found for resolver_turn_on_work_apps_view (3073389230905543680) -->
+ <skip />
<string name="resolver_no_apps_available" msgid="7710339903040989654">"Aucune application disponible"</string>
- <string name="resolver_no_apps_available_explanation" msgid="4662694431121196560">"Aucune application détectée"</string>
- <string name="resolver_switch_on_work" msgid="8294542702883688533">"Activer le profil professionnel"</string>
+ <!-- no translation found for resolver_switch_on_work (2873009160846966379) -->
+ <skip />
<string name="permlab_accessCallAudio" msgid="1682957511874097664">"Enregistrer ou lire du contenu audio lors des appels téléphoniques"</string>
<string name="permdesc_accessCallAudio" msgid="8448360894684277823">"Permet à cette application d\'enregistrer ou de lire du contenu audio lors des appels téléphoniques lorsqu\'elle est définie comme clavier par défaut."</string>
</resources>
diff --git a/core/res/res/values-gl/strings.xml b/core/res/res/values-gl/strings.xml
index cee03a1ad806..838ea9e26a60 100644
--- a/core/res/res/values-gl/strings.xml
+++ b/core/res/res/values-gl/strings.xml
@@ -249,10 +249,8 @@
<item quantity="other">Vaise facer unha captura de pantalla para o informe de erros en <xliff:g id="NUMBER_1">%d</xliff:g> segundos.</item>
<item quantity="one">Vaise facer unha captura de pantalla para o informe de erros en <xliff:g id="NUMBER_0">%d</xliff:g> segundo.</item>
</plurals>
- <!-- no translation found for bugreport_screenshot_success_toast (7986095104151473745) -->
- <skip />
- <!-- no translation found for bugreport_screenshot_failure_toast (6736320861311294294) -->
- <skip />
+ <string name="bugreport_screenshot_success_toast" msgid="7986095104151473745">"Realizouse a captura de pantalla co informe de erros"</string>
+ <string name="bugreport_screenshot_failure_toast" msgid="6736320861311294294">"Produciuse un erro ao realizar a captura de pantalla co informe de erros"</string>
<string name="global_action_toggle_silent_mode" msgid="8464352592860372188">"Modo de silencio"</string>
<string name="global_action_silent_mode_on_status" msgid="2371892537738632013">"O son está desactivado"</string>
<string name="global_action_silent_mode_off_status" msgid="6608006545950920042">"O son está activado"</string>
@@ -454,9 +452,11 @@
<string name="permdesc_acceptHandovers" msgid="7129026180128626870">"Permite que a aplicación continúe unha chamada que se iniciou noutra aplicación."</string>
<string name="permlab_readPhoneNumbers" msgid="5668704794723365628">"ler números de teléfono"</string>
<string name="permdesc_readPhoneNumbers" msgid="7368652482818338871">"Permite que a aplicación acceda aos números de teléfono do dispositivo."</string>
+ <string name="permlab_wakeLock" product="automotive" msgid="1904736682319375676">"manter acendida a pantalla do coche"</string>
<string name="permlab_wakeLock" product="tablet" msgid="1527660973931694000">"evitar que a tableta entre en modo de inactividade"</string>
<string name="permlab_wakeLock" product="tv" msgid="2856941418123343518">"evitar que o dispositivo Android TV entre en modo de suspensión"</string>
<string name="permlab_wakeLock" product="default" msgid="569409726861695115">"evitar que o teléfono entre en modo de suspensión"</string>
+ <string name="permdesc_wakeLock" product="automotive" msgid="5995045369683254571">"Permite que a aplicación manteña acendida a pantalla do coche."</string>
<string name="permdesc_wakeLock" product="tablet" msgid="2441742939101526277">"Permite á aplicación evitar que a tableta acceda ao modo de suspensión."</string>
<string name="permdesc_wakeLock" product="tv" msgid="2329298966735118796">"Permite que a aplicación evite que o dispositivo Android TV entre en modo de suspensión."</string>
<string name="permdesc_wakeLock" product="default" msgid="3689523792074007163">"Permite á aplicación evitar que o teléfono acceda ao modo de suspensión."</string>
@@ -1631,6 +1631,12 @@
<string name="safe_media_volume_warning" product="default" msgid="3751676824423049994">"Queres subir o volume máis do nivel recomendado?\n\nA reprodución de son a un volume elevado durante moito tempo pode provocar danos nos oídos."</string>
<string name="accessibility_shortcut_warning_dialog_title" msgid="4017995837692622933">"Queres utilizar o atallo de accesibilidade?"</string>
<string name="accessibility_shortcut_toogle_warning" msgid="4161716521310929544">"Cando o atallo está activado, podes premer os dous botóns de volume durante 3 segundos para iniciar unha función de accesibilidade."</string>
+ <!-- no translation found for accessibility_select_shortcut_menu_title (7310194076629867377) -->
+ <skip />
+ <!-- no translation found for accessibility_edit_shortcut_menu_button_title (6096484087245145325) -->
+ <skip />
+ <!-- no translation found for accessibility_edit_shortcut_menu_volume_title (4849108668454490699) -->
+ <skip />
<string name="edit_accessibility_shortcut_menu_button" msgid="8885752738733772935">"Editar atallos"</string>
<string name="cancel_accessibility_shortcut_menu_button" msgid="1817413122335452474">"Cancelar"</string>
<string name="disable_accessibility_shortcut" msgid="5806091378745232383">"Desactivar atallo"</string>
@@ -1853,8 +1859,7 @@
<string name="default_notification_channel_label" msgid="3697928973567217330">"Sen clasificar"</string>
<string name="importance_from_user" msgid="2782756722448800447">"Ti defines a importancia destas notificacións."</string>
<string name="importance_from_person" msgid="4235804979664465383">"É importante polas persoas involucradas."</string>
- <!-- no translation found for notification_history_title_placeholder (7748630986182249599) -->
- <skip />
+ <string name="notification_history_title_placeholder" msgid="7748630986182249599">"Notificación de aplicacións personalizada"</string>
<string name="user_creation_account_exists" msgid="2239146360099708035">"Queres permitir que <xliff:g id="APP">%1$s</xliff:g> cree un usuario novo con <xliff:g id="ACCOUNT">%2$s</xliff:g>? (Xa existe un usuario con esta conta)"</string>
<string name="user_creation_adding" msgid="7305185499667958364">"Queres permitir que <xliff:g id="APP">%1$s</xliff:g> cree un usuario novo con <xliff:g id="ACCOUNT">%2$s</xliff:g>?"</string>
<string name="language_selection_title" msgid="52674936078683285">"Engadir un idioma"</string>
@@ -2028,14 +2033,29 @@
<string name="as_app_forced_to_restricted_bucket" msgid="8233871289353898964">"<xliff:g id="PACKAGE_NAME">%1$s</xliff:g> incluíuse no grupo RESTRINXIDO"</string>
<string name="resolver_personal_tab" msgid="2051260504014442073">"Persoal"</string>
<string name="resolver_work_tab" msgid="2690019516263167035">"Traballo"</string>
+ <!-- no translation found for resolver_personal_tab_accessibility (5739524949153091224) -->
+ <skip />
+ <!-- no translation found for resolver_work_tab_accessibility (4753168230363802734) -->
+ <skip />
<string name="resolver_cant_share_with_work_apps" msgid="7539495559434146897">"Non se pode compartir información coas aplicacións do traballo"</string>
<string name="resolver_cant_share_with_personal_apps" msgid="8020581735267157241">"Non se pode compartir información coas aplicacións persoais"</string>
- <string name="resolver_cant_share_cross_profile_explanation" msgid="3536237105241882679">"O teu administrador de TI bloqueou a función de compartir información entre as aplicacións persoais e as do traballo"</string>
- <string name="resolver_turn_on_work_apps" msgid="8987359079870455469">"Activa as aplicacións do traballo"</string>
- <string name="resolver_turn_on_work_apps_explanation" msgid="6322467455509618928">"Activa as aplicacións do traballo para acceder a elas e aos contactos do traballo"</string>
+ <!-- no translation found for resolver_cant_share_cross_profile_explanation (5556640604460901386) -->
+ <skip />
+ <!-- no translation found for resolver_cant_access_work_apps (375634344111233790) -->
+ <skip />
+ <!-- no translation found for resolver_cant_access_work_apps_explanation (3958762224516867388) -->
+ <skip />
+ <!-- no translation found for resolver_cant_access_personal_apps (1953215925406474177) -->
+ <skip />
+ <!-- no translation found for resolver_cant_access_personal_apps_explanation (1725572276741281136) -->
+ <skip />
+ <!-- no translation found for resolver_turn_on_work_apps_share (619263911204978175) -->
+ <skip />
+ <!-- no translation found for resolver_turn_on_work_apps_view (3073389230905543680) -->
+ <skip />
<string name="resolver_no_apps_available" msgid="7710339903040989654">"Non hai aplicacións dispoñibles"</string>
- <string name="resolver_no_apps_available_explanation" msgid="4662694431121196560">"Non se puideron atopar aplicacións"</string>
- <string name="resolver_switch_on_work" msgid="8294542702883688533">"Activar perfil do traballo"</string>
+ <!-- no translation found for resolver_switch_on_work (2873009160846966379) -->
+ <skip />
<string name="permlab_accessCallAudio" msgid="1682957511874097664">"Gravar ou reproducir audio en chamadas telefónicas"</string>
<string name="permdesc_accessCallAudio" msgid="8448360894684277823">"Permite que esta aplicación, cando está asignada como aplicación predeterminada do marcador, grave e reproduza audio en chamadas telefónicas."</string>
</resources>
diff --git a/core/res/res/values-gu/strings.xml b/core/res/res/values-gu/strings.xml
index c718124356d8..6dba380aee47 100644
--- a/core/res/res/values-gu/strings.xml
+++ b/core/res/res/values-gu/strings.xml
@@ -249,10 +249,8 @@
<item quantity="one">બગ રિપોર્ટ માટે <xliff:g id="NUMBER_1">%d</xliff:g> સેકન્ડમાં સ્ક્રીનશોટ લઈ રહ્યાં છે.</item>
<item quantity="other">બગ રિપોર્ટ માટે <xliff:g id="NUMBER_1">%d</xliff:g> સેકન્ડમાં સ્ક્રીનશોટ લઈ રહ્યાં છે.</item>
</plurals>
- <!-- no translation found for bugreport_screenshot_success_toast (7986095104151473745) -->
- <skip />
- <!-- no translation found for bugreport_screenshot_failure_toast (6736320861311294294) -->
- <skip />
+ <string name="bugreport_screenshot_success_toast" msgid="7986095104151473745">"ખામીની જાણકારી સાથે સ્ક્રીનશૉટ લેવામાં આવ્યો"</string>
+ <string name="bugreport_screenshot_failure_toast" msgid="6736320861311294294">"ખામીની જાણકારી સાથે સ્ક્રીનશૉટ લેવામાં નિષ્ફળ થયા"</string>
<string name="global_action_toggle_silent_mode" msgid="8464352592860372188">"સાઇલેન્ટ મોડ"</string>
<string name="global_action_silent_mode_on_status" msgid="2371892537738632013">"અવાજ બંધ છે"</string>
<string name="global_action_silent_mode_off_status" msgid="6608006545950920042">"ધ્વનિ ચાલુ છે"</string>
@@ -454,9 +452,11 @@
<string name="permdesc_acceptHandovers" msgid="7129026180128626870">"એક અન્ય તૃતીય પક્ષ ઍપમાં ચાલુ થયેલા કૉલને આ ઍપમાં ચાલુ રાખવાની મંજૂરી આપે છે."</string>
<string name="permlab_readPhoneNumbers" msgid="5668704794723365628">"ફોન નંબર વાંચો"</string>
<string name="permdesc_readPhoneNumbers" msgid="7368652482818338871">"ઍપ્લિકેશનને ઉપકરણનાં ફોન નંબરને ઍક્સેસ કરવાની મંજૂરી આપે છે."</string>
+ <string name="permlab_wakeLock" product="automotive" msgid="1904736682319375676">"કારની સ્ક્રીન ચાલુ રાખો."</string>
<string name="permlab_wakeLock" product="tablet" msgid="1527660973931694000">"ટેબ્લેટને નિષ્ક્રિય થતું અટકાવો"</string>
<string name="permlab_wakeLock" product="tv" msgid="2856941418123343518">"તમારા Android TV ડિવાઇસને નિષ્ક્રિય થવાથી અટકાવો"</string>
<string name="permlab_wakeLock" product="default" msgid="569409726861695115">"ફોનને નિષ્ક્રિય થતો અટકાવો"</string>
+ <string name="permdesc_wakeLock" product="automotive" msgid="5995045369683254571">"ઍપને કારની સ્ક્રીન ચાલુ રાખવાની મંજૂરી આપો."</string>
<string name="permdesc_wakeLock" product="tablet" msgid="2441742939101526277">"એપ્લિકેશનને ટેબ્લેટને નિષ્ક્રિય થઈ જતો અટકાવવાની મંજૂરી આપે છે."</string>
<string name="permdesc_wakeLock" product="tv" msgid="2329298966735118796">"ઍપને તમારા Android TV ડિવાઇસને નિષ્ક્રિય થઈ જવાથી અટકાવવાની મંજૂરી આપે છે."</string>
<string name="permdesc_wakeLock" product="default" msgid="3689523792074007163">"એપ્લિકેશનને ફોનને નિષ્ક્રિય થઈ જતો અટકાવવાની મંજૂરી આપે છે."</string>
@@ -1631,6 +1631,12 @@
<string name="safe_media_volume_warning" product="default" msgid="3751676824423049994">"ભલામણ કરેલ સ્તરની ઉપર વૉલ્યૂમ વધાર્યો?\n\nલાંબા સમય સુધી ઊંચા અવાજે સાંભળવું તમારી શ્રવણક્ષમતાને નુકસાન પહોંચાડી શકે છે."</string>
<string name="accessibility_shortcut_warning_dialog_title" msgid="4017995837692622933">"ઍક્સેસિબિલિટી શૉર્ટકટનો ઉપયોગ કરીએ?"</string>
<string name="accessibility_shortcut_toogle_warning" msgid="4161716521310929544">"જ્યારે શૉર્ટકટ ચાલુ હોય, ત્યારે બન્ને વૉલ્યૂમ બટનને 3 સેકન્ડ સુધી દબાવી રાખવાથી ઍક્સેસિબિલિટી સુવિધા શરૂ થઈ જશે."</string>
+ <!-- no translation found for accessibility_select_shortcut_menu_title (7310194076629867377) -->
+ <skip />
+ <!-- no translation found for accessibility_edit_shortcut_menu_button_title (6096484087245145325) -->
+ <skip />
+ <!-- no translation found for accessibility_edit_shortcut_menu_volume_title (4849108668454490699) -->
+ <skip />
<string name="edit_accessibility_shortcut_menu_button" msgid="8885752738733772935">"શૉર્ટકટમાં ફેરફાર કરો"</string>
<string name="cancel_accessibility_shortcut_menu_button" msgid="1817413122335452474">"રદ કરો"</string>
<string name="disable_accessibility_shortcut" msgid="5806091378745232383">"શૉર્ટકટ બંધ કરો"</string>
@@ -2028,14 +2034,29 @@
<string name="as_app_forced_to_restricted_bucket" msgid="8233871289353898964">"<xliff:g id="PACKAGE_NAME">%1$s</xliff:g>ને પ્રતિબંધિત સમૂહમાં મૂકવામાં આવ્યું છે"</string>
<string name="resolver_personal_tab" msgid="2051260504014442073">"વ્યક્તિગત"</string>
<string name="resolver_work_tab" msgid="2690019516263167035">"કાર્યાલય"</string>
+ <!-- no translation found for resolver_personal_tab_accessibility (5739524949153091224) -->
+ <skip />
+ <!-- no translation found for resolver_work_tab_accessibility (4753168230363802734) -->
+ <skip />
<string name="resolver_cant_share_with_work_apps" msgid="7539495559434146897">"ઑફિસ માટેની ઍપની સાથે શેર કરી શકતાં નથી"</string>
<string name="resolver_cant_share_with_personal_apps" msgid="8020581735267157241">"વ્યક્તિગત ઍપની સાથે શેર કરી શકતાં નથી"</string>
- <string name="resolver_cant_share_cross_profile_explanation" msgid="3536237105241882679">"તમારા IT વ્યવસ્થાપકે વ્યક્તિગત અને ઑફિસ માટેની ઍપ વચ્ચે શેરિંગની સુવિધાને બ્લૉક કરી છે"</string>
- <string name="resolver_turn_on_work_apps" msgid="8987359079870455469">"ઑફિસ માટેની ઍપ ચાલુ કરો"</string>
- <string name="resolver_turn_on_work_apps_explanation" msgid="6322467455509618928">"ઑફિસ માટેની ઍપ અને સંપર્કોને ઍક્સેસ કરવા માટે ઑફિસ માટેની ઍપ ચાલુ કરો"</string>
+ <!-- no translation found for resolver_cant_share_cross_profile_explanation (5556640604460901386) -->
+ <skip />
+ <!-- no translation found for resolver_cant_access_work_apps (375634344111233790) -->
+ <skip />
+ <!-- no translation found for resolver_cant_access_work_apps_explanation (3958762224516867388) -->
+ <skip />
+ <!-- no translation found for resolver_cant_access_personal_apps (1953215925406474177) -->
+ <skip />
+ <!-- no translation found for resolver_cant_access_personal_apps_explanation (1725572276741281136) -->
+ <skip />
+ <!-- no translation found for resolver_turn_on_work_apps_share (619263911204978175) -->
+ <skip />
+ <!-- no translation found for resolver_turn_on_work_apps_view (3073389230905543680) -->
+ <skip />
<string name="resolver_no_apps_available" msgid="7710339903040989654">"કોઈ ઍપ ઉપલબ્ધ નથી"</string>
- <string name="resolver_no_apps_available_explanation" msgid="4662694431121196560">"અમે કોઈપણ ઍપ શોધી શક્યાં નથી"</string>
- <string name="resolver_switch_on_work" msgid="8294542702883688533">"ઑફિસ માટેની પ્રોફાઇલ પર સ્વિચ કરો"</string>
+ <!-- no translation found for resolver_switch_on_work (2873009160846966379) -->
+ <skip />
<string name="permlab_accessCallAudio" msgid="1682957511874097664">"ટેલિફોની કૉલમાં ઑડિયો રેકૉર્ડ કરો અથવા ચલાવો"</string>
<string name="permdesc_accessCallAudio" msgid="8448360894684277823">"ડિફૉલ્ટ ડાયલર ઍપ તરીકે સોંપણી કરવામાં આવવા પર આ ઍપને ટેલિફોની કૉલમાં ઑડિયો રેકૉર્ડ કરવાની અથવા ચલાવવાની મંજૂરી આપે છે."</string>
</resources>
diff --git a/core/res/res/values-hi/strings.xml b/core/res/res/values-hi/strings.xml
index eab79c0d8168..e73bafa33941 100644
--- a/core/res/res/values-hi/strings.xml
+++ b/core/res/res/values-hi/strings.xml
@@ -191,10 +191,8 @@
<string name="device_ownership_relinquished" msgid="4080886992183195724">"एडमिन ने निजी इस्तेमाल के लिए डिवाइस दे दिया है"</string>
<string name="network_logging_notification_title" msgid="554983187553845004">"डिवाइस प्रबंधित है"</string>
<string name="network_logging_notification_text" msgid="1327373071132562512">"आपका संगठन इस डिवाइस का प्रबंधन करता है और वह नेटवर्क ट्रैफ़िक की निगरानी भी कर सकता है. विवरण के लिए टैप करें."</string>
- <!-- no translation found for location_changed_notification_title (4119726617105166830) -->
- <skip />
- <!-- no translation found for location_changed_notification_text (198907268219396399) -->
- <skip />
+ <string name="location_changed_notification_title" msgid="4119726617105166830">"आपके एडमिन ने जगह की सेटिंग बदली है"</string>
+ <string name="location_changed_notification_text" msgid="198907268219396399">"जगह की सेटिंग देखने के लिए टैप करें."</string>
<!-- no translation found for country_detector (7023275114706088854) -->
<skip />
<!-- no translation found for location_service (2439187616018455546) -->
@@ -255,10 +253,8 @@
<item quantity="one">गड़बड़ी की रिपोर्ट के लिए <xliff:g id="NUMBER_1">%d</xliff:g> सेकंड में स्‍क्रीनशॉट लिया जा रहा है.</item>
<item quantity="other">गड़बड़ी की रिपोर्ट के लिए <xliff:g id="NUMBER_1">%d</xliff:g> सेकंड में स्‍क्रीनशॉट लिया जा रहा है.</item>
</plurals>
- <!-- no translation found for bugreport_screenshot_success_toast (7986095104151473745) -->
- <skip />
- <!-- no translation found for bugreport_screenshot_failure_toast (6736320861311294294) -->
- <skip />
+ <string name="bugreport_screenshot_success_toast" msgid="7986095104151473745">"गड़बड़ी की रिपोर्ट का स्क्रीनशॉट लिया गया"</string>
+ <string name="bugreport_screenshot_failure_toast" msgid="6736320861311294294">"गड़बड़ी की रिपोर्ट का स्क्रीनशॉट नहीं लिया जा सका"</string>
<string name="global_action_toggle_silent_mode" msgid="8464352592860372188">"साइलेंट मोड (खामोश)"</string>
<string name="global_action_silent_mode_on_status" msgid="2371892537738632013">"ध्‍वनि बंद है"</string>
<string name="global_action_silent_mode_off_status" msgid="6608006545950920042">"ध्‍वनि चालू है"</string>
@@ -445,8 +441,7 @@
<string name="permdesc_systemCamera" msgid="544730545441964482">"यह सिस्टम ऐप्लिकेशन तस्वीरें लेने और वीडियो रिकॉर्ड करने के लिए जब चाहे, सिस्टम के कैमरे का इस्तेमाल कर सकता है. ऐप्लिकेशन को android.permission.CAMERA की अनुमति देना भी ज़रूरी है"</string>
<string name="permlab_vibrate" msgid="8596800035791962017">"कंपन (वाइब्रेशन) को नियंत्रित करें"</string>
<string name="permdesc_vibrate" msgid="8733343234582083721">"ऐप्स को कंपनकर्ता नियंत्रित करने देता है."</string>
- <!-- no translation found for permdesc_vibrator_state (7050024956594170724) -->
- <skip />
+ <string name="permdesc_vibrator_state" msgid="7050024956594170724">"इससे ऐप्लिकेशन, डिवाइस का वाइब्रेटर ऐक्सेस कर पाएगा."</string>
<string name="permlab_callPhone" msgid="1798582257194643320">"फ़ोन नंबर पर सीधे कॉल करें"</string>
<string name="permdesc_callPhone" msgid="5439809516131609109">"ऐप्लिकेशन को आपके हस्‍तक्षेप के बिना फ़ोन नंबर पर कॉल करने देता है. इसके परिणाम अनचाहे शुल्‍क या कॉल हो सकते हैं. ध्यान दें कि यह ऐप्लिकेशन को आपातकालीन नंबर पर कॉल नहीं करने देता. नुकसान पहुंचाने वाला ऐप्लिकेशन आपकी पुष्टि के बिना कॉल करके आपके पैसे खर्च करवा सकते हैं."</string>
<string name="permlab_accessImsCallService" msgid="442192920714863782">"IMS कॉल सेवा ऐक्‍सेस करें"</string>
@@ -461,9 +456,11 @@
<string name="permdesc_acceptHandovers" msgid="7129026180128626870">"इसके ज़रिए आप, किसी ऐप्लिकेशन में शुरू किया गया कॉल दूसरे ऐप्लिकेशन में जारी रख सकते हैं."</string>
<string name="permlab_readPhoneNumbers" msgid="5668704794723365628">"फ़ोन नंबर पढ़ना"</string>
<string name="permdesc_readPhoneNumbers" msgid="7368652482818338871">"ऐप को डिवाइस के फ़ोन नंबर का इस्तेमाल करने देती है."</string>
+ <string name="permlab_wakeLock" product="automotive" msgid="1904736682319375676">"कार की स्क्रीन चालू रखना"</string>
<string name="permlab_wakeLock" product="tablet" msgid="1527660973931694000">"टैबलेट को सोने (कम बैटरी मोड) से रोकें"</string>
<string name="permlab_wakeLock" product="tv" msgid="2856941418123343518">"अपने Android TV डिवाइस को स्लीप मोड (कम बैटरी मोड में जाने) से रोकें"</string>
<string name="permlab_wakeLock" product="default" msgid="569409726861695115">"फ़ोन को सोने (कम बैटरी मोड) से रोकें"</string>
+ <string name="permdesc_wakeLock" product="automotive" msgid="5995045369683254571">"यह अनुमति देने पर, ऐप्लिकेशन कार की स्क्रीन चालू रख पाएगा."</string>
<string name="permdesc_wakeLock" product="tablet" msgid="2441742939101526277">"ऐप्स को टैबलेट को प्रयोग में नहीं हो जाने से रोकता है."</string>
<string name="permdesc_wakeLock" product="tv" msgid="2329298966735118796">"यह ऐप्लिकेशन को आपके Android TV डिवाइस को स्लीप मोड (कम बैटरी मोड में जाने) से रोकने की अनुमति देता है."</string>
<string name="permdesc_wakeLock" product="default" msgid="3689523792074007163">"ऐप्स को फ़ोन को प्रयोग में नहीं होने से रोकता है."</string>
@@ -1638,6 +1635,12 @@
<string name="safe_media_volume_warning" product="default" msgid="3751676824423049994">"वॉल्यूम को सुझाए गए स्तर से ऊपर बढ़ाएं?\n\nअत्यधिक वॉल्यूम पर ज़्यादा समय तक सुनने से आपकी सुनने की क्षमता को नुकसान हो सकता है."</string>
<string name="accessibility_shortcut_warning_dialog_title" msgid="4017995837692622933">"सुलभता शॉर्टकट का इस्तेमाल करना चाहते हैं?"</string>
<string name="accessibility_shortcut_toogle_warning" msgid="4161716521310929544">"शॉर्टकट के चालू होने पर, दाेनाें वॉल्यूम बटन (आवाज़ कम या ज़्यादा करने वाले बटन) को तीन सेकंड तक दबाने से, सुलभता सुविधा शुरू हाे जाएगी."</string>
+ <!-- no translation found for accessibility_select_shortcut_menu_title (7310194076629867377) -->
+ <skip />
+ <!-- no translation found for accessibility_edit_shortcut_menu_button_title (6096484087245145325) -->
+ <skip />
+ <!-- no translation found for accessibility_edit_shortcut_menu_volume_title (4849108668454490699) -->
+ <skip />
<string name="edit_accessibility_shortcut_menu_button" msgid="8885752738733772935">"शॉर्टकट में बदलाव करें"</string>
<string name="cancel_accessibility_shortcut_menu_button" msgid="1817413122335452474">"अभी नहीं"</string>
<string name="disable_accessibility_shortcut" msgid="5806091378745232383">"शॉर्टकट बंद करें"</string>
@@ -2035,16 +2038,29 @@
<string name="as_app_forced_to_restricted_bucket" msgid="8233871289353898964">"<xliff:g id="PACKAGE_NAME">%1$s</xliff:g> को प्रतिबंधित बकेट में रखा गया है"</string>
<string name="resolver_personal_tab" msgid="2051260504014442073">"निजी प्रोफ़ाइल"</string>
<string name="resolver_work_tab" msgid="2690019516263167035">"वर्क प्रोफ़ाइल"</string>
+ <!-- no translation found for resolver_personal_tab_accessibility (5739524949153091224) -->
+ <skip />
+ <!-- no translation found for resolver_work_tab_accessibility (4753168230363802734) -->
+ <skip />
<string name="resolver_cant_share_with_work_apps" msgid="7539495559434146897">"ऑफ़िस के काम से जुड़े ऐप्लिकेशन के साथ चीज़ें शेयर नहीं की जा सकतीं"</string>
<string name="resolver_cant_share_with_personal_apps" msgid="8020581735267157241">"निजी ऐप्लिकेशन के साथ कुछ शेयर नहीं किया जा सकता"</string>
- <string name="resolver_cant_share_cross_profile_explanation" msgid="3536237105241882679">"आपके आईटी एडमिन ने निजी ऐप्लिकेशन और ऑफ़िस के काम से जुड़े ऐप्लिकेशन के बीच कुछ शेयर करने की सुविधा पर रोक लगा दी है"</string>
- <string name="resolver_turn_on_work_apps" msgid="8987359079870455469">"ऑफ़िस के काम से जुड़े ऐप्लिकेशन चालू करें"</string>
- <string name="resolver_turn_on_work_apps_explanation" msgid="6322467455509618928">"ऑफ़िस के काम से जुड़े ऐप्लिकेशन और संपर्क ऐक्सेस करने के लिए, इन ऐप्लिकेशन को चालू करें"</string>
- <string name="resolver_no_apps_available" msgid="7710339903040989654">"कोई ऐप्लिकेशन उपलब्ध नहीं है"</string>
- <string name="resolver_no_apps_available_explanation" msgid="4662694431121196560">"हमें कोई ऐप्लिकेशन नहीं मिला"</string>
- <string name="resolver_switch_on_work" msgid="8294542702883688533">"वर्क प्रोफ़ाइल को चालू करें"</string>
- <!-- no translation found for permlab_accessCallAudio (1682957511874097664) -->
+ <!-- no translation found for resolver_cant_share_cross_profile_explanation (5556640604460901386) -->
+ <skip />
+ <!-- no translation found for resolver_cant_access_work_apps (375634344111233790) -->
+ <skip />
+ <!-- no translation found for resolver_cant_access_work_apps_explanation (3958762224516867388) -->
+ <skip />
+ <!-- no translation found for resolver_cant_access_personal_apps (1953215925406474177) -->
<skip />
- <!-- no translation found for permdesc_accessCallAudio (8448360894684277823) -->
+ <!-- no translation found for resolver_cant_access_personal_apps_explanation (1725572276741281136) -->
+ <skip />
+ <!-- no translation found for resolver_turn_on_work_apps_share (619263911204978175) -->
+ <skip />
+ <!-- no translation found for resolver_turn_on_work_apps_view (3073389230905543680) -->
+ <skip />
+ <string name="resolver_no_apps_available" msgid="7710339903040989654">"कोई ऐप्लिकेशन उपलब्ध नहीं है"</string>
+ <!-- no translation found for resolver_switch_on_work (2873009160846966379) -->
<skip />
+ <string name="permlab_accessCallAudio" msgid="1682957511874097664">"फ़ोन कॉल के दौरान, ऑडियो रिकॉर्ड करने या उसे चलाने की अनुमति"</string>
+ <string name="permdesc_accessCallAudio" msgid="8448360894684277823">"डिफ़ॉल्ट डायलर ऐप्लिकेशन के तौर पर असाइन होने पर, इस ऐप्लिकेशन को फ़ोन कॉल के दौरान ऑडियो रिकॉर्ड करने और उसे चलाने की मंज़ूरी मिल जाती है."</string>
</resources>
diff --git a/core/res/res/values-hr/strings.xml b/core/res/res/values-hr/strings.xml
index 5b7ec23752ca..202c3ca315c2 100644
--- a/core/res/res/values-hr/strings.xml
+++ b/core/res/res/values-hr/strings.xml
@@ -252,10 +252,8 @@
<item quantity="few">Izrada snimke zaslona za izvješće o programskoj pogrešci za <xliff:g id="NUMBER_1">%d</xliff:g> sekunde.</item>
<item quantity="other">Izrada snimke zaslona za izvješće o programskoj pogrešci za <xliff:g id="NUMBER_1">%d</xliff:g> sekundi.</item>
</plurals>
- <!-- no translation found for bugreport_screenshot_success_toast (7986095104151473745) -->
- <skip />
- <!-- no translation found for bugreport_screenshot_failure_toast (6736320861311294294) -->
- <skip />
+ <string name="bugreport_screenshot_success_toast" msgid="7986095104151473745">"Snimka zaslona je izrađena s izvješćem o programskoj pogrešci"</string>
+ <string name="bugreport_screenshot_failure_toast" msgid="6736320861311294294">"Snimanje zaslona s izvješćem o programskoj pogrešci nije uspjelo."</string>
<string name="global_action_toggle_silent_mode" msgid="8464352592860372188">"Bešumni način"</string>
<string name="global_action_silent_mode_on_status" msgid="2371892537738632013">"Zvuk je isključen"</string>
<string name="global_action_silent_mode_off_status" msgid="6608006545950920042">"Zvuk je uključen"</string>
@@ -457,9 +455,11 @@
<string name="permdesc_acceptHandovers" msgid="7129026180128626870">"Omogućuje aplikaciji da nastavi poziv započet u nekoj drugoj aplikaciji."</string>
<string name="permlab_readPhoneNumbers" msgid="5668704794723365628">"čitati telefonske brojeve"</string>
<string name="permdesc_readPhoneNumbers" msgid="7368652482818338871">"Aplikaciji omogućuje da pristupi telefonskim brojevima na uređaju."</string>
+ <string name="permlab_wakeLock" product="automotive" msgid="1904736682319375676">"zadržati zaslon automobila uključenim"</string>
<string name="permlab_wakeLock" product="tablet" msgid="1527660973931694000">"spriječi mirovanje tabletnog uređaja"</string>
<string name="permlab_wakeLock" product="tv" msgid="2856941418123343518">"sprječava prelazak Android TV uređaja u mirovanje"</string>
<string name="permlab_wakeLock" product="default" msgid="569409726861695115">"sprečava telefon da prijeđe u stanje mirovanja"</string>
+ <string name="permdesc_wakeLock" product="automotive" msgid="5995045369683254571">"Aplikaciji omogućuje da zaslon automobila zadrži uključenim."</string>
<string name="permdesc_wakeLock" product="tablet" msgid="2441742939101526277">"Aplikaciji omogućuje sprječavanje prelaska tabletnog računala u mirovanje."</string>
<string name="permdesc_wakeLock" product="tv" msgid="2329298966735118796">"Aplikaciji omogućuje sprječavanje prelaska Android TV uređaja u mirovanje."</string>
<string name="permdesc_wakeLock" product="default" msgid="3689523792074007163">"Aplikaciji omogućuje da spriječi prelazak telefona u mirovanje."</string>
@@ -1653,6 +1653,12 @@
<string name="safe_media_volume_warning" product="default" msgid="3751676824423049994">"Želite li pojačati zvuk iznad preporučene razine?\n\nDugotrajno slušanje glasne glazbe može vam oštetiti sluh."</string>
<string name="accessibility_shortcut_warning_dialog_title" msgid="4017995837692622933">"Želite li upotrebljavati prečac za pristupačnost?"</string>
<string name="accessibility_shortcut_toogle_warning" msgid="4161716521310929544">"Kad je taj prečac uključen, pritiskom na obje tipke za glasnoću na tri sekunde pokrenut će se značajka pristupačnosti."</string>
+ <!-- no translation found for accessibility_select_shortcut_menu_title (7310194076629867377) -->
+ <skip />
+ <!-- no translation found for accessibility_edit_shortcut_menu_button_title (6096484087245145325) -->
+ <skip />
+ <!-- no translation found for accessibility_edit_shortcut_menu_volume_title (4849108668454490699) -->
+ <skip />
<string name="edit_accessibility_shortcut_menu_button" msgid="8885752738733772935">"Uredi prečace"</string>
<string name="cancel_accessibility_shortcut_menu_button" msgid="1817413122335452474">"Otkaži"</string>
<string name="disable_accessibility_shortcut" msgid="5806091378745232383">"Isključi prečac"</string>
@@ -1885,8 +1891,7 @@
<string name="default_notification_channel_label" msgid="3697928973567217330">"Nema kategorije"</string>
<string name="importance_from_user" msgid="2782756722448800447">"Postavili ste važnost tih obavijesti."</string>
<string name="importance_from_person" msgid="4235804979664465383">"Važno je zbog uključenih osoba."</string>
- <!-- no translation found for notification_history_title_placeholder (7748630986182249599) -->
- <skip />
+ <string name="notification_history_title_placeholder" msgid="7748630986182249599">"Prilagođena obavijest aplikacije"</string>
<string name="user_creation_account_exists" msgid="2239146360099708035">"Dopustiti aplikaciji <xliff:g id="APP">%1$s</xliff:g> da izradi novog korisnika s računom <xliff:g id="ACCOUNT">%2$s</xliff:g> (korisnik s ovim računom već postoji)?"</string>
<string name="user_creation_adding" msgid="7305185499667958364">"Dopustiti aplikaciji <xliff:g id="APP">%1$s</xliff:g> da izradi novog korisnika s računom <xliff:g id="ACCOUNT">%2$s</xliff:g>?"</string>
<string name="language_selection_title" msgid="52674936078683285">"Dodavanje jezika"</string>
@@ -2062,14 +2067,29 @@
<string name="as_app_forced_to_restricted_bucket" msgid="8233871289353898964">"Paket <xliff:g id="PACKAGE_NAME">%1$s</xliff:g> premješten je u spremnik OGRANIČENO"</string>
<string name="resolver_personal_tab" msgid="2051260504014442073">"Osobno"</string>
<string name="resolver_work_tab" msgid="2690019516263167035">"Posao"</string>
+ <!-- no translation found for resolver_personal_tab_accessibility (5739524949153091224) -->
+ <skip />
+ <!-- no translation found for resolver_work_tab_accessibility (4753168230363802734) -->
+ <skip />
<string name="resolver_cant_share_with_work_apps" msgid="7539495559434146897">"Dijeljenje s poslovnim aplikacijama nije moguće"</string>
<string name="resolver_cant_share_with_personal_apps" msgid="8020581735267157241">"Dijeljenje s osobnim aplikacijama nije moguće"</string>
- <string name="resolver_cant_share_cross_profile_explanation" msgid="3536237105241882679">"Vaš IT administrator blokirao je dijeljenje između osobnih i poslovnih aplikacija"</string>
- <string name="resolver_turn_on_work_apps" msgid="8987359079870455469">"Uključite poslovne aplikacije"</string>
- <string name="resolver_turn_on_work_apps_explanation" msgid="6322467455509618928">"Uključite poslovne aplikacije da biste pristupili poslovnim aplikacijama i kontaktima"</string>
+ <!-- no translation found for resolver_cant_share_cross_profile_explanation (5556640604460901386) -->
+ <skip />
+ <!-- no translation found for resolver_cant_access_work_apps (375634344111233790) -->
+ <skip />
+ <!-- no translation found for resolver_cant_access_work_apps_explanation (3958762224516867388) -->
+ <skip />
+ <!-- no translation found for resolver_cant_access_personal_apps (1953215925406474177) -->
+ <skip />
+ <!-- no translation found for resolver_cant_access_personal_apps_explanation (1725572276741281136) -->
+ <skip />
+ <!-- no translation found for resolver_turn_on_work_apps_share (619263911204978175) -->
+ <skip />
+ <!-- no translation found for resolver_turn_on_work_apps_view (3073389230905543680) -->
+ <skip />
<string name="resolver_no_apps_available" msgid="7710339903040989654">"Aplikacije nisu dostupne"</string>
- <string name="resolver_no_apps_available_explanation" msgid="4662694431121196560">"Nismo pronašli nijednu aplikaciju"</string>
- <string name="resolver_switch_on_work" msgid="8294542702883688533">"Prebaci na poslovni profil"</string>
+ <!-- no translation found for resolver_switch_on_work (2873009160846966379) -->
+ <skip />
<string name="permlab_accessCallAudio" msgid="1682957511874097664">"Snimanje ili reprodukcija zvuka u telefonskim pozivima"</string>
<string name="permdesc_accessCallAudio" msgid="8448360894684277823">"Kad je ova aplikacija postavljena kao zadana aplikacija za biranje, omogućuje joj snimanje ili reprodukciju zvuka u telefonskim pozivima."</string>
</resources>
diff --git a/core/res/res/values-hu/strings.xml b/core/res/res/values-hu/strings.xml
index a474ac776245..356d179ca187 100644
--- a/core/res/res/values-hu/strings.xml
+++ b/core/res/res/values-hu/strings.xml
@@ -249,10 +249,8 @@
<item quantity="other">Képernyőkép készítése a hibajelentéshez <xliff:g id="NUMBER_1">%d</xliff:g> másodpercen belül.</item>
<item quantity="one">Képernyőkép készítése a hibajelentéshez <xliff:g id="NUMBER_0">%d</xliff:g> másodpercen belül.</item>
</plurals>
- <!-- no translation found for bugreport_screenshot_success_toast (7986095104151473745) -->
- <skip />
- <!-- no translation found for bugreport_screenshot_failure_toast (6736320861311294294) -->
- <skip />
+ <string name="bugreport_screenshot_success_toast" msgid="7986095104151473745">"Sikerült a képernyőkép elkészítése a hibajelentéshez"</string>
+ <string name="bugreport_screenshot_failure_toast" msgid="6736320861311294294">"Nem sikerült képernyőképet készíteni a hibajelentéshez"</string>
<string name="global_action_toggle_silent_mode" msgid="8464352592860372188">"Néma üzemmód"</string>
<string name="global_action_silent_mode_on_status" msgid="2371892537738632013">"Hang kikapcsolva"</string>
<string name="global_action_silent_mode_off_status" msgid="6608006545950920042">"Hang bekapcsolva"</string>
@@ -454,9 +452,11 @@
<string name="permdesc_acceptHandovers" msgid="7129026180128626870">"Engedélyezi az alkalmazásnak, hogy folytassa a hívást, amelyet valamelyik másik alkalmazásban kezdtek meg."</string>
<string name="permlab_readPhoneNumbers" msgid="5668704794723365628">"telefonszámok olvasása"</string>
<string name="permdesc_readPhoneNumbers" msgid="7368652482818338871">"Engedélyezi az alkalmazás számára az eszköz telefonszámaihoz való hozzáférést."</string>
+ <string name="permlab_wakeLock" product="automotive" msgid="1904736682319375676">"az autó képernyőjének bekapcsolva tartása"</string>
<string name="permlab_wakeLock" product="tablet" msgid="1527660973931694000">"táblagép alvás üzemmódjának megakadályozása"</string>
<string name="permlab_wakeLock" product="tv" msgid="2856941418123343518">"megakadályozza, hogy az Android TV eszköz alvó üzemmódra váltson"</string>
<string name="permlab_wakeLock" product="default" msgid="569409726861695115">"telefon alvó üzemmódjának megakadályozása"</string>
+ <string name="permdesc_wakeLock" product="automotive" msgid="5995045369683254571">"Lehetővé teszi az alkalmazás számára az autó képernyőjének bekapcsolva tartását."</string>
<string name="permdesc_wakeLock" product="tablet" msgid="2441742939101526277">"Lehetővé teszi az alkalmazás számára, hogy megakadályozza, hogy a táblagép alvó üzemmódra váltson."</string>
<string name="permdesc_wakeLock" product="tv" msgid="2329298966735118796">"Lehetővé teszi az alkalmazás számára, hogy megakadályozza, hogy az Android TV eszköz alvó üzemmódra váltson."</string>
<string name="permdesc_wakeLock" product="default" msgid="3689523792074007163">"Lehetővé teszi az alkalmazás számára, hogy megakadályozza, hogy a telefon alvó üzemmódra váltson."</string>
@@ -1631,6 +1631,12 @@
<string name="safe_media_volume_warning" product="default" msgid="3751676824423049994">"Az ajánlott szint fölé szeretné emelni a hangerőt?\n\nHa hosszú időn át teszi ki magát nagy hangerőnek, azzal károsíthatja a hallását."</string>
<string name="accessibility_shortcut_warning_dialog_title" msgid="4017995837692622933">"Szeretné használni a Kisegítő lehetőségek billentyűparancsot?"</string>
<string name="accessibility_shortcut_toogle_warning" msgid="4161716521310929544">"Ha a gyorsparancs aktív, akkor a két hangerőgomb három másodpercig tartó együttes lenyomásával kisegítő funkciót indíthat el."</string>
+ <!-- no translation found for accessibility_select_shortcut_menu_title (7310194076629867377) -->
+ <skip />
+ <!-- no translation found for accessibility_edit_shortcut_menu_button_title (6096484087245145325) -->
+ <skip />
+ <!-- no translation found for accessibility_edit_shortcut_menu_volume_title (4849108668454490699) -->
+ <skip />
<string name="edit_accessibility_shortcut_menu_button" msgid="8885752738733772935">"Gyorsparancsszerkesztés"</string>
<string name="cancel_accessibility_shortcut_menu_button" msgid="1817413122335452474">"Mégse"</string>
<string name="disable_accessibility_shortcut" msgid="5806091378745232383">"Billentyűparancs kikapcsolása"</string>
@@ -1853,8 +1859,7 @@
<string name="default_notification_channel_label" msgid="3697928973567217330">"Nincs kategóriába sorolva"</string>
<string name="importance_from_user" msgid="2782756722448800447">"Ön állította be ezen értesítések fontossági szintjét."</string>
<string name="importance_from_person" msgid="4235804979664465383">"Ez az üzenet a résztvevők miatt fontos."</string>
- <!-- no translation found for notification_history_title_placeholder (7748630986182249599) -->
- <skip />
+ <string name="notification_history_title_placeholder" msgid="7748630986182249599">"Egyéni alkalmazásértesítés"</string>
<string name="user_creation_account_exists" msgid="2239146360099708035">"Engedélyezi a(z) <xliff:g id="APP">%1$s</xliff:g> számára, hogy új felhasználót hozzon létre a(z) <xliff:g id="ACCOUNT">%2$s</xliff:g> fiókkal? (Már létezik felhasználó ezzel a fiókkal.)"</string>
<string name="user_creation_adding" msgid="7305185499667958364">"Engedélyezi a(z) <xliff:g id="APP">%1$s</xliff:g> számára, hogy új felhasználót hozzon létre a(z) <xliff:g id="ACCOUNT">%2$s</xliff:g> fiókkal?"</string>
<string name="language_selection_title" msgid="52674936078683285">"Nyelv hozzáadása"</string>
@@ -2028,14 +2033,29 @@
<string name="as_app_forced_to_restricted_bucket" msgid="8233871289353898964">"A következő csomag a KORLÁTOZOTT csoportba került: <xliff:g id="PACKAGE_NAME">%1$s</xliff:g>"</string>
<string name="resolver_personal_tab" msgid="2051260504014442073">"Személyes"</string>
<string name="resolver_work_tab" msgid="2690019516263167035">"Munka"</string>
+ <!-- no translation found for resolver_personal_tab_accessibility (5739524949153091224) -->
+ <skip />
+ <!-- no translation found for resolver_work_tab_accessibility (4753168230363802734) -->
+ <skip />
<string name="resolver_cant_share_with_work_apps" msgid="7539495559434146897">"Nem lehetséges a munkahelyi alkalmazásokkal való megosztás"</string>
<string name="resolver_cant_share_with_personal_apps" msgid="8020581735267157241">"Nem lehetséges a személyes alkalmazásokkal való megosztás"</string>
- <string name="resolver_cant_share_cross_profile_explanation" msgid="3536237105241882679">"Rendszergazdája letiltotta a személyes és a munkahelyi alkalmazások közti megosztást"</string>
- <string name="resolver_turn_on_work_apps" msgid="8987359079870455469">"Kapcsolja be a munkahelyi alkalmazásokat"</string>
- <string name="resolver_turn_on_work_apps_explanation" msgid="6322467455509618928">"Kapcsolja be a munkahelyi alkalmazásokat a munkahelyi alkalmazásokhoz és a névjegyekhez való hozzáférés érdekében"</string>
+ <!-- no translation found for resolver_cant_share_cross_profile_explanation (5556640604460901386) -->
+ <skip />
+ <!-- no translation found for resolver_cant_access_work_apps (375634344111233790) -->
+ <skip />
+ <!-- no translation found for resolver_cant_access_work_apps_explanation (3958762224516867388) -->
+ <skip />
+ <!-- no translation found for resolver_cant_access_personal_apps (1953215925406474177) -->
+ <skip />
+ <!-- no translation found for resolver_cant_access_personal_apps_explanation (1725572276741281136) -->
+ <skip />
+ <!-- no translation found for resolver_turn_on_work_apps_share (619263911204978175) -->
+ <skip />
+ <!-- no translation found for resolver_turn_on_work_apps_view (3073389230905543680) -->
+ <skip />
<string name="resolver_no_apps_available" msgid="7710339903040989654">"Nem áll rendelkezésre alkalmazás"</string>
- <string name="resolver_no_apps_available_explanation" msgid="4662694431121196560">"Nem találtunk egy alkalmazást sem"</string>
- <string name="resolver_switch_on_work" msgid="8294542702883688533">"Munkaprofil bekapcsolása"</string>
+ <!-- no translation found for resolver_switch_on_work (2873009160846966379) -->
+ <skip />
<string name="permlab_accessCallAudio" msgid="1682957511874097664">"Audiotartalmak felvétele és lejátszása telefonhívások közben"</string>
<string name="permdesc_accessCallAudio" msgid="8448360894684277823">"Lehetővé teszi ennek az alkalmazásnak audiotartalmak felvételét és lejátszását telefonhívások közben, amennyiben az alkalmazás alapértelmezett tárcsázóalkalmazásként van kijelölve."</string>
</resources>
diff --git a/core/res/res/values-hy/strings.xml b/core/res/res/values-hy/strings.xml
index 80b7985c5a11..ca9833157369 100644
--- a/core/res/res/values-hy/strings.xml
+++ b/core/res/res/values-hy/strings.xml
@@ -249,10 +249,8 @@
<item quantity="one">Սքրինշոթը կարվի <xliff:g id="NUMBER_1">%d</xliff:g> վայրկյանից:</item>
<item quantity="other">Սքրինշոթը կարվի <xliff:g id="NUMBER_1">%d</xliff:g> վայրկյանից:</item>
</plurals>
- <!-- no translation found for bugreport_screenshot_success_toast (7986095104151473745) -->
- <skip />
- <!-- no translation found for bugreport_screenshot_failure_toast (6736320861311294294) -->
- <skip />
+ <string name="bugreport_screenshot_success_toast" msgid="7986095104151473745">"Վրիպակների հաշվետվության պատկերով սքրինշոթ արվեց"</string>
+ <string name="bugreport_screenshot_failure_toast" msgid="6736320861311294294">"Չհաջողվեց վրիպակների հաշվետվության պատկերով սքրինշոթ անել"</string>
<string name="global_action_toggle_silent_mode" msgid="8464352592860372188">"Անձայն ռեժիմ"</string>
<string name="global_action_silent_mode_on_status" msgid="2371892537738632013">"Ձայնը անջատված է"</string>
<string name="global_action_silent_mode_off_status" msgid="6608006545950920042">"Ձայնը միացված է"</string>
@@ -454,9 +452,11 @@
<string name="permdesc_acceptHandovers" msgid="7129026180128626870">"Թույլ է տալիս հավելվածին շարունակել մեկ այլ հավելվածի միջոցով սկսած զանգը:"</string>
<string name="permlab_readPhoneNumbers" msgid="5668704794723365628">"օգտագործել հեռախոսահամարները"</string>
<string name="permdesc_readPhoneNumbers" msgid="7368652482818338871">"Հավելվածին թույլ է տալիս օգտագործել սարքի հեռախոսահամարները:"</string>
+ <string name="permlab_wakeLock" product="automotive" msgid="1904736682319375676">"միացրած թողնել մեքենայի էկրանը"</string>
<string name="permlab_wakeLock" product="tablet" msgid="1527660973931694000">"զերծ պահել պլանշետը քնելուց"</string>
<string name="permlab_wakeLock" product="tv" msgid="2856941418123343518">"թույլ չտալ, որ Android TV սարքն անցնի քնի ռեժիմի"</string>
<string name="permlab_wakeLock" product="default" msgid="569409726861695115">"կանխել հեռախոսի քնի ռեժիմին անցնելը"</string>
+ <string name="permdesc_wakeLock" product="automotive" msgid="5995045369683254571">"Հավելվածին թույլ է տալիս միացրած թողնել մեքենայի էկրանը։"</string>
<string name="permdesc_wakeLock" product="tablet" msgid="2441742939101526277">"Թույլ է տալիս հավելվածին կանխել պլանշետի` քնի ռեժիմին անցնելը:"</string>
<string name="permdesc_wakeLock" product="tv" msgid="2329298966735118796">"Թույլ է տալիս հավելվածին կանխել, որ Android TV սարքը չանցնի քնի ռեժիմի:"</string>
<string name="permdesc_wakeLock" product="default" msgid="3689523792074007163">"Թույլ է տալիս հավելվածին կանխել հեռախոսի` քնի ռեժիմին անցնելը:"</string>
@@ -1631,6 +1631,12 @@
<string name="safe_media_volume_warning" product="default" msgid="3751676824423049994">"Ձայնը բարձրացնե՞լ խորհուրդ տրվող մակարդակից ավել:\n\nԵրկարատև բարձրաձայն լսելը կարող է վնասել ձեր լսողությունը:"</string>
<string name="accessibility_shortcut_warning_dialog_title" msgid="4017995837692622933">"Օգտագործե՞լ Մատչելիության դյուրանցումը։"</string>
<string name="accessibility_shortcut_toogle_warning" msgid="4161716521310929544">"Հատուկ գործառույթն օգտագործելու համար սեղմեք և 3 վայրկյան սեղմած պահեք ձայնի ուժգնության երկու կոճակները, երբ գործառույթը միացված է:"</string>
+ <!-- no translation found for accessibility_select_shortcut_menu_title (7310194076629867377) -->
+ <skip />
+ <!-- no translation found for accessibility_edit_shortcut_menu_button_title (6096484087245145325) -->
+ <skip />
+ <!-- no translation found for accessibility_edit_shortcut_menu_volume_title (4849108668454490699) -->
+ <skip />
<string name="edit_accessibility_shortcut_menu_button" msgid="8885752738733772935">"Փոփոխել դյուրանցումները"</string>
<string name="cancel_accessibility_shortcut_menu_button" msgid="1817413122335452474">"Չեղարկել"</string>
<string name="disable_accessibility_shortcut" msgid="5806091378745232383">"Անջատել դյուրանցումը"</string>
@@ -1853,8 +1859,7 @@
<string name="default_notification_channel_label" msgid="3697928973567217330">"Չդասակարգված"</string>
<string name="importance_from_user" msgid="2782756722448800447">"Դուք սահմանել եք այս ծանուցումների կարևորությունը:"</string>
<string name="importance_from_person" msgid="4235804979664465383">"Կարևոր է, քանի որ որոշակի մարդիկ են ներգրավված:"</string>
- <!-- no translation found for notification_history_title_placeholder (7748630986182249599) -->
- <skip />
+ <string name="notification_history_title_placeholder" msgid="7748630986182249599">"Հավելվածի հատուկ ծանուցում"</string>
<string name="user_creation_account_exists" msgid="2239146360099708035">"Թույլատրե՞լ <xliff:g id="APP">%1$s</xliff:g> հավելվածին <xliff:g id="ACCOUNT">%2$s</xliff:g> հաշվով նոր Օգտատեր ստեղծել (նման հաշվով Օգտատեր արդեն գոյություն ունի):"</string>
<string name="user_creation_adding" msgid="7305185499667958364">"Թույլատրե՞լ <xliff:g id="APP">%1$s</xliff:g> հավելվածին <xliff:g id="ACCOUNT">%2$s</xliff:g> հաշվով նոր Օգտատեր ստեղծել:"</string>
<string name="language_selection_title" msgid="52674936078683285">"Ավելացնել լեզու"</string>
@@ -2028,14 +2033,29 @@
<string name="as_app_forced_to_restricted_bucket" msgid="8233871289353898964">"<xliff:g id="PACKAGE_NAME">%1$s</xliff:g> փաթեթը գցվեց ՍԱՀՄԱՆԱՓԱԿՎԱԾ զամբյուղի մեջ"</string>
<string name="resolver_personal_tab" msgid="2051260504014442073">"Անձնական"</string>
<string name="resolver_work_tab" msgid="2690019516263167035">"Աշխատանքային"</string>
+ <!-- no translation found for resolver_personal_tab_accessibility (5739524949153091224) -->
+ <skip />
+ <!-- no translation found for resolver_work_tab_accessibility (4753168230363802734) -->
+ <skip />
<string name="resolver_cant_share_with_work_apps" msgid="7539495559434146897">"Հնարավոր չէ կիսվել աշխատանքային հավելվածների հետ"</string>
<string name="resolver_cant_share_with_personal_apps" msgid="8020581735267157241">"Հնարավոր չէ կիսվել անձնական հավելվածների հետ"</string>
- <string name="resolver_cant_share_cross_profile_explanation" msgid="3536237105241882679">"Ձեր ՏՏ ադմինիստրատորն արգելափակել է աշխատանքային և անձնական հավելվածների միջև տվյալների փոխանակումը։"</string>
- <string name="resolver_turn_on_work_apps" msgid="8987359079870455469">"Միացրեք աշխատանքային հավելվածները"</string>
- <string name="resolver_turn_on_work_apps_explanation" msgid="6322467455509618928">"Միացրեք աշխատանքային հավելվածները, որպեսզի կարողանաք օգտագործել աշխատանքային տվյալները (հավելվածներն ու կոնտակտները)"</string>
+ <!-- no translation found for resolver_cant_share_cross_profile_explanation (5556640604460901386) -->
+ <skip />
+ <!-- no translation found for resolver_cant_access_work_apps (375634344111233790) -->
+ <skip />
+ <!-- no translation found for resolver_cant_access_work_apps_explanation (3958762224516867388) -->
+ <skip />
+ <!-- no translation found for resolver_cant_access_personal_apps (1953215925406474177) -->
+ <skip />
+ <!-- no translation found for resolver_cant_access_personal_apps_explanation (1725572276741281136) -->
+ <skip />
+ <!-- no translation found for resolver_turn_on_work_apps_share (619263911204978175) -->
+ <skip />
+ <!-- no translation found for resolver_turn_on_work_apps_view (3073389230905543680) -->
+ <skip />
<string name="resolver_no_apps_available" msgid="7710339903040989654">"Հասանելի հավելվածներ չկան"</string>
- <string name="resolver_no_apps_available_explanation" msgid="4662694431121196560">"Չհաջողվեց գտնել հավելվածներ"</string>
- <string name="resolver_switch_on_work" msgid="8294542702883688533">"Անցնել աշխատանքային հաշվին"</string>
+ <!-- no translation found for resolver_switch_on_work (2873009160846966379) -->
+ <skip />
<string name="permlab_accessCallAudio" msgid="1682957511874097664">"Հեռախոսային զանգերի ձայնագրում և նվագարկում"</string>
<string name="permdesc_accessCallAudio" msgid="8448360894684277823">"Եթե այս հավելվածն ըստ կանխադրման օգտագործվում է զանգերի համար, այն կարող է ձայնագրել և նվագարկել հեռախոսային խոսակցությունները։"</string>
</resources>
diff --git a/core/res/res/values-in/strings.xml b/core/res/res/values-in/strings.xml
index d45370aa4ace..8b28f63226c0 100644
--- a/core/res/res/values-in/strings.xml
+++ b/core/res/res/values-in/strings.xml
@@ -89,7 +89,7 @@
<string name="EmergencyCallWarningSummary" msgid="1194185880092805497">"Tidak dapat melakukan panggilan darurat melalui Wi-Fi"</string>
<string name="notification_channel_network_alert" msgid="4788053066033851841">"Notifikasi"</string>
<string name="notification_channel_call_forward" msgid="8230490317314272406">"Penerusan panggilan"</string>
- <string name="notification_channel_emergency_callback" msgid="54074839059123159">"Mode panggilan balik darurat"</string>
+ <string name="notification_channel_emergency_callback" msgid="54074839059123159">"Mode telepon balik darurat"</string>
<string name="notification_channel_mobile_data_status" msgid="1941911162076442474">"Status data seluler"</string>
<string name="notification_channel_sms" msgid="1243384981025535724">"Pesan SMS"</string>
<string name="notification_channel_voice_mail" msgid="8457433203106654172">"Notifikasi pesan suara"</string>
@@ -249,10 +249,8 @@
<item quantity="other">Mengambil screenshot untuk laporan bug dalam <xliff:g id="NUMBER_1">%d</xliff:g> detik.</item>
<item quantity="one">Mengambil screenshot untuk laporan bug dalam <xliff:g id="NUMBER_0">%d</xliff:g> detik.</item>
</plurals>
- <!-- no translation found for bugreport_screenshot_success_toast (7986095104151473745) -->
- <skip />
- <!-- no translation found for bugreport_screenshot_failure_toast (6736320861311294294) -->
- <skip />
+ <string name="bugreport_screenshot_success_toast" msgid="7986095104151473745">"Screenshot berisi laporan bug diambil"</string>
+ <string name="bugreport_screenshot_failure_toast" msgid="6736320861311294294">"Gagal mengambil screenshot berisi laporan bug"</string>
<string name="global_action_toggle_silent_mode" msgid="8464352592860372188">"Mode senyap"</string>
<string name="global_action_silent_mode_on_status" msgid="2371892537738632013">"Suara MATI"</string>
<string name="global_action_silent_mode_off_status" msgid="6608006545950920042">"Suara AKTIF"</string>
@@ -454,9 +452,11 @@
<string name="permdesc_acceptHandovers" msgid="7129026180128626870">"Mengizinkan aplikasi melanjutkan panggilan yang dimulai di aplikasi lain."</string>
<string name="permlab_readPhoneNumbers" msgid="5668704794723365628">"membaca nomor telepon"</string>
<string name="permdesc_readPhoneNumbers" msgid="7368652482818338871">"Mengizinkan aplikasi mengakses nomor telepon perangkat."</string>
+ <string name="permlab_wakeLock" product="automotive" msgid="1904736682319375676">"tetap aktifkan layar mobil"</string>
<string name="permlab_wakeLock" product="tablet" msgid="1527660973931694000">"cegah tablet dari tidur"</string>
<string name="permlab_wakeLock" product="tv" msgid="2856941418123343518">"cegah perangkat Android TV tidur"</string>
<string name="permlab_wakeLock" product="default" msgid="569409726861695115">"mencegah ponsel menjadi tidak aktif"</string>
+ <string name="permdesc_wakeLock" product="automotive" msgid="5995045369683254571">"Mengizinkan aplikasi untuk menjaga agar layar mobil tetap aktif."</string>
<string name="permdesc_wakeLock" product="tablet" msgid="2441742939101526277">"Mengizinkan apl mencegah tablet tidur."</string>
<string name="permdesc_wakeLock" product="tv" msgid="2329298966735118796">"Mengizinkan aplikasi untuk mencegah perangkat Android TV tidur."</string>
<string name="permdesc_wakeLock" product="default" msgid="3689523792074007163">"Mengizinkan apl mencegah ponsel tidur."</string>
@@ -1631,6 +1631,12 @@
<string name="safe_media_volume_warning" product="default" msgid="3751676824423049994">"Mengeraskan volume di atas tingkat yang disarankan?\n\nMendengarkan dengan volume keras dalam waktu yang lama dapat merusak pendengaran Anda."</string>
<string name="accessibility_shortcut_warning_dialog_title" msgid="4017995837692622933">"Gunakan Pintasan Aksesibilitas?"</string>
<string name="accessibility_shortcut_toogle_warning" msgid="4161716521310929544">"Saat pintasan aktif, menekan kedua tombol volume selama 3 detik akan memulai fitur aksesibilitas."</string>
+ <!-- no translation found for accessibility_select_shortcut_menu_title (7310194076629867377) -->
+ <skip />
+ <!-- no translation found for accessibility_edit_shortcut_menu_button_title (6096484087245145325) -->
+ <skip />
+ <!-- no translation found for accessibility_edit_shortcut_menu_volume_title (4849108668454490699) -->
+ <skip />
<string name="edit_accessibility_shortcut_menu_button" msgid="8885752738733772935">"Edit pintasan"</string>
<string name="cancel_accessibility_shortcut_menu_button" msgid="1817413122335452474">"Batal"</string>
<string name="disable_accessibility_shortcut" msgid="5806091378745232383">"Nonaktifkan Pintasan"</string>
@@ -1853,8 +1859,7 @@
<string name="default_notification_channel_label" msgid="3697928973567217330">"Belum dikategorikan"</string>
<string name="importance_from_user" msgid="2782756722448800447">"Anda menyetel nilai penting notifikasi ini."</string>
<string name="importance_from_person" msgid="4235804979664465383">"Ini penting karena orang-orang yang terlibat."</string>
- <!-- no translation found for notification_history_title_placeholder (7748630986182249599) -->
- <skip />
+ <string name="notification_history_title_placeholder" msgid="7748630986182249599">"Notifikasi aplikasi kustom"</string>
<string name="user_creation_account_exists" msgid="2239146360099708035">"Izinkan <xliff:g id="APP">%1$s</xliff:g> membuat Pengguna baru dengan <xliff:g id="ACCOUNT">%2$s</xliff:g> (Pengguna dengan akun ini sudah ada) ?"</string>
<string name="user_creation_adding" msgid="7305185499667958364">"Izinkan <xliff:g id="APP">%1$s</xliff:g> membuat Pengguna baru dengan <xliff:g id="ACCOUNT">%2$s</xliff:g> ?"</string>
<string name="language_selection_title" msgid="52674936078683285">"Tambahkan bahasa"</string>
@@ -2028,14 +2033,29 @@
<string name="as_app_forced_to_restricted_bucket" msgid="8233871289353898964">"<xliff:g id="PACKAGE_NAME">%1$s</xliff:g> telah dimasukkan ke dalam bucket DIBATASI"</string>
<string name="resolver_personal_tab" msgid="2051260504014442073">"Pribadi"</string>
<string name="resolver_work_tab" msgid="2690019516263167035">"Kerja"</string>
+ <!-- no translation found for resolver_personal_tab_accessibility (5739524949153091224) -->
+ <skip />
+ <!-- no translation found for resolver_work_tab_accessibility (4753168230363802734) -->
+ <skip />
<string name="resolver_cant_share_with_work_apps" msgid="7539495559434146897">"Tidak dapat membagikan ke aplikasi kerja"</string>
<string name="resolver_cant_share_with_personal_apps" msgid="8020581735267157241">"Tidak dapat membagikan ke aplikasi pribadi"</string>
- <string name="resolver_cant_share_cross_profile_explanation" msgid="3536237105241882679">"Admin IT memblokir berbagi antara aplikasi kerja dan pribadi"</string>
- <string name="resolver_turn_on_work_apps" msgid="8987359079870455469">"Aktifkan aplikasi kerja"</string>
- <string name="resolver_turn_on_work_apps_explanation" msgid="6322467455509618928">"Aktifkan aplikasi kerja untuk mengakses aplikasi kerja &amp; kontak"</string>
+ <!-- no translation found for resolver_cant_share_cross_profile_explanation (5556640604460901386) -->
+ <skip />
+ <!-- no translation found for resolver_cant_access_work_apps (375634344111233790) -->
+ <skip />
+ <!-- no translation found for resolver_cant_access_work_apps_explanation (3958762224516867388) -->
+ <skip />
+ <!-- no translation found for resolver_cant_access_personal_apps (1953215925406474177) -->
+ <skip />
+ <!-- no translation found for resolver_cant_access_personal_apps_explanation (1725572276741281136) -->
+ <skip />
+ <!-- no translation found for resolver_turn_on_work_apps_share (619263911204978175) -->
+ <skip />
+ <!-- no translation found for resolver_turn_on_work_apps_view (3073389230905543680) -->
+ <skip />
<string name="resolver_no_apps_available" msgid="7710339903040989654">"Tidak ada aplikasi yang tersedia"</string>
- <string name="resolver_no_apps_available_explanation" msgid="4662694431121196560">"Kami tidak menemukan aplikasi"</string>
- <string name="resolver_switch_on_work" msgid="8294542702883688533">"Aktifkan profil kerja"</string>
+ <!-- no translation found for resolver_switch_on_work (2873009160846966379) -->
+ <skip />
<string name="permlab_accessCallAudio" msgid="1682957511874097664">"Rekam atau putar audio dalam panggilan telepon"</string>
<string name="permdesc_accessCallAudio" msgid="8448360894684277823">"Mengizinkan aplikasi ini, saat ditetapkan sebagai aplikasi telepon default, untuk merekam atau memutar audio dalam panggilan telepon."</string>
</resources>
diff --git a/core/res/res/values-is/strings.xml b/core/res/res/values-is/strings.xml
index 342f6f20f907..1aecb5714e1c 100644
--- a/core/res/res/values-is/strings.xml
+++ b/core/res/res/values-is/strings.xml
@@ -249,10 +249,8 @@
<item quantity="one">Tekur skjámynd fyrir villutilkynningu eftir <xliff:g id="NUMBER_1">%d</xliff:g> sekúndu.</item>
<item quantity="other">Tekur skjámynd fyrir villutilkynningu eftir <xliff:g id="NUMBER_1">%d</xliff:g> sekúndur.</item>
</plurals>
- <!-- no translation found for bugreport_screenshot_success_toast (7986095104151473745) -->
- <skip />
- <!-- no translation found for bugreport_screenshot_failure_toast (6736320861311294294) -->
- <skip />
+ <string name="bugreport_screenshot_success_toast" msgid="7986095104151473745">"Skjámynd með villutilkynningu tekin"</string>
+ <string name="bugreport_screenshot_failure_toast" msgid="6736320861311294294">"Mistókst að taka skjámynd með villutilkynningu"</string>
<string name="global_action_toggle_silent_mode" msgid="8464352592860372188">"Hljóðlaus stilling"</string>
<string name="global_action_silent_mode_on_status" msgid="2371892537738632013">"SLÖKKT er á hljóði"</string>
<string name="global_action_silent_mode_off_status" msgid="6608006545950920042">"KVEIKT er á hljóði"</string>
@@ -454,9 +452,11 @@
<string name="permdesc_acceptHandovers" msgid="7129026180128626870">"Leyfir forritinu að halda áfram með símtal sem hófst í öðru forriti."</string>
<string name="permlab_readPhoneNumbers" msgid="5668704794723365628">"lesa símanúmer"</string>
<string name="permdesc_readPhoneNumbers" msgid="7368652482818338871">"Veitir forritinu aðgang að símanúmerum tækisins."</string>
+ <string name="permlab_wakeLock" product="automotive" msgid="1904736682319375676">"hafa kveikt á skjá bílsins"</string>
<string name="permlab_wakeLock" product="tablet" msgid="1527660973931694000">"koma í veg fyrir að spjaldtölvan fari í biðstöðu"</string>
<string name="permlab_wakeLock" product="tv" msgid="2856941418123343518">"koma í veg fyrir að Android TV fari í biðstöðu"</string>
<string name="permlab_wakeLock" product="default" msgid="569409726861695115">"koma í veg fyrir að síminn fari í biðstöðu"</string>
+ <string name="permdesc_wakeLock" product="automotive" msgid="5995045369683254571">"Gerir forritinu kleift að hafa kveikt á skjá bílsins."</string>
<string name="permdesc_wakeLock" product="tablet" msgid="2441742939101526277">"Leyfir forriti að koma í veg fyrir að spjaldtölvan fari í biðstöðu."</string>
<string name="permdesc_wakeLock" product="tv" msgid="2329298966735118796">"Leyfir forritinu að koma í veg fyrir að Android TV tækið fari í biðstöðu."</string>
<string name="permdesc_wakeLock" product="default" msgid="3689523792074007163">"Leyfir forriti að koma í veg fyrir að síminn fari í biðstöðu."</string>
@@ -1631,6 +1631,12 @@
<string name="safe_media_volume_warning" product="default" msgid="3751676824423049994">"Hækka hljóðstyrk umfram ráðlagðan styrk?\n\nEf hlustað er á háum hljóðstyrk í langan tíma kann það að skaða heyrnina."</string>
<string name="accessibility_shortcut_warning_dialog_title" msgid="4017995837692622933">"Viltu nota aðgengisflýtileið?"</string>
<string name="accessibility_shortcut_toogle_warning" msgid="4161716521310929544">"Þegar flýtileiðin er virk er kveikt á aðgengiseiginleikanum með því að halda báðum hljóðstyrkshnöppunum inni í þrjár sekúndur."</string>
+ <!-- no translation found for accessibility_select_shortcut_menu_title (7310194076629867377) -->
+ <skip />
+ <!-- no translation found for accessibility_edit_shortcut_menu_button_title (6096484087245145325) -->
+ <skip />
+ <!-- no translation found for accessibility_edit_shortcut_menu_volume_title (4849108668454490699) -->
+ <skip />
<string name="edit_accessibility_shortcut_menu_button" msgid="8885752738733772935">"Breyta flýtileiðum"</string>
<string name="cancel_accessibility_shortcut_menu_button" msgid="1817413122335452474">"Hætta við"</string>
<string name="disable_accessibility_shortcut" msgid="5806091378745232383">"Slökkva á flýtileið"</string>
@@ -1853,8 +1859,7 @@
<string name="default_notification_channel_label" msgid="3697928973567217330">"Óflokkað"</string>
<string name="importance_from_user" msgid="2782756722448800447">"Þú stilltir mikilvægi þessara tilkynninga."</string>
<string name="importance_from_person" msgid="4235804979664465383">"Þetta er mikilvægt vegna fólksins sem tekur þátt í þessu."</string>
- <!-- no translation found for notification_history_title_placeholder (7748630986182249599) -->
- <skip />
+ <string name="notification_history_title_placeholder" msgid="7748630986182249599">"Sérsniðin forritatilkynning"</string>
<string name="user_creation_account_exists" msgid="2239146360099708035">"Viltu leyfa <xliff:g id="APP">%1$s</xliff:g> að stofna nýjan notanda með <xliff:g id="ACCOUNT">%2$s</xliff:g> (notandi með þennan reikning er þegar fyrir hendi)?"</string>
<string name="user_creation_adding" msgid="7305185499667958364">"Leyfa <xliff:g id="APP">%1$s</xliff:g> að stofna nýjan notanda með <xliff:g id="ACCOUNT">%2$s</xliff:g> ?"</string>
<string name="language_selection_title" msgid="52674936078683285">"Bæta við tungumáli"</string>
@@ -2028,14 +2033,29 @@
<string name="as_app_forced_to_restricted_bucket" msgid="8233871289353898964">"<xliff:g id="PACKAGE_NAME">%1$s</xliff:g> var sett í flokkinn TAKMARKAÐ"</string>
<string name="resolver_personal_tab" msgid="2051260504014442073">"Persónulegt"</string>
<string name="resolver_work_tab" msgid="2690019516263167035">"Vinna"</string>
+ <!-- no translation found for resolver_personal_tab_accessibility (5739524949153091224) -->
+ <skip />
+ <!-- no translation found for resolver_work_tab_accessibility (4753168230363802734) -->
+ <skip />
<string name="resolver_cant_share_with_work_apps" msgid="7539495559434146897">"Ekki er hægt að deila með vinnuforritum"</string>
<string name="resolver_cant_share_with_personal_apps" msgid="8020581735267157241">"Ekki er hægt að deila með persónulegum forritum"</string>
- <string name="resolver_cant_share_cross_profile_explanation" msgid="3536237105241882679">"Kerfisstjórinn þinn hefur lokað á deilingu milli persónulegra forrita og vinnuforrita"</string>
- <string name="resolver_turn_on_work_apps" msgid="8987359079870455469">"Kveikja á vinnuforritum"</string>
- <string name="resolver_turn_on_work_apps_explanation" msgid="6322467455509618928">"Kveiktu á vinnuforritum til að fá aðgang að þeim og vinnutengiliðum"</string>
+ <!-- no translation found for resolver_cant_share_cross_profile_explanation (5556640604460901386) -->
+ <skip />
+ <!-- no translation found for resolver_cant_access_work_apps (375634344111233790) -->
+ <skip />
+ <!-- no translation found for resolver_cant_access_work_apps_explanation (3958762224516867388) -->
+ <skip />
+ <!-- no translation found for resolver_cant_access_personal_apps (1953215925406474177) -->
+ <skip />
+ <!-- no translation found for resolver_cant_access_personal_apps_explanation (1725572276741281136) -->
+ <skip />
+ <!-- no translation found for resolver_turn_on_work_apps_share (619263911204978175) -->
+ <skip />
+ <!-- no translation found for resolver_turn_on_work_apps_view (3073389230905543680) -->
+ <skip />
<string name="resolver_no_apps_available" msgid="7710339903040989654">"Engin forrit í boði"</string>
- <string name="resolver_no_apps_available_explanation" msgid="4662694431121196560">"Við fundum engin forrit"</string>
- <string name="resolver_switch_on_work" msgid="8294542702883688533">"Skipta yfir í vinnu"</string>
+ <!-- no translation found for resolver_switch_on_work (2873009160846966379) -->
+ <skip />
<string name="permlab_accessCallAudio" msgid="1682957511874097664">"Taka upp eða spila hljóð í símtölum"</string>
<string name="permdesc_accessCallAudio" msgid="8448360894684277823">"Gerir þessu forriti kleift að taka upp og spila hljóð í símtölum þegar það er valið sem sjálfgefið hringiforrit."</string>
</resources>
diff --git a/core/res/res/values-it/strings.xml b/core/res/res/values-it/strings.xml
index 783e45ed33b2..85fbf617a165 100644
--- a/core/res/res/values-it/strings.xml
+++ b/core/res/res/values-it/strings.xml
@@ -249,10 +249,8 @@
<item quantity="other">Lo screenshot per la segnalazione di bug verrà acquisito tra <xliff:g id="NUMBER_1">%d</xliff:g> secondi.</item>
<item quantity="one">Lo screenshot per la segnalazione di bug verrà acquisito tra <xliff:g id="NUMBER_0">%d</xliff:g> secondo.</item>
</plurals>
- <!-- no translation found for bugreport_screenshot_success_toast (7986095104151473745) -->
- <skip />
- <!-- no translation found for bugreport_screenshot_failure_toast (6736320861311294294) -->
- <skip />
+ <string name="bugreport_screenshot_success_toast" msgid="7986095104151473745">"Screenshot con segnalazione di bug effettuato correttamente"</string>
+ <string name="bugreport_screenshot_failure_toast" msgid="6736320861311294294">"Impossibile acquisire screenshot con segnalazione di bug"</string>
<string name="global_action_toggle_silent_mode" msgid="8464352592860372188">"Modalità silenziosa"</string>
<string name="global_action_silent_mode_on_status" msgid="2371892537738632013">"Audio non attivo"</string>
<string name="global_action_silent_mode_off_status" msgid="6608006545950920042">"Audio attivo"</string>
@@ -454,9 +452,11 @@
<string name="permdesc_acceptHandovers" msgid="7129026180128626870">"Consente all\'app di continuare una chiamata che è stata iniziata in un\'altra app."</string>
<string name="permlab_readPhoneNumbers" msgid="5668704794723365628">"lettura dei numeri di telefono"</string>
<string name="permdesc_readPhoneNumbers" msgid="7368652482818338871">"Consente all\'app di accedere ai numeri di telefono del dispositivo."</string>
+ <string name="permlab_wakeLock" product="automotive" msgid="1904736682319375676">"Mantenere attivo lo schermo dell\'auto"</string>
<string name="permlab_wakeLock" product="tablet" msgid="1527660973931694000">"disattivazione stand-by del tablet"</string>
<string name="permlab_wakeLock" product="tv" msgid="2856941418123343518">"Blocco dell\'attivazione della modalità di sospensione del dispositivo Android TV"</string>
<string name="permlab_wakeLock" product="default" msgid="569409726861695115">"disattivazione stand-by del telefono"</string>
+ <string name="permdesc_wakeLock" product="automotive" msgid="5995045369683254571">"Consente all\'app di mantenere attivo lo schermo dell\'auto."</string>
<string name="permdesc_wakeLock" product="tablet" msgid="2441742939101526277">"Consente all\'applicazione di impedire lo stand-by del tablet."</string>
<string name="permdesc_wakeLock" product="tv" msgid="2329298966735118796">"Consente all\'app di impedire l\'attivazione della modalità di sospensione del dispositivo Android TV."</string>
<string name="permdesc_wakeLock" product="default" msgid="3689523792074007163">"Consente all\'applicazione di impedire lo stand-by del telefono."</string>
@@ -1631,6 +1631,12 @@
<string name="safe_media_volume_warning" product="default" msgid="3751676824423049994">"Vuoi aumentare il volume oltre il livello consigliato?\n\nL\'ascolto ad alto volume per lunghi periodi di tempo potrebbe danneggiare l\'udito."</string>
<string name="accessibility_shortcut_warning_dialog_title" msgid="4017995837692622933">"Usare la scorciatoia Accessibilità?"</string>
<string name="accessibility_shortcut_toogle_warning" msgid="4161716521310929544">"Quando la scorciatoia è attiva, puoi premere entrambi i pulsanti del volume per tre secondi per avviare una funzione di accessibilità."</string>
+ <!-- no translation found for accessibility_select_shortcut_menu_title (7310194076629867377) -->
+ <skip />
+ <!-- no translation found for accessibility_edit_shortcut_menu_button_title (6096484087245145325) -->
+ <skip />
+ <!-- no translation found for accessibility_edit_shortcut_menu_volume_title (4849108668454490699) -->
+ <skip />
<string name="edit_accessibility_shortcut_menu_button" msgid="8885752738733772935">"Modifica scorciatoie"</string>
<string name="cancel_accessibility_shortcut_menu_button" msgid="1817413122335452474">"Annulla"</string>
<string name="disable_accessibility_shortcut" msgid="5806091378745232383">"Disattiva scorciatoia"</string>
@@ -1853,8 +1859,7 @@
<string name="default_notification_channel_label" msgid="3697928973567217330">"Senza categoria"</string>
<string name="importance_from_user" msgid="2782756722448800447">"Stabilisci tu l\'importanza di queste notifiche."</string>
<string name="importance_from_person" msgid="4235804979664465383">"Importante a causa delle persone coinvolte."</string>
- <!-- no translation found for notification_history_title_placeholder (7748630986182249599) -->
- <skip />
+ <string name="notification_history_title_placeholder" msgid="7748630986182249599">"Notifica app personalizzata"</string>
<string name="user_creation_account_exists" msgid="2239146360099708035">"Consentire a <xliff:g id="APP">%1$s</xliff:g> di creare un nuovo utente con l\'account <xliff:g id="ACCOUNT">%2$s</xliff:g> (esiste già un utente con questo account)?"</string>
<string name="user_creation_adding" msgid="7305185499667958364">"Consentire a <xliff:g id="APP">%1$s</xliff:g> di creare un nuovo utente con l\'account <xliff:g id="ACCOUNT">%2$s</xliff:g>?"</string>
<string name="language_selection_title" msgid="52674936078683285">"Aggiungi una lingua"</string>
@@ -2028,14 +2033,29 @@
<string name="as_app_forced_to_restricted_bucket" msgid="8233871289353898964">"<xliff:g id="PACKAGE_NAME">%1$s</xliff:g> è stato inserito nel bucket RESTRICTED"</string>
<string name="resolver_personal_tab" msgid="2051260504014442073">"Personale"</string>
<string name="resolver_work_tab" msgid="2690019516263167035">"Lavoro"</string>
+ <!-- no translation found for resolver_personal_tab_accessibility (5739524949153091224) -->
+ <skip />
+ <!-- no translation found for resolver_work_tab_accessibility (4753168230363802734) -->
+ <skip />
<string name="resolver_cant_share_with_work_apps" msgid="7539495559434146897">"Impossibile condividere con app di lavoro"</string>
<string name="resolver_cant_share_with_personal_apps" msgid="8020581735267157241">"Impossibile condividere con app personali"</string>
- <string name="resolver_cant_share_cross_profile_explanation" msgid="3536237105241882679">"Il tuo amministratore IT ha bloccato la condivisione tra app personali e di lavoro"</string>
- <string name="resolver_turn_on_work_apps" msgid="8987359079870455469">"Attiva app di lavoro"</string>
- <string name="resolver_turn_on_work_apps_explanation" msgid="6322467455509618928">"Attiva le app di lavoro per accedere alle app e ai contatti di lavoro"</string>
+ <!-- no translation found for resolver_cant_share_cross_profile_explanation (5556640604460901386) -->
+ <skip />
+ <!-- no translation found for resolver_cant_access_work_apps (375634344111233790) -->
+ <skip />
+ <!-- no translation found for resolver_cant_access_work_apps_explanation (3958762224516867388) -->
+ <skip />
+ <!-- no translation found for resolver_cant_access_personal_apps (1953215925406474177) -->
+ <skip />
+ <!-- no translation found for resolver_cant_access_personal_apps_explanation (1725572276741281136) -->
+ <skip />
+ <!-- no translation found for resolver_turn_on_work_apps_share (619263911204978175) -->
+ <skip />
+ <!-- no translation found for resolver_turn_on_work_apps_view (3073389230905543680) -->
+ <skip />
<string name="resolver_no_apps_available" msgid="7710339903040989654">"Nessuna app disponibile"</string>
- <string name="resolver_no_apps_available_explanation" msgid="4662694431121196560">"Nessuna app trovata"</string>
- <string name="resolver_switch_on_work" msgid="8294542702883688533">"Attiva profilo di lavoro"</string>
+ <!-- no translation found for resolver_switch_on_work (2873009160846966379) -->
+ <skip />
<string name="permlab_accessCallAudio" msgid="1682957511874097664">"Registrazione o riproduzione dell\'audio delle telefonate"</string>
<string name="permdesc_accessCallAudio" msgid="8448360894684277823">"Consente a questa app, se assegnata come applicazione telefono predefinita, di registrare o riprodurre l\'audio delle telefonate."</string>
</resources>
diff --git a/core/res/res/values-iw/strings.xml b/core/res/res/values-iw/strings.xml
index b2b56578d527..b4e47e3b7ec8 100644
--- a/core/res/res/values-iw/strings.xml
+++ b/core/res/res/values-iw/strings.xml
@@ -255,10 +255,8 @@
<item quantity="other">יוצר צילום מסך לדוח על באג בעוד <xliff:g id="NUMBER_1">%d</xliff:g> שניות.</item>
<item quantity="one">יוצר צילום מסך לדוח על באג בעוד שנייה <xliff:g id="NUMBER_0">%d</xliff:g>.</item>
</plurals>
- <!-- no translation found for bugreport_screenshot_success_toast (7986095104151473745) -->
- <skip />
- <!-- no translation found for bugreport_screenshot_failure_toast (6736320861311294294) -->
- <skip />
+ <string name="bugreport_screenshot_success_toast" msgid="7986095104151473745">"בוצע צילום מסך של דוח על באג"</string>
+ <string name="bugreport_screenshot_failure_toast" msgid="6736320861311294294">"הניסיון לצילום המסך של דוח על באג נכשל"</string>
<string name="global_action_toggle_silent_mode" msgid="8464352592860372188">"מצב שקט"</string>
<string name="global_action_silent_mode_on_status" msgid="2371892537738632013">"הקול כבוי"</string>
<string name="global_action_silent_mode_off_status" msgid="6608006545950920042">"קול מופעל"</string>
@@ -460,9 +458,11 @@
<string name="permdesc_acceptHandovers" msgid="7129026180128626870">"הרשאה זו מתירה לאפליקציה להמשיך שיחה שהחלה באפליקציה אחרת."</string>
<string name="permlab_readPhoneNumbers" msgid="5668704794723365628">"גישה למספרי הטלפון"</string>
<string name="permdesc_readPhoneNumbers" msgid="7368652482818338871">"מתירה לאפליקציה גישה למספרי הטלפון במכשיר."</string>
+ <string name="permlab_wakeLock" product="automotive" msgid="1904736682319375676">"מסך המכונית יישאר דלוק"</string>
<string name="permlab_wakeLock" product="tablet" msgid="1527660973931694000">"מנע מהטאבלט לעבור למצב שינה"</string>
<string name="permlab_wakeLock" product="tv" msgid="2856941418123343518">"‏מונעת ממכשיר ה-Android TV להיכנס למצב שינה"</string>
<string name="permlab_wakeLock" product="default" msgid="569409726861695115">"מניעת מעבר הטלפון למצב שינה"</string>
+ <string name="permdesc_wakeLock" product="automotive" msgid="5995045369683254571">"מסך המכונית יישאר דלוק כשהאפליקציה פועלת."</string>
<string name="permdesc_wakeLock" product="tablet" msgid="2441742939101526277">"מאפשר לאפליקציה למנוע מהטאבלט לעבור למצב שינה."</string>
<string name="permdesc_wakeLock" product="tv" msgid="2329298966735118796">"‏מאפשרת לאפליקציה למנוע ממכשיר ה-Android TV לעבור למצב שינה."</string>
<string name="permdesc_wakeLock" product="default" msgid="3689523792074007163">"מאפשר לאפליקציה למנוע מהטלפון לעבור למצב שינה."</string>
@@ -1675,6 +1675,12 @@
<string name="safe_media_volume_warning" product="default" msgid="3751676824423049994">"האם להעלות את עוצמת הקול מעל לרמה המומלצת?\n\nהאזנה בעוצמת קול גבוהה למשכי זמן ממושכים עלולה לפגוע בשמיעה."</string>
<string name="accessibility_shortcut_warning_dialog_title" msgid="4017995837692622933">"להשתמש בקיצור הדרך לתכונת הנגישות?"</string>
<string name="accessibility_shortcut_toogle_warning" msgid="4161716521310929544">"כשקיצור הדרך מופעל, לחיצה על שני לחצני עוצמת הקול למשך שלוש שניות מפעילה את תכונת הנגישות."</string>
+ <!-- no translation found for accessibility_select_shortcut_menu_title (7310194076629867377) -->
+ <skip />
+ <!-- no translation found for accessibility_edit_shortcut_menu_button_title (6096484087245145325) -->
+ <skip />
+ <!-- no translation found for accessibility_edit_shortcut_menu_volume_title (4849108668454490699) -->
+ <skip />
<string name="edit_accessibility_shortcut_menu_button" msgid="8885752738733772935">"עריכת קיצורי הדרך"</string>
<string name="cancel_accessibility_shortcut_menu_button" msgid="1817413122335452474">"ביטול"</string>
<string name="disable_accessibility_shortcut" msgid="5806091378745232383">"כבה את קיצור הדרך"</string>
@@ -1917,8 +1923,7 @@
<string name="default_notification_channel_label" msgid="3697928973567217330">"ללא שיוך לקטגוריה"</string>
<string name="importance_from_user" msgid="2782756722448800447">"עליך להגדיר את החשיבות של ההתראות האלה."</string>
<string name="importance_from_person" msgid="4235804979664465383">"ההודעה חשובה בשל האנשים המעורבים."</string>
- <!-- no translation found for notification_history_title_placeholder (7748630986182249599) -->
- <skip />
+ <string name="notification_history_title_placeholder" msgid="7748630986182249599">"התראות אפליקציה בהתאמה אישית"</string>
<string name="user_creation_account_exists" msgid="2239146360099708035">"האם לאפשר לאפליקציה <xliff:g id="APP">%1$s</xliff:g> ליצור משתמש חדש באמצעות <xliff:g id="ACCOUNT">%2$s</xliff:g> (כבר קיים משתמש לחשבון הזה) ?"</string>
<string name="user_creation_adding" msgid="7305185499667958364">"האם לאפשר לאפליקציה <xliff:g id="APP">%1$s</xliff:g> ליצור משתמש חדש באמצעות <xliff:g id="ACCOUNT">%2$s</xliff:g> ?"</string>
<string name="language_selection_title" msgid="52674936078683285">"הוספת שפה"</string>
@@ -2096,14 +2101,29 @@
<string name="as_app_forced_to_restricted_bucket" msgid="8233871289353898964">"<xliff:g id="PACKAGE_NAME">%1$s</xliff:g> התווספה לקטגוריה \'מוגבל\'"</string>
<string name="resolver_personal_tab" msgid="2051260504014442073">"אישי"</string>
<string name="resolver_work_tab" msgid="2690019516263167035">"עבודה"</string>
+ <!-- no translation found for resolver_personal_tab_accessibility (5739524949153091224) -->
+ <skip />
+ <!-- no translation found for resolver_work_tab_accessibility (4753168230363802734) -->
+ <skip />
<string name="resolver_cant_share_with_work_apps" msgid="7539495559434146897">"לא ניתן לשתף עם אפליקציות לעבודה"</string>
<string name="resolver_cant_share_with_personal_apps" msgid="8020581735267157241">"לא ניתן לשתף עם אפליקציות פרטיות"</string>
- <string name="resolver_cant_share_cross_profile_explanation" msgid="3536237105241882679">"‏השיתוף בין אפליקציות לעבודה לאפליקציות פרטיות נחסמה על ידי מנהל ה-IT"</string>
- <string name="resolver_turn_on_work_apps" msgid="8987359079870455469">"הפעלה של אפליקציות לעבודה"</string>
- <string name="resolver_turn_on_work_apps_explanation" msgid="6322467455509618928">"יש להפעיל אפליקציות לעבודה כדי לגשת אל אפליקציות ואנשי קשר לעבודה"</string>
+ <!-- no translation found for resolver_cant_share_cross_profile_explanation (5556640604460901386) -->
+ <skip />
+ <!-- no translation found for resolver_cant_access_work_apps (375634344111233790) -->
+ <skip />
+ <!-- no translation found for resolver_cant_access_work_apps_explanation (3958762224516867388) -->
+ <skip />
+ <!-- no translation found for resolver_cant_access_personal_apps (1953215925406474177) -->
+ <skip />
+ <!-- no translation found for resolver_cant_access_personal_apps_explanation (1725572276741281136) -->
+ <skip />
+ <!-- no translation found for resolver_turn_on_work_apps_share (619263911204978175) -->
+ <skip />
+ <!-- no translation found for resolver_turn_on_work_apps_view (3073389230905543680) -->
+ <skip />
<string name="resolver_no_apps_available" msgid="7710339903040989654">"אין אפליקציות זמינות"</string>
- <string name="resolver_no_apps_available_explanation" msgid="4662694431121196560">"לא מצאנו אפליקציות"</string>
- <string name="resolver_switch_on_work" msgid="8294542702883688533">"הפעלה לעבודה"</string>
+ <!-- no translation found for resolver_switch_on_work (2873009160846966379) -->
+ <skip />
<string name="permlab_accessCallAudio" msgid="1682957511874097664">"הקלטה או הפעלה של אודיו בשיחות טלפוניות"</string>
<string name="permdesc_accessCallAudio" msgid="8448360894684277823">"כאשר האפליקציה הזו מוגדרת כאפליקציית חייגן בברירת מחדל, תהיה לה הרשאה להקליט ולהפעיל אודיו בשיחות טלפוניות."</string>
</resources>
diff --git a/core/res/res/values-ja/strings.xml b/core/res/res/values-ja/strings.xml
index 850f6016af96..1a7f30159b68 100644
--- a/core/res/res/values-ja/strings.xml
+++ b/core/res/res/values-ja/strings.xml
@@ -249,10 +249,8 @@
<item quantity="other"><xliff:g id="NUMBER_1">%d</xliff:g> 秒後にバグレポートのスクリーンショットが作成されます。</item>
<item quantity="one"><xliff:g id="NUMBER_0">%d</xliff:g> 秒後にバグレポートのスクリーンショットが作成されます。</item>
</plurals>
- <!-- no translation found for bugreport_screenshot_success_toast (7986095104151473745) -->
- <skip />
- <!-- no translation found for bugreport_screenshot_failure_toast (6736320861311294294) -->
- <skip />
+ <string name="bugreport_screenshot_success_toast" msgid="7986095104151473745">"バグレポートのスクリーンショットを取得しました"</string>
+ <string name="bugreport_screenshot_failure_toast" msgid="6736320861311294294">"バグレポートのスクリーンショットを取得できませんでした"</string>
<string name="global_action_toggle_silent_mode" msgid="8464352592860372188">"マナーモード"</string>
<string name="global_action_silent_mode_on_status" msgid="2371892537738632013">"サウンドOFF"</string>
<string name="global_action_silent_mode_off_status" msgid="6608006545950920042">"サウンドON"</string>
@@ -454,9 +452,11 @@
<string name="permdesc_acceptHandovers" msgid="7129026180128626870">"別のアプリで通話を続行することをこのアプリに許可します。"</string>
<string name="permlab_readPhoneNumbers" msgid="5668704794723365628">"電話番号の読み取り"</string>
<string name="permdesc_readPhoneNumbers" msgid="7368652482818338871">"デバイスの電話番号へのアクセスをアプリに許可します。"</string>
+ <string name="permlab_wakeLock" product="automotive" msgid="1904736682319375676">"車の画面を常にオンにする"</string>
<string name="permlab_wakeLock" product="tablet" msgid="1527660973931694000">"タブレットのスリープを無効化"</string>
<string name="permlab_wakeLock" product="tv" msgid="2856941418123343518">"Android TV デバイスのスリープの無効化"</string>
<string name="permlab_wakeLock" product="default" msgid="569409726861695115">"デバイスのスリープを無効にする"</string>
+ <string name="permdesc_wakeLock" product="automotive" msgid="5995045369683254571">"車の画面を常にオンにすることをアプリに許可します。"</string>
<string name="permdesc_wakeLock" product="tablet" msgid="2441742939101526277">"タブレットのスリープを無効にすることをアプリに許可します。"</string>
<string name="permdesc_wakeLock" product="tv" msgid="2329298966735118796">"Android TV デバイスのスリープを無効にすることをアプリに許可します。"</string>
<string name="permdesc_wakeLock" product="default" msgid="3689523792074007163">"モバイル デバイスのスリープを無効にすることをアプリに許可します。"</string>
@@ -1631,6 +1631,9 @@
<string name="safe_media_volume_warning" product="default" msgid="3751676824423049994">"推奨レベルを超えるまで音量を上げますか?\n\n大音量で長時間聞き続けると、聴力を損なう恐れがあります。"</string>
<string name="accessibility_shortcut_warning_dialog_title" msgid="4017995837692622933">"ユーザー補助機能のショートカットの使用"</string>
<string name="accessibility_shortcut_toogle_warning" msgid="4161716521310929544">"ショートカットが ON の場合、両方の音量ボタンを 3 秒ほど長押しするとユーザー補助機能が起動します。"</string>
+ <string name="accessibility_select_shortcut_menu_title" msgid="7310194076629867377">"使用するユーザー補助アプリをタップ"</string>
+ <string name="accessibility_edit_shortcut_menu_button_title" msgid="6096484087245145325">"ユーザー補助機能ボタンで使用できるアプリを選択"</string>
+ <string name="accessibility_edit_shortcut_menu_volume_title" msgid="4849108668454490699">"音量キーのショートカットで使用できるアプリを選択"</string>
<string name="edit_accessibility_shortcut_menu_button" msgid="8885752738733772935">"ショートカットの編集"</string>
<string name="cancel_accessibility_shortcut_menu_button" msgid="1817413122335452474">"キャンセル"</string>
<string name="disable_accessibility_shortcut" msgid="5806091378745232383">"ショートカットを OFF にする"</string>
@@ -1773,8 +1776,8 @@
<string name="package_updated_device_owner" msgid="7560272363805506941">"管理者により更新されています"</string>
<string name="package_deleted_device_owner" msgid="2292335928930293023">"管理者により削除されています"</string>
<string name="confirm_battery_saver" msgid="5247976246208245754">"OK"</string>
- <string name="battery_saver_description_with_learn_more" msgid="1817385558636532621">"電池を長持ちさせるためにバッテリー セーバーが行う操作:\n·ダークテーマをオンにする\n·バックグラウンド アクティビティ、一部の視覚効果や、「OK Google」などの機能をオフにする、または制限する\n\n"<annotation id="url">"詳細"</annotation></string>
- <string name="battery_saver_description" msgid="7618492104632328184">"電池を長持ちさせるためにバッテリー セーバーが行う操作:\n·ダークテーマをオンにする\n·バックグラウンド アクティビティ、一部の視覚効果や、「OK Google」などの機能をオフにする、または制限する"</string>
+ <string name="battery_saver_description_with_learn_more" msgid="1817385558636532621">"電池を長持ちさせるためにバッテリー セーバーが行う操作:\n·ダークテーマを ON にする\n·バックグラウンド アクティビティ、一部の視覚効果や、「OK Google」などの機能を OFF にする、または制限する\n\n"<annotation id="url">"詳細"</annotation></string>
+ <string name="battery_saver_description" msgid="7618492104632328184">"電池を長持ちさせるためにバッテリー セーバーが行う操作:\n·ダークテーマを ON にする\n·バックグラウンド アクティビティ、一部の視覚効果や、「OK Google」などの機能を OFF にする、または制限する"</string>
<string name="data_saver_description" msgid="4995164271550590517">"データセーバーは、一部のアプリによるバックグラウンドでのデータ送受信を停止することでデータ使用量を抑制します。使用中のアプリからデータにアクセスすることはできますが、その頻度は低くなる場合があります。この影響として、たとえば画像はタップしないと表示されないようになります。"</string>
<string name="data_saver_enable_title" msgid="7080620065745260137">"データセーバーを ON にしますか?"</string>
<string name="data_saver_enable_button" msgid="4399405762586419726">"ON にする"</string>
@@ -1853,8 +1856,7 @@
<string name="default_notification_channel_label" msgid="3697928973567217330">"カテゴリなし"</string>
<string name="importance_from_user" msgid="2782756722448800447">"このような通知の重要度を設定します。"</string>
<string name="importance_from_person" msgid="4235804979664465383">"関係するユーザーのため、この設定は重要です。"</string>
- <!-- no translation found for notification_history_title_placeholder (7748630986182249599) -->
- <skip />
+ <string name="notification_history_title_placeholder" msgid="7748630986182249599">"カスタムアプリ通知"</string>
<string name="user_creation_account_exists" msgid="2239146360099708035">"<xliff:g id="APP">%1$s</xliff:g> が <xliff:g id="ACCOUNT">%2$s</xliff:g> で新しいユーザーを作成できるようにしますか?(このアカウントのユーザーはすでに存在します)"</string>
<string name="user_creation_adding" msgid="7305185499667958364">"<xliff:g id="APP">%1$s</xliff:g> が <xliff:g id="ACCOUNT">%2$s</xliff:g> で新しいユーザーを作成できるようにしますか?"</string>
<string name="language_selection_title" msgid="52674936078683285">"言語を追加"</string>
@@ -2028,14 +2030,19 @@
<string name="as_app_forced_to_restricted_bucket" msgid="8233871289353898964">"<xliff:g id="PACKAGE_NAME">%1$s</xliff:g> は RESTRICTED バケットに移動しました。"</string>
<string name="resolver_personal_tab" msgid="2051260504014442073">"個人用"</string>
<string name="resolver_work_tab" msgid="2690019516263167035">"仕事用"</string>
+ <string name="resolver_personal_tab_accessibility" msgid="5739524949153091224">"個人用ビュー"</string>
+ <string name="resolver_work_tab_accessibility" msgid="4753168230363802734">"仕事用ビュー"</string>
<string name="resolver_cant_share_with_work_apps" msgid="7539495559434146897">"仕事用アプリと共有できません"</string>
<string name="resolver_cant_share_with_personal_apps" msgid="8020581735267157241">"個人用アプリと共有できません"</string>
- <string name="resolver_cant_share_cross_profile_explanation" msgid="3536237105241882679">"IT 管理者が個人用アプリと仕事用アプリの間の共有をブロックしました"</string>
- <string name="resolver_turn_on_work_apps" msgid="8987359079870455469">"仕事用アプリを ON にする"</string>
- <string name="resolver_turn_on_work_apps_explanation" msgid="6322467455509618928">"仕事用のアプリや連絡先にアクセスするには、仕事用アプリを ON にしてください"</string>
+ <string name="resolver_cant_share_cross_profile_explanation" msgid="5556640604460901386">"IT 管理者が個人用プロファイルと仕事用プロファイルの間の共有をブロックしました"</string>
+ <string name="resolver_cant_access_work_apps" msgid="375634344111233790">"仕事用アプリにアクセスできません"</string>
+ <string name="resolver_cant_access_work_apps_explanation" msgid="3958762224516867388">"IT 管理者は個人用コンテンツを仕事用アプリで表示することを許可していません"</string>
+ <string name="resolver_cant_access_personal_apps" msgid="1953215925406474177">"個人用アプリにアクセスできません"</string>
+ <string name="resolver_cant_access_personal_apps_explanation" msgid="1725572276741281136">"IT 管理者は仕事用コンテンツを個人用アプリで表示することを許可していません"</string>
+ <string name="resolver_turn_on_work_apps_share" msgid="619263911204978175">"コンテンツを共有するには、仕事用プロファイルをオンにしてください"</string>
+ <string name="resolver_turn_on_work_apps_view" msgid="3073389230905543680">"コンテンツを表示するには、仕事用プロファイルをオンにしてください"</string>
<string name="resolver_no_apps_available" msgid="7710339903040989654">"利用できるアプリはありません"</string>
- <string name="resolver_no_apps_available_explanation" msgid="4662694431121196560">"アプリが見つかりませんでした"</string>
- <string name="resolver_switch_on_work" msgid="8294542702883688533">"仕事用に切り替え"</string>
+ <string name="resolver_switch_on_work" msgid="2873009160846966379">"オンにする"</string>
<string name="permlab_accessCallAudio" msgid="1682957511874097664">"通話中に録音または音声の再生を行う"</string>
<string name="permdesc_accessCallAudio" msgid="8448360894684277823">"デフォルトの電話アプリケーションとして割り当てられている場合、このアプリに通話中の録音または音声の再生を許可します。"</string>
</resources>
diff --git a/core/res/res/values-ka/strings.xml b/core/res/res/values-ka/strings.xml
index 1ed4854a4155..e1c97331df55 100644
--- a/core/res/res/values-ka/strings.xml
+++ b/core/res/res/values-ka/strings.xml
@@ -249,10 +249,8 @@
<item quantity="other">ხარვეზის შესახებ ანგარიშის ეკრანის ანაბეჭდის გადაღება მოხდება <xliff:g id="NUMBER_1">%d</xliff:g> წამში.</item>
<item quantity="one">ხარვეზის შესახებ ანგარიშის ეკრანის ანაბეჭდის გადაღება მოხდება <xliff:g id="NUMBER_0">%d</xliff:g> წამში.</item>
</plurals>
- <!-- no translation found for bugreport_screenshot_success_toast (7986095104151473745) -->
- <skip />
- <!-- no translation found for bugreport_screenshot_failure_toast (6736320861311294294) -->
- <skip />
+ <string name="bugreport_screenshot_success_toast" msgid="7986095104151473745">"სისტემის ხარვეზის ანგარიშის ეკრანის ანაბეჭდი გადაღებულია"</string>
+ <string name="bugreport_screenshot_failure_toast" msgid="6736320861311294294">"სისტემის ხარვეზის ანგარიშის ეკრანის ანაბეჭდის გადაღება ვერ მოხერხდა"</string>
<string name="global_action_toggle_silent_mode" msgid="8464352592860372188">"ჩუმი რეჟიმი"</string>
<string name="global_action_silent_mode_on_status" msgid="2371892537738632013">"ხმა გამორთულია"</string>
<string name="global_action_silent_mode_off_status" msgid="6608006545950920042">"ხმა ჩართულია"</string>
@@ -454,9 +452,11 @@
<string name="permdesc_acceptHandovers" msgid="7129026180128626870">"ნებას რთავს აპს, გააგრძელოს ზარი, რომელიც სხვა აპშია წამოწყებული."</string>
<string name="permlab_readPhoneNumbers" msgid="5668704794723365628">"ტელეფონის ნომრების წაკითხვა"</string>
<string name="permdesc_readPhoneNumbers" msgid="7368652482818338871">"აპს მოწყობილობის ტელეფონის ნომრებზე წვდომის საშუალებას მისცემს."</string>
+ <string name="permlab_wakeLock" product="automotive" msgid="1904736682319375676">"ჩართული ჰქონდეს მანქანის ეკრანი"</string>
<string name="permlab_wakeLock" product="tablet" msgid="1527660973931694000">"დაიცავით ტაბლეტი დაძინებისგან"</string>
<string name="permlab_wakeLock" product="tv" msgid="2856941418123343518">"არ მისცეთ დაძინების საშუალება Android TV მოწყობილობას"</string>
<string name="permlab_wakeLock" product="default" msgid="569409726861695115">"ტელეფონის ძილის რეჟიმში გადასვლის აღკვეთა"</string>
+ <string name="permdesc_wakeLock" product="automotive" msgid="5995045369683254571">"ნებას რთავს აპს, ჩართული ჰქონდეს მანქანის ეკრანი."</string>
<string name="permdesc_wakeLock" product="tablet" msgid="2441742939101526277">"აპს შეეძლება ხელი შეუშალოს ტაბლეტის დაძინებას."</string>
<string name="permdesc_wakeLock" product="tv" msgid="2329298966735118796">"ნებას რთავს აპს, ხელი შეუშალოს Android TV მოწყობილობას დაძინებაში."</string>
<string name="permdesc_wakeLock" product="default" msgid="3689523792074007163">"აპს შეეძლება ხელი შეუშალოს ტელეფონის დაძინებას."</string>
@@ -1631,6 +1631,12 @@
<string name="safe_media_volume_warning" product="default" msgid="3751676824423049994">"გსურთ ხმის რეკომენდებულ დონეზე მაღლა აწევა?\n\nხანგრძლივად ხმამაღლა მოსმენით შესაძლოა სმენადობა დაიზიანოთ."</string>
<string name="accessibility_shortcut_warning_dialog_title" msgid="4017995837692622933">"გსურთ მარტივი წვდომის მალსახმობის გამოყენება?"</string>
<string name="accessibility_shortcut_toogle_warning" msgid="4161716521310929544">"თუ მალსახმობი ჩართულია, ხმის ორივე ღილაკზე 3 წამის განმავლობაში დაჭერით მარტივი წვდომის ფუნქცია ჩაირთვება."</string>
+ <!-- no translation found for accessibility_select_shortcut_menu_title (7310194076629867377) -->
+ <skip />
+ <!-- no translation found for accessibility_edit_shortcut_menu_button_title (6096484087245145325) -->
+ <skip />
+ <!-- no translation found for accessibility_edit_shortcut_menu_volume_title (4849108668454490699) -->
+ <skip />
<string name="edit_accessibility_shortcut_menu_button" msgid="8885752738733772935">"მალსახმობების რედაქტირება"</string>
<string name="cancel_accessibility_shortcut_menu_button" msgid="1817413122335452474">"გაუქმება"</string>
<string name="disable_accessibility_shortcut" msgid="5806091378745232383">"მალსახმობის გამორთვა"</string>
@@ -1853,8 +1859,7 @@
<string name="default_notification_channel_label" msgid="3697928973567217330">"კატეგორიის გარეშე"</string>
<string name="importance_from_user" msgid="2782756722448800447">"ამ შეტყობინებების მნიშვნელობის დონე განისაზღვრა თქვენ მიერ."</string>
<string name="importance_from_person" msgid="4235804979664465383">"მნიშვნელოვანია ჩართული მომხმარებლების გამო."</string>
- <!-- no translation found for notification_history_title_placeholder (7748630986182249599) -->
- <skip />
+ <string name="notification_history_title_placeholder" msgid="7748630986182249599">"აპის მორგებული შეტყობინება"</string>
<string name="user_creation_account_exists" msgid="2239146360099708035">"მიეცეს უფლება <xliff:g id="APP">%1$s</xliff:g>-ს <xliff:g id="ACCOUNT">%2$s</xliff:g>-ის მეშვეობით ახალი მომხმარებელი შექმნას (ამ ანგარიშის მქონე მომხმარებელი უკვე არსებობს)?"</string>
<string name="user_creation_adding" msgid="7305185499667958364">"მიეცეს უფლება <xliff:g id="APP">%1$s</xliff:g>-ს <xliff:g id="ACCOUNT">%2$s</xliff:g>-ის მეშვეობით ახალი მომხმარებელი შექმნას?"</string>
<string name="language_selection_title" msgid="52674936078683285">"ენის დამატება"</string>
@@ -2028,14 +2033,29 @@
<string name="as_app_forced_to_restricted_bucket" msgid="8233871289353898964">"<xliff:g id="PACKAGE_NAME">%1$s</xliff:g> მოთავსდა კალათაში „შეზღუდული“"</string>
<string name="resolver_personal_tab" msgid="2051260504014442073">"პირადი"</string>
<string name="resolver_work_tab" msgid="2690019516263167035">"სამსახური"</string>
+ <!-- no translation found for resolver_personal_tab_accessibility (5739524949153091224) -->
+ <skip />
+ <!-- no translation found for resolver_work_tab_accessibility (4753168230363802734) -->
+ <skip />
<string name="resolver_cant_share_with_work_apps" msgid="7539495559434146897">"სამსახურის აპებით გაზიარება შეუძლებელია"</string>
<string name="resolver_cant_share_with_personal_apps" msgid="8020581735267157241">"პირადი აპებით გაზიარება შეუძლებელია"</string>
- <string name="resolver_cant_share_cross_profile_explanation" msgid="3536237105241882679">"თქვენმა IT ადმინისტრატორმა დაბლოკა გაზიარება პირად და სამსახურის აპებს შორის"</string>
- <string name="resolver_turn_on_work_apps" msgid="8987359079870455469">"სამსახურის აპების ჩართვა"</string>
- <string name="resolver_turn_on_work_apps_explanation" msgid="6322467455509618928">"სამსახურის აპებსა და კონტაქტებზე წვდომისთვის ჩართეთ სამსახურის აპები"</string>
+ <!-- no translation found for resolver_cant_share_cross_profile_explanation (5556640604460901386) -->
+ <skip />
+ <!-- no translation found for resolver_cant_access_work_apps (375634344111233790) -->
+ <skip />
+ <!-- no translation found for resolver_cant_access_work_apps_explanation (3958762224516867388) -->
+ <skip />
+ <!-- no translation found for resolver_cant_access_personal_apps (1953215925406474177) -->
+ <skip />
+ <!-- no translation found for resolver_cant_access_personal_apps_explanation (1725572276741281136) -->
+ <skip />
+ <!-- no translation found for resolver_turn_on_work_apps_share (619263911204978175) -->
+ <skip />
+ <!-- no translation found for resolver_turn_on_work_apps_view (3073389230905543680) -->
+ <skip />
<string name="resolver_no_apps_available" msgid="7710339903040989654">"ხელმისაწვდომი აპები არ არის"</string>
- <string name="resolver_no_apps_available_explanation" msgid="4662694431121196560">"აპები ვერ მოიძებნა"</string>
- <string name="resolver_switch_on_work" msgid="8294542702883688533">"სამსახურზე გადართვა"</string>
+ <!-- no translation found for resolver_switch_on_work (2873009160846966379) -->
+ <skip />
<string name="permlab_accessCallAudio" msgid="1682957511874097664">"სატელეფონო ზარებში აუდიოს ჩაწერა ან დაკვრა"</string>
<string name="permdesc_accessCallAudio" msgid="8448360894684277823">"ნაგულისხმევ დასარეკ აპლიკაციად არჩევის შემთხვევაში, ნებას რთავს აპს ჩაიწეროს ან დაუკრას აუდიო სატელეფონო ზარებში."</string>
</resources>
diff --git a/core/res/res/values-kk/strings.xml b/core/res/res/values-kk/strings.xml
index 2e10b16958e5..f3108d205ef7 100644
--- a/core/res/res/values-kk/strings.xml
+++ b/core/res/res/values-kk/strings.xml
@@ -249,10 +249,8 @@
<item quantity="other"><xliff:g id="NUMBER_1">%d</xliff:g> секундтан кейін қате туралы есептің скриншоты түсіріледі.</item>
<item quantity="one"><xliff:g id="NUMBER_0">%d</xliff:g> секундтан кейін қате туралы есептің скриншоты түсіріледі.</item>
</plurals>
- <!-- no translation found for bugreport_screenshot_success_toast (7986095104151473745) -->
- <skip />
- <!-- no translation found for bugreport_screenshot_failure_toast (6736320861311294294) -->
- <skip />
+ <string name="bugreport_screenshot_success_toast" msgid="7986095104151473745">"Қате туралы есеп түсірілген скриншот"</string>
+ <string name="bugreport_screenshot_failure_toast" msgid="6736320861311294294">"Қате туралы есеп скриншоты түсірілмеді."</string>
<string name="global_action_toggle_silent_mode" msgid="8464352592860372188">"Үнсіз режимі"</string>
<string name="global_action_silent_mode_on_status" msgid="2371892537738632013">"Дыбыс ӨШІРУЛІ"</string>
<string name="global_action_silent_mode_off_status" msgid="6608006545950920042">"Дыбыс ҚОСУЛЫ"</string>
@@ -454,9 +452,11 @@
<string name="permdesc_acceptHandovers" msgid="7129026180128626870">"Қолданбаға басқа қолданбадағы қоңырауды жалғастыруға рұқсат береді."</string>
<string name="permlab_readPhoneNumbers" msgid="5668704794723365628">"телефон нөмірлерін оқу"</string>
<string name="permdesc_readPhoneNumbers" msgid="7368652482818338871">"Қолданбаға құрылғының телефон нөмірлерін алуға мүмкіндік береді."</string>
+ <string name="permlab_wakeLock" product="automotive" msgid="1904736682319375676">"көлік экранын қосулы күйде ұстау"</string>
<string name="permlab_wakeLock" product="tablet" msgid="1527660973931694000">"планшетті ұйқыдан бөгеу"</string>
<string name="permlab_wakeLock" product="tv" msgid="2856941418123343518">"Android TV құрылғыңызды ұйқы режиміне өткізбеу"</string>
<string name="permlab_wakeLock" product="default" msgid="569409726861695115">"телефонды ұйқыдан бөгеу"</string>
+ <string name="permdesc_wakeLock" product="automotive" msgid="5995045369683254571">"Қолданбаға көлік экранын қосулы күйде ұстауға мүмкіндік береді."</string>
<string name="permdesc_wakeLock" product="tablet" msgid="2441742939101526277">"Қолданбаға планшеттің ұйқыға кетуін болдырмауға рұқсат береді."</string>
<string name="permdesc_wakeLock" product="tv" msgid="2329298966735118796">"Қолданба Android TV құрылғысын \"Ұйқы\" режиміне өткізбейтін болады."</string>
<string name="permdesc_wakeLock" product="default" msgid="3689523792074007163">"Қолданбаға телефонның ұйқыға кетуін болдырмауға рұқсат береді."</string>
@@ -1631,6 +1631,12 @@
<string name="safe_media_volume_warning" product="default" msgid="3751676824423049994">"Дыбыс деңгейін ұсынылған деңгейден көтеру керек пе?\n\nЖоғары дыбыс деңгейінде ұзақ кезеңдер бойы тыңдау есту қабілетіңізге зиян тигізуі мүмкін."</string>
<string name="accessibility_shortcut_warning_dialog_title" msgid="4017995837692622933">"Арнайы мүмкіндік төте жолын пайдалану керек пе?"</string>
<string name="accessibility_shortcut_toogle_warning" msgid="4161716521310929544">"Түймелер тіркесімі қосулы кезде, екі дыбыс түймесін 3 секунд басып тұрсаңыз, \"Арнайы мүмкіндіктер\" функциясы іске қосылады."</string>
+ <!-- no translation found for accessibility_select_shortcut_menu_title (7310194076629867377) -->
+ <skip />
+ <!-- no translation found for accessibility_edit_shortcut_menu_button_title (6096484087245145325) -->
+ <skip />
+ <!-- no translation found for accessibility_edit_shortcut_menu_volume_title (4849108668454490699) -->
+ <skip />
<string name="edit_accessibility_shortcut_menu_button" msgid="8885752738733772935">"Таңбашаларды өзгерту"</string>
<string name="cancel_accessibility_shortcut_menu_button" msgid="1817413122335452474">"Бас тарту"</string>
<string name="disable_accessibility_shortcut" msgid="5806091378745232383">"Төте жолды өшіру"</string>
@@ -1853,8 +1859,7 @@
<string name="default_notification_channel_label" msgid="3697928973567217330">"Санатқа жатқызылмаған"</string>
<string name="importance_from_user" msgid="2782756722448800447">"Сіз осы хабарландырулардың маңыздылығын орнатасыз."</string>
<string name="importance_from_person" msgid="4235804979664465383">"Қатысты адамдарға байланысты бұл маңызды."</string>
- <!-- no translation found for notification_history_title_placeholder (7748630986182249599) -->
- <skip />
+ <string name="notification_history_title_placeholder" msgid="7748630986182249599">"Арнаулы хабар хабарландыруы"</string>
<string name="user_creation_account_exists" msgid="2239146360099708035">"<xliff:g id="APP">%1$s</xliff:g> қолданбасына <xliff:g id="ACCOUNT">%2$s</xliff:g> есептік жазбасы бар жаңа пайдаланушы (мұндай есептік жазбаға ие пайдаланушы бұрыннан бар) жасауға рұқсат етілсін бе?"</string>
<string name="user_creation_adding" msgid="7305185499667958364">"<xliff:g id="APP">%1$s</xliff:g> қолданбасына <xliff:g id="ACCOUNT">%2$s</xliff:g> есептік жазбасы бар жаңа пайдаланушы жасауға рұқсат етілсін бе?"</string>
<string name="language_selection_title" msgid="52674936078683285">"Тілді қосу"</string>
@@ -2028,14 +2033,29 @@
<string name="as_app_forced_to_restricted_bucket" msgid="8233871289353898964">"<xliff:g id="PACKAGE_NAME">%1$s</xliff:g> ШЕКТЕЛГЕН себетке салынды."</string>
<string name="resolver_personal_tab" msgid="2051260504014442073">"Жеке"</string>
<string name="resolver_work_tab" msgid="2690019516263167035">"Жұмыс"</string>
+ <!-- no translation found for resolver_personal_tab_accessibility (5739524949153091224) -->
+ <skip />
+ <!-- no translation found for resolver_work_tab_accessibility (4753168230363802734) -->
+ <skip />
<string name="resolver_cant_share_with_work_apps" msgid="7539495559434146897">"Жұмыс қолданбаларымен бөлісілмейді"</string>
<string name="resolver_cant_share_with_personal_apps" msgid="8020581735267157241">"Жеке қолданбалармен бөлісілмейді"</string>
- <string name="resolver_cant_share_cross_profile_explanation" msgid="3536237105241882679">"АТ әкімшісі жеке және жұмыс қолданбалары арасында деректер бөлісуді бөгеді."</string>
- <string name="resolver_turn_on_work_apps" msgid="8987359079870455469">"Жұмыс қолданбаларын іске қосу"</string>
- <string name="resolver_turn_on_work_apps_explanation" msgid="6322467455509618928">"Жұмыс қолданбаларын және контактілерді пайдалану үшін, оларды іске қосыңыз."</string>
+ <!-- no translation found for resolver_cant_share_cross_profile_explanation (5556640604460901386) -->
+ <skip />
+ <!-- no translation found for resolver_cant_access_work_apps (375634344111233790) -->
+ <skip />
+ <!-- no translation found for resolver_cant_access_work_apps_explanation (3958762224516867388) -->
+ <skip />
+ <!-- no translation found for resolver_cant_access_personal_apps (1953215925406474177) -->
+ <skip />
+ <!-- no translation found for resolver_cant_access_personal_apps_explanation (1725572276741281136) -->
+ <skip />
+ <!-- no translation found for resolver_turn_on_work_apps_share (619263911204978175) -->
+ <skip />
+ <!-- no translation found for resolver_turn_on_work_apps_view (3073389230905543680) -->
+ <skip />
<string name="resolver_no_apps_available" msgid="7710339903040989654">"Қолданбалар жоқ"</string>
- <string name="resolver_no_apps_available_explanation" msgid="4662694431121196560">"Ешқандай қолданба табылмады."</string>
- <string name="resolver_switch_on_work" msgid="8294542702883688533">"Жұмыс профилін іске қосу"</string>
+ <!-- no translation found for resolver_switch_on_work (2873009160846966379) -->
+ <skip />
<string name="permlab_accessCallAudio" msgid="1682957511874097664">"Телефон қоңырауларында аудио жазу немесе ойнату"</string>
<string name="permdesc_accessCallAudio" msgid="8448360894684277823">"Қолданба әдепкі нөмір тергіш қолданба ретінде тағайындалған кезде, телефон қоңырауларында аудионы жазуға немесе ойнатуға мүмкіндік береді."</string>
</resources>
diff --git a/core/res/res/values-km/strings.xml b/core/res/res/values-km/strings.xml
index ce8983276023..180031a927b5 100644
--- a/core/res/res/values-km/strings.xml
+++ b/core/res/res/values-km/strings.xml
@@ -249,10 +249,8 @@
<item quantity="other">នឹងថតរូបអេក្រង់សម្រាប់របាយការណ៍កំហុសក្នុងរយៈពេល <xliff:g id="NUMBER_1">%d</xliff:g> វិនាទីទៀត។</item>
<item quantity="one">នឹងថតរូបអេក្រង់សម្រាប់របាយការណ៍កំហុសក្នុងរយៈពេល <xliff:g id="NUMBER_0">%d</xliff:g> វិនាទីទៀត។</item>
</plurals>
- <!-- no translation found for bugreport_screenshot_success_toast (7986095104151473745) -->
- <skip />
- <!-- no translation found for bugreport_screenshot_failure_toast (6736320861311294294) -->
- <skip />
+ <string name="bugreport_screenshot_success_toast" msgid="7986095104151473745">"បានថតរូបថត​អេក្រង់ដែលមាន​របាយការណ៍អំពីបញ្ហា"</string>
+ <string name="bugreport_screenshot_failure_toast" msgid="6736320861311294294">"មិនអាចថត​រូបថតអេក្រង់​ដែលមានរបាយការណ៍​អំពីបញ្ហាបានទេ"</string>
<string name="global_action_toggle_silent_mode" msgid="8464352592860372188">"របៀប​ស្ងាត់"</string>
<string name="global_action_silent_mode_on_status" msgid="2371892537738632013">"បិទ​សំឡេង"</string>
<string name="global_action_silent_mode_off_status" msgid="6608006545950920042">"បើក​សំឡេង"</string>
@@ -454,9 +452,11 @@
<string name="permdesc_acceptHandovers" msgid="7129026180128626870">"អនុញ្ញាត​ឱ្យ​កម្មវិធី​បន្ត​ការ​ហៅ​ទូរសព្ទ​ ដែល​បាន​ចាប់ផ្តើម​នៅក្នុង​កម្មវិធី​ផ្សេង​។"</string>
<string name="permlab_readPhoneNumbers" msgid="5668704794723365628">"អាន​លេខ​ទូរសព្ទ"</string>
<string name="permdesc_readPhoneNumbers" msgid="7368652482818338871">"អនុញ្ញាត​ឲ្យ​កម្មវិធីនេះ​ចូលប្រើប្រាស់​លេខទូរសព្ទ​របស់​ឧបករណ៍​នេះ។"</string>
+ <string name="permlab_wakeLock" product="automotive" msgid="1904736682319375676">"បន្តបើក​អេក្រង់​រថយន្ត"</string>
<string name="permlab_wakeLock" product="tablet" msgid="1527660973931694000">"ការពារ​​កុំព្យូទ័រ​បន្ទះ​មិន​ឲ្យ​ដេក"</string>
<string name="permlab_wakeLock" product="tv" msgid="2856941418123343518">"ទប់ស្កាត់មិនឱ្យ​ឧបករណ៍ Android TV របស់អ្នកដេក"</string>
<string name="permlab_wakeLock" product="default" msgid="569409726861695115">"ការ​ពារ​ទូរស័ព្ទ​មិន​ឲ្យ​ដេក"</string>
+ <string name="permdesc_wakeLock" product="automotive" msgid="5995045369683254571">"អនុញ្ញាតឱ្យ​កម្មវិធី​បន្តបើក​អេក្រង់​រថយន្ត។"</string>
<string name="permdesc_wakeLock" product="tablet" msgid="2441742939101526277">"ឲ្យ​​កម្មវិធី​ការពារ​កុំព្យូទ័រ​បន្ទះ​មិន​ឲ្យ​ដេក។"</string>
<string name="permdesc_wakeLock" product="tv" msgid="2329298966735118796">"អនុញ្ញាត​ឱ្យកម្មវិធី​ទប់ស្កាត់មិនឱ្យ​ឧបករណ៍ Android TV របស់អ្នកដេក។"</string>
<string name="permdesc_wakeLock" product="default" msgid="3689523792074007163">"ឲ្យ​កម្មវិធី​ការពារ​ទូរស័ព្ទ​មិន​ឲ្យ​ដេក។"</string>
@@ -1633,6 +1633,12 @@
<string name="safe_media_volume_warning" product="default" msgid="3751676824423049994">"បង្កើន​កម្រិត​សំឡេង​លើស​ពី​កម្រិត​បាន​ផ្ដល់​យោបល់?\n\nការ​ស្ដាប់​នៅ​កម្រិត​សំឡេង​ខ្លាំង​យូរ​អាច​ធ្វើឲ្យ​ខូច​ត្រចៀក។"</string>
<string name="accessibility_shortcut_warning_dialog_title" msgid="4017995837692622933">"ប្រើប្រាស់​ផ្លូវកាត់​ភាព​ងាយស្រួល?"</string>
<string name="accessibility_shortcut_toogle_warning" msgid="4161716521310929544">"នៅពេលបើក​ផ្លូវកាត់ ការចុច​ប៊ូតុង​កម្រិតសំឡេង​ទាំងពីរ​រយៈពេល 3 វិនាទី​នឹង​ចាប់ផ្តើម​មុខងារ​ភាពងាយប្រើ។"</string>
+ <!-- no translation found for accessibility_select_shortcut_menu_title (7310194076629867377) -->
+ <skip />
+ <!-- no translation found for accessibility_edit_shortcut_menu_button_title (6096484087245145325) -->
+ <skip />
+ <!-- no translation found for accessibility_edit_shortcut_menu_volume_title (4849108668454490699) -->
+ <skip />
<string name="edit_accessibility_shortcut_menu_button" msgid="8885752738733772935">"កែ​ផ្លូវកាត់"</string>
<string name="cancel_accessibility_shortcut_menu_button" msgid="1817413122335452474">"បោះបង់"</string>
<string name="disable_accessibility_shortcut" msgid="5806091378745232383">"បិទ​ផ្លូវកាត់"</string>
@@ -1855,8 +1861,7 @@
<string name="default_notification_channel_label" msgid="3697928973567217330">"មិន​​បែងចែក​ប្រភេទ"</string>
<string name="importance_from_user" msgid="2782756722448800447">"អ្នកបានកំណត់សារៈសំខាន់នៃការជូនដំណឹងទាំងនេះ"</string>
<string name="importance_from_person" msgid="4235804979664465383">"វាមានសារៈសំខាន់ដោយសារតែមនុស្សដែលពាក់ព័ន្ធ"</string>
- <!-- no translation found for notification_history_title_placeholder (7748630986182249599) -->
- <skip />
+ <string name="notification_history_title_placeholder" msgid="7748630986182249599">"ការជូន​ដំណឹងកម្មវិធី​ផ្ទាល់ខ្លួន"</string>
<string name="user_creation_account_exists" msgid="2239146360099708035">"អនុញ្ញាតឱ្យ <xliff:g id="APP">%1$s</xliff:g> បង្កើតអ្នកប្រើប្រាស់​ថ្មីដោយប្រើ <xliff:g id="ACCOUNT">%2$s</xliff:g> (អ្នកប្រើប្រាស់ដែលមានគណនីនេះមានរួចហើយ) ដែរឬទេ?"</string>
<string name="user_creation_adding" msgid="7305185499667958364">"អនុញ្ញាតឱ្យ <xliff:g id="APP">%1$s</xliff:g> បង្កើតអ្នកប្រើប្រាស់​ថ្មីដោយប្រើ <xliff:g id="ACCOUNT">%2$s</xliff:g> ដែរឬទេ?"</string>
<string name="language_selection_title" msgid="52674936078683285">"បន្ថែមភាសា"</string>
@@ -2030,14 +2035,29 @@
<string name="as_app_forced_to_restricted_bucket" msgid="8233871289353898964">"<xliff:g id="PACKAGE_NAME">%1$s</xliff:g> ត្រូវបានដាក់​ទៅក្នុងធុង​ដែលបានដាក់កំហិត"</string>
<string name="resolver_personal_tab" msgid="2051260504014442073">"ផ្ទាល់ខ្លួន"</string>
<string name="resolver_work_tab" msgid="2690019516263167035">"ការងារ"</string>
+ <!-- no translation found for resolver_personal_tab_accessibility (5739524949153091224) -->
+ <skip />
+ <!-- no translation found for resolver_work_tab_accessibility (4753168230363802734) -->
+ <skip />
<string name="resolver_cant_share_with_work_apps" msgid="7539495559434146897">"មិនអាច​ចែករំលែក​ជាមួយ​កម្មវិធី​ការងារ​បានទេ"</string>
<string name="resolver_cant_share_with_personal_apps" msgid="8020581735267157241">"មិនអាច​ចែករំលែក​ជាមួយ​កម្មវិធី​ផ្ទាល់ខ្លួន​បានទេ"</string>
- <string name="resolver_cant_share_cross_profile_explanation" msgid="3536237105241882679">"អ្នកគ្រប់គ្រង​ផ្នែកព័ត៌មានវិទ្យា​របស់អ្នក​បានទប់ស្កាត់​ការចែករំលែក​រវាង​កម្មវិធី​ការងារ និង​ផ្ទាល់ខ្លួន"</string>
- <string name="resolver_turn_on_work_apps" msgid="8987359079870455469">"បើក​កម្មវិធី​ការងារ"</string>
- <string name="resolver_turn_on_work_apps_explanation" msgid="6322467455509618928">"បើក​កម្មវិធី​ការងារ ដើម្បី​ចូល​ប្រើ​ទំនាក់ទំនង និងកម្មវិធី​ការងារ"</string>
+ <!-- no translation found for resolver_cant_share_cross_profile_explanation (5556640604460901386) -->
+ <skip />
+ <!-- no translation found for resolver_cant_access_work_apps (375634344111233790) -->
+ <skip />
+ <!-- no translation found for resolver_cant_access_work_apps_explanation (3958762224516867388) -->
+ <skip />
+ <!-- no translation found for resolver_cant_access_personal_apps (1953215925406474177) -->
+ <skip />
+ <!-- no translation found for resolver_cant_access_personal_apps_explanation (1725572276741281136) -->
+ <skip />
+ <!-- no translation found for resolver_turn_on_work_apps_share (619263911204978175) -->
+ <skip />
+ <!-- no translation found for resolver_turn_on_work_apps_view (3073389230905543680) -->
+ <skip />
<string name="resolver_no_apps_available" msgid="7710339903040989654">"មិនមាន​កម្មវិធី​ដែល​អាចប្រើ​បានទេ"</string>
- <string name="resolver_no_apps_available_explanation" msgid="4662694431121196560">"យើង​រកមិនឃើញ​កម្មវិធី​ណាមួយទេ"</string>
- <string name="resolver_switch_on_work" msgid="8294542702883688533">"បើក​កម្រងព័ត៌មាន​ការងារ"</string>
+ <!-- no translation found for resolver_switch_on_work (2873009160846966379) -->
+ <skip />
<string name="permlab_accessCallAudio" msgid="1682957511874097664">"ថត ឬចាក់សំឡេង​នៅក្នុង​ការហៅទូរសព្ទ"</string>
<string name="permdesc_accessCallAudio" msgid="8448360894684277823">"នៅពេលកំណត់​ជាកម្មវិធីផ្ទាំងចុច​ហៅទូរសព្ទលំនាំដើម សូមអនុញ្ញាត​ឱ្យកម្មវិធីនេះថត ឬចាក់សំឡេង​នៅក្នុង​ការហៅទូរសព្ទ។"</string>
</resources>
diff --git a/core/res/res/values-kn/strings.xml b/core/res/res/values-kn/strings.xml
index 93721a5c7a36..8072123c8c78 100644
--- a/core/res/res/values-kn/strings.xml
+++ b/core/res/res/values-kn/strings.xml
@@ -249,10 +249,8 @@
<item quantity="one">ಬಗ್ ವರದಿ ಮಾಡಲು <xliff:g id="NUMBER_1">%d</xliff:g> ಸೆಕೆಂಡುಗಳಲ್ಲಿ ಸ್ಕ್ರೀನ್‌ಶಾಟ್ ತೆಗೆದುಕೊಳ್ಳಲಾಗುತ್ತಿದೆ.</item>
<item quantity="other">ಬಗ್ ವರದಿ ಮಾಡಲು <xliff:g id="NUMBER_1">%d</xliff:g> ಸೆಕೆಂಡುಗಳಲ್ಲಿ ಸ್ಕ್ರೀನ್‌ಶಾಟ್ ತೆಗೆದುಕೊಳ್ಳಲಾಗುತ್ತಿದೆ.</item>
</plurals>
- <!-- no translation found for bugreport_screenshot_success_toast (7986095104151473745) -->
- <skip />
- <!-- no translation found for bugreport_screenshot_failure_toast (6736320861311294294) -->
- <skip />
+ <string name="bugreport_screenshot_success_toast" msgid="7986095104151473745">"ಬಗ್ ವರದಿಯ ಜೊತೆಗೆ ಸ್ಕ್ರೀನ್‌ಶಾಟ್ ತೆಗೆದುಕೊಳ್ಳಲಾಗಿದೆ"</string>
+ <string name="bugreport_screenshot_failure_toast" msgid="6736320861311294294">"ಬಗ್ ವರದಿಯ ಜೊತೆಗೆ ಸ್ಕ್ರೀನ್‌ಶಾಟ್ ತೆಗೆದುಕೊಳ್ಳಲು ವಿಫಲವಾಗಿದೆ"</string>
<string name="global_action_toggle_silent_mode" msgid="8464352592860372188">"ಶಾಂತ ಮೋಡ್"</string>
<string name="global_action_silent_mode_on_status" msgid="2371892537738632013">"ಶಬ್ಧ ಆಫ್ ಆಗಿದೆ"</string>
<string name="global_action_silent_mode_off_status" msgid="6608006545950920042">"ಶಬ್ಧ ಆನ್ ಆಗಿದೆ"</string>
@@ -454,9 +452,11 @@
<string name="permdesc_acceptHandovers" msgid="7129026180128626870">"ಮತ್ತೊಂದು ಅಪ್ಲಿಕೇಶನ್‌ನಲ್ಲಿ ಪ್ರಾರಂಭವಾದ ಕರೆಯನ್ನು ಮುಂದುವರಿಸಲು ಅಪ್ಲಿಕೇಶನ್‌ಗೆ ಅವಕಾಶ ಮಾಡಿಕೊಡಿ."</string>
<string name="permlab_readPhoneNumbers" msgid="5668704794723365628">"ಫೋನ್‌ ಸಂಖ್ಯೆಗಳನ್ನು ಓದಿ"</string>
<string name="permdesc_readPhoneNumbers" msgid="7368652482818338871">"ಸಾಧನದ ಫೋನ್ ಸಂಖ್ಯೆಗಳಿಗೆ ಪ್ರವೇಶ ಪಡೆಯಲು ಅಪ್ಲಿಕೇಶನ್‌ಗೆ ಅನುಮತಿ ನೀಡುತ್ತದೆ."</string>
+ <string name="permlab_wakeLock" product="automotive" msgid="1904736682319375676">"ಕಾರ್ ಸ್ಕ್ರೀನ್ ಅನ್ನು ಆನ್‌ನಲ್ಲೇ ಇರಿಸಿ"</string>
<string name="permlab_wakeLock" product="tablet" msgid="1527660973931694000">"ಟ್ಯಾಬ್ಲೆಟ್ ನಿದ್ರಾವಸ್ಥೆಯನ್ನು ತಡೆಯಿರಿ"</string>
<string name="permlab_wakeLock" product="tv" msgid="2856941418123343518">"ನಿಮ್ಮ Android TV ಸಾಧನವು ನಿದ್ರಾವಸ್ಥೆಗೆ ಹೋಗುವುದನ್ನು ತಡೆಯಿರಿ"</string>
<string name="permlab_wakeLock" product="default" msgid="569409726861695115">"ಫೋನ್ ಆಫ್ ಆಗುವುದರಿಂದ ತಡೆಯಿರಿ"</string>
+ <string name="permdesc_wakeLock" product="automotive" msgid="5995045369683254571">"ಕಾರ್ ಸ್ಕ್ರೀನ್ ಅನ್ನು ಆನ್‌ನಲ್ಲೇ ಇರಿಸಲು ಆ್ಯಪ್‌ಗೆ ಅನುಮತಿಸುತ್ತದೆ."</string>
<string name="permdesc_wakeLock" product="tablet" msgid="2441742939101526277">"ಟ್ಯಾಬ್ಲೆಟ್‌ ನಿದ್ರೆಗೆ ಹೋಗುವುದನ್ನು ತಡೆಯಲು ಅಪ್ಲಿಕೇಶನ್‌ಗೆ ಅನುಮತಿಸುತ್ತದೆ."</string>
<string name="permdesc_wakeLock" product="tv" msgid="2329298966735118796">"ನಿಮ್ಮ Android TV ಸಾಧನವು ನಿದ್ರಾವಸ್ಥೆಗೆ ಹೋಗುವುದನ್ನು ತಡೆಯಲು ಅಪ್ಲಿಕೇಶನ್‌ಗೆ ಅನುಮತಿಸುತ್ತದೆ."</string>
<string name="permdesc_wakeLock" product="default" msgid="3689523792074007163">"ಫೋನ್‌ ನಿದ್ರೆಗೆ ಹೋಗುವುದನ್ನು ತಡೆಯಲು ಅಪ್ಲಿಕೇಶನ್‌ಗೆ ಅನುಮತಿಸುತ್ತದೆ."</string>
@@ -1631,6 +1631,12 @@
<string name="safe_media_volume_warning" product="default" msgid="3751676824423049994">"ವಾಲ್ಯೂಮ್‌ ಅನ್ನು ಶಿಫಾರಸು ಮಾಡಲಾದ ಮಟ್ಟಕ್ಕಿಂತಲೂ ಹೆಚ್ಚು ಮಾಡುವುದೇ?\n\nದೀರ್ಘ ಅವಧಿಯವರೆಗೆ ಹೆಚ್ಚಿನ ವಾಲ್ಯೂಮ್‌ನಲ್ಲಿ ಆಲಿಸುವುದರಿಂದ ನಿಮ್ಮ ಆಲಿಸುವಿಕೆ ಸಾಮರ್ಥ್ಯಕ್ಕೆ ಹಾನಿಯುಂಟು ಮಾಡಬಹುದು."</string>
<string name="accessibility_shortcut_warning_dialog_title" msgid="4017995837692622933">"ಪ್ರವೇಶಿಸುವಿಕೆ ಶಾರ್ಟ್‌ಕಟ್ ಬಳಸುವುದೇ?"</string>
<string name="accessibility_shortcut_toogle_warning" msgid="4161716521310929544">"ಶಾರ್ಟ್‌ಕಟ್ ಆನ್ ಆಗಿರುವಾಗ, ಎರಡೂ ವಾಲ್ಯೂಮ್ ಬಟನ್‌ಗಳನ್ನು 3 ಸೆಕೆಂಡುಗಳ ಕಾಲ ಒತ್ತಿದರೆ ಪ್ರವೇಶಿಸುವಿಕೆ ವೈಶಿಷ್ಟ್ಯವೊಂದು ಪ್ರಾರಂಭವಾಗುತ್ತದೆ."</string>
+ <!-- no translation found for accessibility_select_shortcut_menu_title (7310194076629867377) -->
+ <skip />
+ <!-- no translation found for accessibility_edit_shortcut_menu_button_title (6096484087245145325) -->
+ <skip />
+ <!-- no translation found for accessibility_edit_shortcut_menu_volume_title (4849108668454490699) -->
+ <skip />
<string name="edit_accessibility_shortcut_menu_button" msgid="8885752738733772935">"ಶಾರ್ಟ್‌ಕಟ್‌‍ಗಳನ್ನು ಎಡಿಟ್ ಮಾಡಿ"</string>
<string name="cancel_accessibility_shortcut_menu_button" msgid="1817413122335452474">"ರದ್ದುಗೊಳಿಸಿ"</string>
<string name="disable_accessibility_shortcut" msgid="5806091378745232383">"ಶಾರ್ಟ್‌ಕಟ್‌ ಆಫ್ ಮಾಡಿ"</string>
@@ -2028,14 +2034,29 @@
<string name="as_app_forced_to_restricted_bucket" msgid="8233871289353898964">"<xliff:g id="PACKAGE_NAME">%1$s</xliff:g> ಅನ್ನು ನಿರ್ಬಂಧಿತ ಬಕೆಟ್‌ಗೆ ಹಾಕಲಾಗಿದೆ"</string>
<string name="resolver_personal_tab" msgid="2051260504014442073">"ವೈಯಕ್ತಿಕ"</string>
<string name="resolver_work_tab" msgid="2690019516263167035">"ಕೆಲಸ"</string>
+ <!-- no translation found for resolver_personal_tab_accessibility (5739524949153091224) -->
+ <skip />
+ <!-- no translation found for resolver_work_tab_accessibility (4753168230363802734) -->
+ <skip />
<string name="resolver_cant_share_with_work_apps" msgid="7539495559434146897">"ಕೆಲಸದ ಆ್ಯಪ್‌ಗಳೊಂದಿಗೆ ಹಂಚಿಕೊಳ್ಳಲು ಸಾಧ್ಯವಿಲ್ಲ"</string>
<string name="resolver_cant_share_with_personal_apps" msgid="8020581735267157241">"ವೈಯಕ್ತಿಕ ಆ್ಯಪ್‌ಗಳೊಂದಿಗೆ ಹಂಚಿಕೊಳ್ಳಲು ಸಾಧ್ಯವಿಲ್ಲ"</string>
- <string name="resolver_cant_share_cross_profile_explanation" msgid="3536237105241882679">"ನಿಮ್ಮ ಐಟಿ ನಿರ್ವಾಹಕರು, ವೈಯಕ್ತಿಕ ಮತ್ತು ಕೆಲಸಕ್ಕೆ ಸಂಬಂಧಿಸಿದ ಆ್ಯಪ್‌ಗಳ ನಡುವೆ ಹಂಚಿಕೊಳ್ಳುವುದನ್ನು ನಿರ್ಬಂಧಿಸಿದ್ದಾರೆ"</string>
- <string name="resolver_turn_on_work_apps" msgid="8987359079870455469">"ಕೆಲಸಕ್ಕೆ ಸಂಬಂಧಿಸಿದ ಆ್ಯಪ್‌ಗಳನ್ನು ಆನ್ ಮಾಡಿ"</string>
- <string name="resolver_turn_on_work_apps_explanation" msgid="6322467455509618928">"ಕೆಲಸಕ್ಕೆ ಸಂಬಂಧಿಸಿದ ಆ್ಯಪ್‌ಗಳು ಮತ್ತು ಸಂಪರ್ಕಗಳನ್ನು ಪ್ರವೇಶಿಸಲು, ಕೆಲಸಕ್ಕೆ ಸಂಬಂಧಿಸಿದ ಆ್ಯಪ್‌ಗಳನ್ನು ಆನ್ ಮಾಡಿ"</string>
+ <!-- no translation found for resolver_cant_share_cross_profile_explanation (5556640604460901386) -->
+ <skip />
+ <!-- no translation found for resolver_cant_access_work_apps (375634344111233790) -->
+ <skip />
+ <!-- no translation found for resolver_cant_access_work_apps_explanation (3958762224516867388) -->
+ <skip />
+ <!-- no translation found for resolver_cant_access_personal_apps (1953215925406474177) -->
+ <skip />
+ <!-- no translation found for resolver_cant_access_personal_apps_explanation (1725572276741281136) -->
+ <skip />
+ <!-- no translation found for resolver_turn_on_work_apps_share (619263911204978175) -->
+ <skip />
+ <!-- no translation found for resolver_turn_on_work_apps_view (3073389230905543680) -->
+ <skip />
<string name="resolver_no_apps_available" msgid="7710339903040989654">"ಯಾವುದೇ ಆ್ಯಪ್‌ಗಳು ಲಭ್ಯವಿಲ್ಲ"</string>
- <string name="resolver_no_apps_available_explanation" msgid="4662694431121196560">"ನಮಗೆ ಯಾವುದೇ ಆ್ಯಪ್‌ಗಳನ್ನು ಹುಡುಕಲು ಸಾಧ್ಯವಾಗಲಿಲ್ಲ"</string>
- <string name="resolver_switch_on_work" msgid="8294542702883688533">"ಉದ್ಯೋಗ ಪ್ರೊಫೈಲ್‌ ಅನ್ನು ಆನ್ ಮಾಡಿ"</string>
+ <!-- no translation found for resolver_switch_on_work (2873009160846966379) -->
+ <skip />
<string name="permlab_accessCallAudio" msgid="1682957511874097664">"ಫೋನ್ ಕರೆಗಳಲ್ಲಿ ಆಡಿಯೊವನ್ನು ರೆಕಾರ್ಡ್ ಮಾಡಿ ಅಥವಾ ಪ್ಲೇ ಮಾಡಿ"</string>
<string name="permdesc_accessCallAudio" msgid="8448360894684277823">"ಡೀಫಾಲ್ಟ್ ಡಯಲರ್ ಅಪ್ಲಿಕೇಶನ್ ರೀತಿ ಬಳಸಿದಾಗ ಫೋನ್ ಕರೆಗಳಲ್ಲಿ ಆಡಿಯೊವನ್ನು ರೆಕಾರ್ಡ್ ಮಾಡಲು ಅಥವಾ ಪ್ಲೇ ಮಾಡಲು ಈ ಆ್ಯಪ್ ಅನ್ನು ಅನುಮತಿಸಿ."</string>
</resources>
diff --git a/core/res/res/values-ko/strings.xml b/core/res/res/values-ko/strings.xml
index 7ec0e77ee804..f7c24da8d3ae 100644
--- a/core/res/res/values-ko/strings.xml
+++ b/core/res/res/values-ko/strings.xml
@@ -249,10 +249,8 @@
<item quantity="other">버그 신고 스크린샷을 <xliff:g id="NUMBER_1">%d</xliff:g>초 후에 찍습니다.</item>
<item quantity="one">버그 신고 스크린샷을 <xliff:g id="NUMBER_0">%d</xliff:g>초 후에 찍습니다.</item>
</plurals>
- <!-- no translation found for bugreport_screenshot_success_toast (7986095104151473745) -->
- <skip />
- <!-- no translation found for bugreport_screenshot_failure_toast (6736320861311294294) -->
- <skip />
+ <string name="bugreport_screenshot_success_toast" msgid="7986095104151473745">"버그 신고용 스크린샷 촬영 완료"</string>
+ <string name="bugreport_screenshot_failure_toast" msgid="6736320861311294294">"버그 신고용 스크린샷 촬영 실패"</string>
<string name="global_action_toggle_silent_mode" msgid="8464352592860372188">"무음 모드"</string>
<string name="global_action_silent_mode_on_status" msgid="2371892537738632013">"소리 꺼짐"</string>
<string name="global_action_silent_mode_off_status" msgid="6608006545950920042">"소리 켜짐"</string>
@@ -454,9 +452,11 @@
<string name="permdesc_acceptHandovers" msgid="7129026180128626870">"다른 앱에서 수신한 전화를 계속하려면 앱을 허용합니다."</string>
<string name="permlab_readPhoneNumbers" msgid="5668704794723365628">"전화번호 읽기"</string>
<string name="permdesc_readPhoneNumbers" msgid="7368652482818338871">"앱에서 기기의 전화번호에 액세스하도록 허용합니다."</string>
+ <string name="permlab_wakeLock" product="automotive" msgid="1904736682319375676">"차량 화면 켜진 상태로 유지"</string>
<string name="permlab_wakeLock" product="tablet" msgid="1527660973931694000">"태블릿이 절전 모드로 전환되지 않도록 설정"</string>
<string name="permlab_wakeLock" product="tv" msgid="2856941418123343518">"Android TV 기기 절전 모드 해제"</string>
<string name="permlab_wakeLock" product="default" msgid="569409726861695115">"휴대전화가 절전 모드로 전환되지 않도록 설정"</string>
+ <string name="permdesc_wakeLock" product="automotive" msgid="5995045369683254571">"앱에서 차량 화면을 켜진 상태로 유지하도록 허용합니다."</string>
<string name="permdesc_wakeLock" product="tablet" msgid="2441742939101526277">"앱이 태블릿의 절전 모드 전환을 막도록 허용합니다."</string>
<string name="permdesc_wakeLock" product="tv" msgid="2329298966735118796">"앱이 Android TV 기기가 절전 모드로 전환되지 않게 막도록 허용합니다."</string>
<string name="permdesc_wakeLock" product="default" msgid="3689523792074007163">"앱이 휴대전화의 절전 모드 전환을 막도록 허용합니다."</string>
@@ -1631,6 +1631,12 @@
<string name="safe_media_volume_warning" product="default" msgid="3751676824423049994">"권장 수준 이상으로 볼륨을 높이시겠습니까?\n\n높은 볼륨으로 장시간 청취하면 청력에 손상이 올 수 있습니다."</string>
<string name="accessibility_shortcut_warning_dialog_title" msgid="4017995837692622933">"접근성 단축키를 사용하시겠습니까?"</string>
<string name="accessibility_shortcut_toogle_warning" msgid="4161716521310929544">"단축키가 사용 설정된 경우 볼륨 버튼 두 개를 동시에 3초간 누르면 접근성 기능이 시작됩니다."</string>
+ <!-- no translation found for accessibility_select_shortcut_menu_title (7310194076629867377) -->
+ <skip />
+ <!-- no translation found for accessibility_edit_shortcut_menu_button_title (6096484087245145325) -->
+ <skip />
+ <!-- no translation found for accessibility_edit_shortcut_menu_volume_title (4849108668454490699) -->
+ <skip />
<string name="edit_accessibility_shortcut_menu_button" msgid="8885752738733772935">"단축키 수정"</string>
<string name="cancel_accessibility_shortcut_menu_button" msgid="1817413122335452474">"취소"</string>
<string name="disable_accessibility_shortcut" msgid="5806091378745232383">"단축키 사용 중지"</string>
@@ -1853,8 +1859,7 @@
<string name="default_notification_channel_label" msgid="3697928973567217330">"지정된 카테고리 없음"</string>
<string name="importance_from_user" msgid="2782756722448800447">"이러한 알림의 중요도를 설정했습니다."</string>
<string name="importance_from_person" msgid="4235804979664465383">"관련된 사용자가 있으므로 중요합니다."</string>
- <!-- no translation found for notification_history_title_placeholder (7748630986182249599) -->
- <skip />
+ <string name="notification_history_title_placeholder" msgid="7748630986182249599">"맞춤 앱 알림"</string>
<string name="user_creation_account_exists" msgid="2239146360099708035">"<xliff:g id="APP">%1$s</xliff:g>에서 <xliff:g id="ACCOUNT">%2$s</xliff:g> 계정으로 신규 사용자를 만들도록 허용하시겠습니까? 이 계정으로 등록된 사용자가 이미 존재합니다."</string>
<string name="user_creation_adding" msgid="7305185499667958364">"<xliff:g id="APP">%1$s</xliff:g>에서 <xliff:g id="ACCOUNT">%2$s</xliff:g> 계정으로 신규 사용자를 만들도록 허용하시겠습니까?"</string>
<string name="language_selection_title" msgid="52674936078683285">"언어 추가"</string>
@@ -2028,14 +2033,29 @@
<string name="as_app_forced_to_restricted_bucket" msgid="8233871289353898964">"<xliff:g id="PACKAGE_NAME">%1$s</xliff:g> 항목이 RESTRICTED 버킷으로 이동함"</string>
<string name="resolver_personal_tab" msgid="2051260504014442073">"개인"</string>
<string name="resolver_work_tab" msgid="2690019516263167035">"직장"</string>
+ <!-- no translation found for resolver_personal_tab_accessibility (5739524949153091224) -->
+ <skip />
+ <!-- no translation found for resolver_work_tab_accessibility (4753168230363802734) -->
+ <skip />
<string name="resolver_cant_share_with_work_apps" msgid="7539495559434146897">"직장 앱과 공유할 수 없음"</string>
<string name="resolver_cant_share_with_personal_apps" msgid="8020581735267157241">"개인 앱과 공유할 수 없음"</string>
- <string name="resolver_cant_share_cross_profile_explanation" msgid="3536237105241882679">"IT 관리자가 개인 앱과 직장 앱 간의 공유를 차단함"</string>
- <string name="resolver_turn_on_work_apps" msgid="8987359079870455469">"직장 앱 사용 설정"</string>
- <string name="resolver_turn_on_work_apps_explanation" msgid="6322467455509618928">"직장 앱 및 연락처에 액세스하도록 직장 앱 사용 설정"</string>
+ <!-- no translation found for resolver_cant_share_cross_profile_explanation (5556640604460901386) -->
+ <skip />
+ <!-- no translation found for resolver_cant_access_work_apps (375634344111233790) -->
+ <skip />
+ <!-- no translation found for resolver_cant_access_work_apps_explanation (3958762224516867388) -->
+ <skip />
+ <!-- no translation found for resolver_cant_access_personal_apps (1953215925406474177) -->
+ <skip />
+ <!-- no translation found for resolver_cant_access_personal_apps_explanation (1725572276741281136) -->
+ <skip />
+ <!-- no translation found for resolver_turn_on_work_apps_share (619263911204978175) -->
+ <skip />
+ <!-- no translation found for resolver_turn_on_work_apps_view (3073389230905543680) -->
+ <skip />
<string name="resolver_no_apps_available" msgid="7710339903040989654">"사용 가능한 앱 없음"</string>
- <string name="resolver_no_apps_available_explanation" msgid="4662694431121196560">"앱을 찾을 수 없음"</string>
- <string name="resolver_switch_on_work" msgid="8294542702883688533">"직장 프로필 사용"</string>
+ <!-- no translation found for resolver_switch_on_work (2873009160846966379) -->
+ <skip />
<string name="permlab_accessCallAudio" msgid="1682957511874097664">"전화 통화 중에 오디오 녹음 또는 재생"</string>
<string name="permdesc_accessCallAudio" msgid="8448360894684277823">"이 앱이 기본 다이얼러 애플리케이션으로 지정되었을 때 전화 통화 중에 오디오를 녹음하거나 재생하도록 허용합니다."</string>
</resources>
diff --git a/core/res/res/values-ky/strings.xml b/core/res/res/values-ky/strings.xml
index 74e03c08f72e..b04863c9052b 100644
--- a/core/res/res/values-ky/strings.xml
+++ b/core/res/res/values-ky/strings.xml
@@ -249,10 +249,8 @@
<item quantity="other">Мүчүлүштүк тууралуу кабарлоо үчүн <xliff:g id="NUMBER_1">%d</xliff:g> секундда скриншот алынат.</item>
<item quantity="one">Мүчүлүштүк тууралуу кабарлоо үчүн <xliff:g id="NUMBER_0">%d</xliff:g> секундда скриншот алынат.</item>
</plurals>
- <!-- no translation found for bugreport_screenshot_success_toast (7986095104151473745) -->
- <skip />
- <!-- no translation found for bugreport_screenshot_failure_toast (6736320861311294294) -->
- <skip />
+ <string name="bugreport_screenshot_success_toast" msgid="7986095104151473745">"Мүчүлүштүк тууралуу кабар берүү үчүн скриншот тартылды"</string>
+ <string name="bugreport_screenshot_failure_toast" msgid="6736320861311294294">"Мүчүлүштүк тууралуу кабар берүү үчүн скриншот тартылган жок"</string>
<string name="global_action_toggle_silent_mode" msgid="8464352592860372188">"Үнсүз режим"</string>
<string name="global_action_silent_mode_on_status" msgid="2371892537738632013">"Добушу ӨЧҮК"</string>
<string name="global_action_silent_mode_off_status" msgid="6608006545950920042">"Добушу КҮЙҮК"</string>
@@ -454,9 +452,11 @@
<string name="permdesc_acceptHandovers" msgid="7129026180128626870">"Башка колдонмодон аткарылган чалууну бул колдонмодо улантууга уруксат берүү."</string>
<string name="permlab_readPhoneNumbers" msgid="5668704794723365628">"телефон номерлерин окуу"</string>
<string name="permdesc_readPhoneNumbers" msgid="7368652482818338871">"Колдонмого түзмөктүн телефон номерлерин окуу мүмкүнчүлүгү берилет."</string>
+ <string name="permlab_wakeLock" product="automotive" msgid="1904736682319375676">"унаанын экранын күйгүзүлгөн бойдон калтыруу"</string>
<string name="permlab_wakeLock" product="tablet" msgid="1527660973931694000">"планшетти уктатпай сактоо"</string>
<string name="permlab_wakeLock" product="tv" msgid="2856941418123343518">"Android TV түзмөгүңүзгө уйку режимин күйгүзүүгө жол бербеңиз"</string>
<string name="permlab_wakeLock" product="default" msgid="569409726861695115">"телефонду уктатпай сактоо"</string>
+ <string name="permdesc_wakeLock" product="automotive" msgid="5995045369683254571">"Колдонмого унаанын экранын күйгүзүлгөн бойдон калтырууга уруксат берет."</string>
<string name="permdesc_wakeLock" product="tablet" msgid="2441742939101526277">"Колдонмо планшетти көшүү режимине өткөрбөйт."</string>
<string name="permdesc_wakeLock" product="tv" msgid="2329298966735118796">"Колдонмого Android TV түзмөгүңүзгө уйку режимин күйгүзүүгө жол бербөөгө уруксат берет."</string>
<string name="permdesc_wakeLock" product="default" msgid="3689523792074007163">"Колдонмо телефонду көшүү режимине өткөрбөйт."</string>
@@ -1631,6 +1631,12 @@
<string name="safe_media_volume_warning" product="default" msgid="3751676824423049994">"Сунушталган деңгээлден да катуулатып уккуңуз келеби?\n\nМузыканы узакка чейин катуу уксаңыз, угууңуз начарлап кетиши мүмкүн."</string>
<string name="accessibility_shortcut_warning_dialog_title" msgid="4017995837692622933">"Ыкчам иштетесизби?"</string>
<string name="accessibility_shortcut_toogle_warning" msgid="4161716521310929544">"Атайын мүмкүнчүлүктөр функциясын пайдалануу үчүн ал күйгүзүлгөндө, үндү катуулатып/акырындаткан эки баскычты тең 3 секунддай коё бербей басып туруңуз."</string>
+ <!-- no translation found for accessibility_select_shortcut_menu_title (7310194076629867377) -->
+ <skip />
+ <!-- no translation found for accessibility_edit_shortcut_menu_button_title (6096484087245145325) -->
+ <skip />
+ <!-- no translation found for accessibility_edit_shortcut_menu_volume_title (4849108668454490699) -->
+ <skip />
<string name="edit_accessibility_shortcut_menu_button" msgid="8885752738733772935">"Кыска жолдорду түзөтүү"</string>
<string name="cancel_accessibility_shortcut_menu_button" msgid="1817413122335452474">"Жокко чыгаруу"</string>
<string name="disable_accessibility_shortcut" msgid="5806091378745232383">"Кыска жолду өчүрүү"</string>
@@ -1853,8 +1859,7 @@
<string name="default_notification_channel_label" msgid="3697928973567217330">"Категорияларга бөлүнгөн эмес"</string>
<string name="importance_from_user" msgid="2782756722448800447">"Бул эскертмелердин маанилүүлүгүн белгиледиңиз."</string>
<string name="importance_from_person" msgid="4235804979664465383">"Булар сиз үчүн маанилүү адамдар."</string>
- <!-- no translation found for notification_history_title_placeholder (7748630986182249599) -->
- <skip />
+ <string name="notification_history_title_placeholder" msgid="7748630986182249599">"Колдонмонун ыңгайлаштырылган билдирмеси"</string>
<string name="user_creation_account_exists" msgid="2239146360099708035">"<xliff:g id="APP">%1$s</xliff:g> колдонмосуна <xliff:g id="ACCOUNT">%2$s</xliff:g> аккаунту менен жаңы колдонуучу түзүүгө уруксат бересизби (мындай аккаунту бар колдонуучу мурунтан эле бар)?"</string>
<string name="user_creation_adding" msgid="7305185499667958364">"<xliff:g id="APP">%1$s</xliff:g> колдонмосуна <xliff:g id="ACCOUNT">%2$s</xliff:g> аккаунту менен жаңы колдонуучу түзүүгө уруксат бересизби?"</string>
<string name="language_selection_title" msgid="52674936078683285">"Тил кошуу"</string>
@@ -2028,14 +2033,29 @@
<string name="as_app_forced_to_restricted_bucket" msgid="8233871289353898964">"<xliff:g id="PACKAGE_NAME">%1$s</xliff:g> ЧЕКТЕЛГЕН чакага коюлган"</string>
<string name="resolver_personal_tab" msgid="2051260504014442073">"Жеке"</string>
<string name="resolver_work_tab" msgid="2690019516263167035">"Жумуш"</string>
+ <!-- no translation found for resolver_personal_tab_accessibility (5739524949153091224) -->
+ <skip />
+ <!-- no translation found for resolver_work_tab_accessibility (4753168230363802734) -->
+ <skip />
<string name="resolver_cant_share_with_work_apps" msgid="7539495559434146897">"Жумуш колдонмолору менен бөлүшүүгө болбойт"</string>
<string name="resolver_cant_share_with_personal_apps" msgid="8020581735267157241">"Жеке колдонмолор менен бөлүшүүгө болбойт"</string>
- <string name="resolver_cant_share_cross_profile_explanation" msgid="3536237105241882679">"IT администраторуңуз жеке жана жумуш колдонмолорунун ортосунда бөлүшүүнү бөгөттөп койгон"</string>
- <string name="resolver_turn_on_work_apps" msgid="8987359079870455469">"Жумуш колдонмолорун күйгүзүү"</string>
- <string name="resolver_turn_on_work_apps_explanation" msgid="6322467455509618928">"Жумуш колдонмолоруна жана байланыштарга кирүү үчүн жумуш колдонмолорун күйүгүзүңүз"</string>
+ <!-- no translation found for resolver_cant_share_cross_profile_explanation (5556640604460901386) -->
+ <skip />
+ <!-- no translation found for resolver_cant_access_work_apps (375634344111233790) -->
+ <skip />
+ <!-- no translation found for resolver_cant_access_work_apps_explanation (3958762224516867388) -->
+ <skip />
+ <!-- no translation found for resolver_cant_access_personal_apps (1953215925406474177) -->
+ <skip />
+ <!-- no translation found for resolver_cant_access_personal_apps_explanation (1725572276741281136) -->
+ <skip />
+ <!-- no translation found for resolver_turn_on_work_apps_share (619263911204978175) -->
+ <skip />
+ <!-- no translation found for resolver_turn_on_work_apps_view (3073389230905543680) -->
+ <skip />
<string name="resolver_no_apps_available" msgid="7710339903040989654">"Колдонмолор жок"</string>
- <string name="resolver_no_apps_available_explanation" msgid="4662694431121196560">"Эч кандай колдонмо табылган жок"</string>
- <string name="resolver_switch_on_work" msgid="8294542702883688533">"Жумуш профилине которулуу"</string>
+ <!-- no translation found for resolver_switch_on_work (2873009160846966379) -->
+ <skip />
<string name="permlab_accessCallAudio" msgid="1682957511874097664">"Телефон чалууларда жаздырып же аудиону ойнотуу"</string>
<string name="permdesc_accessCallAudio" msgid="8448360894684277823">"Бул колдонмо демейки телефон катары дайындалганда ага чалууларды жаздырууга жана аудиону ойнотууга уруксат берет."</string>
</resources>
diff --git a/core/res/res/values-lo/strings.xml b/core/res/res/values-lo/strings.xml
index 862aa53fe9da..92ab1d3287bb 100644
--- a/core/res/res/values-lo/strings.xml
+++ b/core/res/res/values-lo/strings.xml
@@ -249,10 +249,8 @@
<item quantity="other">ກຳລັງຈະຖ່າຍພາບໜ້າຈໍສຳລັບການລາຍງານຂໍ້ຜິດພາດໃນ <xliff:g id="NUMBER_1">%d</xliff:g> ວິນາທີ.</item>
<item quantity="one">ກຳລັງຈະຖ່າຍພາບໜ້າຈໍສຳລັບການລາຍງານຂໍ້ຜິດພາດໃນ <xliff:g id="NUMBER_0">%d</xliff:g> ວິນາທີ.</item>
</plurals>
- <!-- no translation found for bugreport_screenshot_success_toast (7986095104151473745) -->
- <skip />
- <!-- no translation found for bugreport_screenshot_failure_toast (6736320861311294294) -->
- <skip />
+ <string name="bugreport_screenshot_success_toast" msgid="7986095104151473745">"ຖ່າຍຮູບໜ້າຈໍກັບການລາຍງານຂໍ້ຜິດພາດແລ້ວ"</string>
+ <string name="bugreport_screenshot_failure_toast" msgid="6736320861311294294">"ຖ່າຍຮູບໜ້າຈໍກັບການລາຍງານຂໍ້ຜິດພາດບໍ່ສຳເລັດ"</string>
<string name="global_action_toggle_silent_mode" msgid="8464352592860372188">"ໂໝດປິດສຽງ"</string>
<string name="global_action_silent_mode_on_status" msgid="2371892537738632013">"ປິດສຽງແລ້ວ"</string>
<string name="global_action_silent_mode_off_status" msgid="6608006545950920042">"ເປິດສຽງແລ້ວ"</string>
@@ -454,9 +452,11 @@
<string name="permdesc_acceptHandovers" msgid="7129026180128626870">"ອະນຸຍາດໃຫ້ແອັບສືບຕໍ່ການໂທເຊິ່ງອາດຖືກເລີ່ມຕົ້ນໃນແອັບອື່ນ."</string>
<string name="permlab_readPhoneNumbers" msgid="5668704794723365628">"ອ່ານເບີໂທລະສັບ"</string>
<string name="permdesc_readPhoneNumbers" msgid="7368652482818338871">"ອະນຸຍາດໃຫ້ແອັບເຂົ້າເຖິງເບີໂທລະສັບຂອງອຸປະກອນໄດ້."</string>
+ <string name="permlab_wakeLock" product="automotive" msgid="1904736682319375676">"ເປີດໜ້າຈໍລົດໄວ້ຕະຫຼອດ"</string>
<string name="permlab_wakeLock" product="tablet" msgid="1527660973931694000">"ຂັດຂວາງບໍ່ໃຫ້ປິດໜ້າຈໍແທັບເລັດ"</string>
<string name="permlab_wakeLock" product="tv" msgid="2856941418123343518">"ປ້ອງກັນບໍ່ໃຫ້ອຸປະກອນ Android TV ຂອງທ່ານນອນ"</string>
<string name="permlab_wakeLock" product="default" msgid="569409726861695115">"ຂັດຂວາງບໍ່ໃຫ້ໂທລະສັບປິດໜ້າຈໍ"</string>
+ <string name="permdesc_wakeLock" product="automotive" msgid="5995045369683254571">"ອະນຸຍາດໃຫ້ແອັບເຮັດໃຫ້ໜ້າຈໍລົດເປີດໄວ້ຕະຫຼອດ."</string>
<string name="permdesc_wakeLock" product="tablet" msgid="2441742939101526277">"ອະນຸຍາດໃຫ້ແອັບຯ ປ້ອງກັນບໍ່ໃຫ້ປິດໜ້າຈໍແທັບເລັດ."</string>
<string name="permdesc_wakeLock" product="tv" msgid="2329298966735118796">"ອະນຸຍາດໃຫ້ແອັບປ້ອງກັນບໍ່ໃຫ້ອຸປະກອນ Android TV ຂອງທ່ານນອນ."</string>
<string name="permdesc_wakeLock" product="default" msgid="3689523792074007163">"ອະນຸຍາດໃຫ້ແອັບຯປ້ອງກັນບໍ່ໃຫ້ປິດໜ້າຈໍໂທລະສັບ."</string>
@@ -1631,6 +1631,12 @@
<string name="safe_media_volume_warning" product="default" msgid="3751676824423049994">"ເພີ່ມ​ລະ​ດັບ​ສຽງ​ໃຫ້​ເກີນກວ່າ​ລະ​ດັບ​ທີ່​ແນະ​ນຳ​ບໍ?\n\n​ການ​ຮັບ​ຟັງ​ສຽງ​ໃນ​ລະ​ດັບ​ທີ່​ສູງ​ເປັນ​ໄລ​ຍະ​ເວ​ລາ​ດົນ​​ອາດ​ເຮັດ​ໃຫ້​ການ​ຟັງ​ຂອງ​ທ່ານ​ມີ​ບັນ​ຫາ​ໄດ້."</string>
<string name="accessibility_shortcut_warning_dialog_title" msgid="4017995837692622933">"ໃຊ້ປຸ່ມລັດການຊ່ວຍເຂົ້າເຖິງບໍ?"</string>
<string name="accessibility_shortcut_toogle_warning" msgid="4161716521310929544">"ເມື່ອເປີດໃຊ້ທາງລັດແລ້ວ, ການກົດປຸ່ມລະດັບສຽງທັງສອງຄ້າງໄວ້ 3 ວິນາທີຈະເປັນການເລີ່ມຄຸນສົມບັດການຊ່ວຍເຂົ້າເຖິງ."</string>
+ <!-- no translation found for accessibility_select_shortcut_menu_title (7310194076629867377) -->
+ <skip />
+ <!-- no translation found for accessibility_edit_shortcut_menu_button_title (6096484087245145325) -->
+ <skip />
+ <!-- no translation found for accessibility_edit_shortcut_menu_volume_title (4849108668454490699) -->
+ <skip />
<string name="edit_accessibility_shortcut_menu_button" msgid="8885752738733772935">"ແກ້ໄຂທາງລັດ"</string>
<string name="cancel_accessibility_shortcut_menu_button" msgid="1817413122335452474">"ຍົກເລີກ"</string>
<string name="disable_accessibility_shortcut" msgid="5806091378745232383">"ປິດປຸ່ມລັດ"</string>
@@ -1853,8 +1859,7 @@
<string name="default_notification_channel_label" msgid="3697928973567217330">"ບໍ່​ມີ​ໝວດ​ໝູ່"</string>
<string name="importance_from_user" msgid="2782756722448800447">"ທ່ານຕັ້ງຄວາມສຳຄັນຂອງການແຈ້ງເຕືອນເຫຼົ່ານີ້."</string>
<string name="importance_from_person" msgid="4235804979664465383">"ຂໍ້ຄວາມນີ້ສຳຄັນເນື່ອງຈາກບຸກຄົນທີ່ກ່ຽວຂ້ອງ."</string>
- <!-- no translation found for notification_history_title_placeholder (7748630986182249599) -->
- <skip />
+ <string name="notification_history_title_placeholder" msgid="7748630986182249599">"ການແຈ້ງເຕືອນແອັບແບບກຳນົດເອງ"</string>
<string name="user_creation_account_exists" msgid="2239146360099708035">"ອະນຸຍາດໃຫ້ <xliff:g id="APP">%1$s</xliff:g> ສ້າງຜູ້ໃຊ້ໃໝ່ກັບ <xliff:g id="ACCOUNT">%2$s</xliff:g> ໄດ້ບໍ່ (ມີຜູ້ໃຊ້ທີ່ໃຊ້ບັນຊີນີ້ຢູ່ກ່ອນແລ້ວ) ?"</string>
<string name="user_creation_adding" msgid="7305185499667958364">"ອະນຸຍາດໃຫ້ <xliff:g id="APP">%1$s</xliff:g> ສ້າງຜູ້ໃຊ້ໃໝ່ກັບ <xliff:g id="ACCOUNT">%2$s</xliff:g> ໄດ້ບໍ?"</string>
<string name="language_selection_title" msgid="52674936078683285">"ເພີ່ມພາສາ"</string>
@@ -2028,14 +2033,29 @@
<string name="as_app_forced_to_restricted_bucket" msgid="8233871289353898964">"<xliff:g id="PACKAGE_NAME">%1$s</xliff:g> ຖືກວາງໄວ້ໃນກະຕ່າ \"ຈຳກັດ\" ແລ້ວ"</string>
<string name="resolver_personal_tab" msgid="2051260504014442073">"ສ່ວນຕົວ"</string>
<string name="resolver_work_tab" msgid="2690019516263167035">"ວຽກ"</string>
+ <!-- no translation found for resolver_personal_tab_accessibility (5739524949153091224) -->
+ <skip />
+ <!-- no translation found for resolver_work_tab_accessibility (4753168230363802734) -->
+ <skip />
<string name="resolver_cant_share_with_work_apps" msgid="7539495559434146897">"ບໍ່ສາມາດແບ່ງປັນກັບແອັບວຽກໄດ້"</string>
<string name="resolver_cant_share_with_personal_apps" msgid="8020581735267157241">"ບໍ່ສາມາດແບ່ງປັນກັບແອັບສ່ວນຕົວໄດ້"</string>
- <string name="resolver_cant_share_cross_profile_explanation" msgid="3536237105241882679">"ຜູ້ເບິ່ງແຍງໄອທີຂອງທ່ານບລັອກການແບ່ງປັນລະຫວ່າງແອັບສ່ວນຕົວ ແລະ ແອັບວຽກໄວ້"</string>
- <string name="resolver_turn_on_work_apps" msgid="8987359079870455469">"ປຸ່ມເປີດຢູ່ແອັບວຽກ"</string>
- <string name="resolver_turn_on_work_apps_explanation" msgid="6322467455509618928">"ເປີດໃຊ້ແອັບວຽກເພື່ອເຂົ້າເຖິງແອັບ ແລະ ລາຍຊື່ຜູ້ຕິດຕໍ່ວຽກ"</string>
+ <!-- no translation found for resolver_cant_share_cross_profile_explanation (5556640604460901386) -->
+ <skip />
+ <!-- no translation found for resolver_cant_access_work_apps (375634344111233790) -->
+ <skip />
+ <!-- no translation found for resolver_cant_access_work_apps_explanation (3958762224516867388) -->
+ <skip />
+ <!-- no translation found for resolver_cant_access_personal_apps (1953215925406474177) -->
+ <skip />
+ <!-- no translation found for resolver_cant_access_personal_apps_explanation (1725572276741281136) -->
+ <skip />
+ <!-- no translation found for resolver_turn_on_work_apps_share (619263911204978175) -->
+ <skip />
+ <!-- no translation found for resolver_turn_on_work_apps_view (3073389230905543680) -->
+ <skip />
<string name="resolver_no_apps_available" msgid="7710339903040989654">"ບໍ່ມີແອັບທີ່ສາມາດໃຊ້ໄດ້"</string>
- <string name="resolver_no_apps_available_explanation" msgid="4662694431121196560">"ພວກເຮົາບໍ່ພົບແອັບໃດໆເລີຍ"</string>
- <string name="resolver_switch_on_work" msgid="8294542702883688533">"ປຸ່ມເປີດຢູ່ວຽກ"</string>
+ <!-- no translation found for resolver_switch_on_work (2873009160846966379) -->
+ <skip />
<string name="permlab_accessCallAudio" msgid="1682957511874097664">"ບັນທຶກ ຫຼື ຫຼິ້ນສຽງໃນການໂທລະສັບ"</string>
<string name="permdesc_accessCallAudio" msgid="8448360894684277823">"ອະນຸຍາດແອັບນີ້, ເມື່ອມອບໝາຍເປັນແອັບພລິເຄຊັນໂທລະສັບເລີ່ມຕົ້ນເພື່ອບັນທຶກ ຫຼື ຫຼິ້ນສຽງໃນການໂທລະສັບ."</string>
</resources>
diff --git a/core/res/res/values-lt/strings.xml b/core/res/res/values-lt/strings.xml
index e816f5e23969..518bb186247a 100644
--- a/core/res/res/values-lt/strings.xml
+++ b/core/res/res/values-lt/strings.xml
@@ -255,10 +255,8 @@
<item quantity="many">Pranešimo apie riktą ekrano kopija bus užfiksuota po <xliff:g id="NUMBER_1">%d</xliff:g> sekundės.</item>
<item quantity="other">Pranešimo apie riktą ekrano kopija bus užfiksuota po <xliff:g id="NUMBER_1">%d</xliff:g> sekundžių.</item>
</plurals>
- <!-- no translation found for bugreport_screenshot_success_toast (7986095104151473745) -->
- <skip />
- <!-- no translation found for bugreport_screenshot_failure_toast (6736320861311294294) -->
- <skip />
+ <string name="bugreport_screenshot_success_toast" msgid="7986095104151473745">"Sukurta ekrano kopija su pranešimu apie riktą"</string>
+ <string name="bugreport_screenshot_failure_toast" msgid="6736320861311294294">"Nepavyko sukurti ekrano kopijos su pranešimu apie riktą"</string>
<string name="global_action_toggle_silent_mode" msgid="8464352592860372188">"Tylus režimas"</string>
<string name="global_action_silent_mode_on_status" msgid="2371892537738632013">"Garsas IŠJUNGTAS"</string>
<string name="global_action_silent_mode_off_status" msgid="6608006545950920042">"Garsas ĮJUNGTAS"</string>
@@ -460,9 +458,11 @@
<string name="permdesc_acceptHandovers" msgid="7129026180128626870">"Programai leidžiama tęsti skambutį, kuris buvo pradėtas naudojant kitą programą."</string>
<string name="permlab_readPhoneNumbers" msgid="5668704794723365628">"skaityti telefonų numerius"</string>
<string name="permdesc_readPhoneNumbers" msgid="7368652482818338871">"Programai leidžiama pasiekti įrenginio telefonų numerius."</string>
+ <string name="permlab_wakeLock" product="automotive" msgid="1904736682319375676">"palikti automobilio ekraną įjungtą"</string>
<string name="permlab_wakeLock" product="tablet" msgid="1527660973931694000">"neleisti planšetiniam kompiuteriui užmigti"</string>
<string name="permlab_wakeLock" product="tv" msgid="2856941418123343518">"neleisti „Android TV“ įrenginiui užmigti"</string>
<string name="permlab_wakeLock" product="default" msgid="569409726861695115">"neleisti telefonui snausti"</string>
+ <string name="permdesc_wakeLock" product="automotive" msgid="5995045369683254571">"Programai leidžiama palikti automobilio ekraną įjungtą."</string>
<string name="permdesc_wakeLock" product="tablet" msgid="2441742939101526277">"Leidžiama programai neleisti planšetiniam kompiuteriui užmigti."</string>
<string name="permdesc_wakeLock" product="tv" msgid="2329298966735118796">"Programai leidžiama nustatyti, kad „Android TV“ įrenginys nebūtų perjungtas į miego būseną."</string>
<string name="permdesc_wakeLock" product="default" msgid="3689523792074007163">"Leidžiama programai neleisti telefonui užmigti."</string>
@@ -1675,6 +1675,12 @@
<string name="safe_media_volume_warning" product="default" msgid="3751676824423049994">"Padidinti garsą daugiau nei rekomenduojamas lygis?\n\nIlgai klausydami dideliu garsu galite pažeisti klausą."</string>
<string name="accessibility_shortcut_warning_dialog_title" msgid="4017995837692622933">"Naudoti spartųjį pritaikymo neįgaliesiems klavišą?"</string>
<string name="accessibility_shortcut_toogle_warning" msgid="4161716521310929544">"Kai spartusis klavišas įjungtas, paspaudus abu garsumo mygtukus ir palaikius 3 sekundes bus įjungta pritaikymo neįgaliesiems funkcija."</string>
+ <!-- no translation found for accessibility_select_shortcut_menu_title (7310194076629867377) -->
+ <skip />
+ <!-- no translation found for accessibility_edit_shortcut_menu_button_title (6096484087245145325) -->
+ <skip />
+ <!-- no translation found for accessibility_edit_shortcut_menu_volume_title (4849108668454490699) -->
+ <skip />
<string name="edit_accessibility_shortcut_menu_button" msgid="8885752738733772935">"Redaguoti sparčiuosius klavišus"</string>
<string name="cancel_accessibility_shortcut_menu_button" msgid="1817413122335452474">"Atšaukti"</string>
<string name="disable_accessibility_shortcut" msgid="5806091378745232383">"Išjungti spartųjį klavišą"</string>
@@ -1917,8 +1923,7 @@
<string name="default_notification_channel_label" msgid="3697928973567217330">"Be kategorijos"</string>
<string name="importance_from_user" msgid="2782756722448800447">"Galite nustatyti šių pranešimų svarbą."</string>
<string name="importance_from_person" msgid="4235804979664465383">"Tai svarbu dėl susijusių žmonių."</string>
- <!-- no translation found for notification_history_title_placeholder (7748630986182249599) -->
- <skip />
+ <string name="notification_history_title_placeholder" msgid="7748630986182249599">"Tinkintas programos pranešimas"</string>
<string name="user_creation_account_exists" msgid="2239146360099708035">"Leisti „<xliff:g id="APP">%1$s</xliff:g>“ kurti naują <xliff:g id="ACCOUNT">%2$s</xliff:g> naudotoją (šią paskyrą naudojantis naudotojas jau yra)?"</string>
<string name="user_creation_adding" msgid="7305185499667958364">"Leisti „<xliff:g id="APP">%1$s</xliff:g>“ kurti naują <xliff:g id="ACCOUNT">%2$s</xliff:g> naudotoją?"</string>
<string name="language_selection_title" msgid="52674936078683285">"Pridėkite kalbą"</string>
@@ -2096,14 +2101,29 @@
<string name="as_app_forced_to_restricted_bucket" msgid="8233871289353898964">"„<xliff:g id="PACKAGE_NAME">%1$s</xliff:g>“ įkeltas į grupę APRIBOTA"</string>
<string name="resolver_personal_tab" msgid="2051260504014442073">"Asmeninė"</string>
<string name="resolver_work_tab" msgid="2690019516263167035">"Darbo"</string>
+ <!-- no translation found for resolver_personal_tab_accessibility (5739524949153091224) -->
+ <skip />
+ <!-- no translation found for resolver_work_tab_accessibility (4753168230363802734) -->
+ <skip />
<string name="resolver_cant_share_with_work_apps" msgid="7539495559434146897">"Negalima bendrinti su darbo programomis"</string>
<string name="resolver_cant_share_with_personal_apps" msgid="8020581735267157241">"Negalima bendrinti su asmeninėmis programomis"</string>
- <string name="resolver_cant_share_cross_profile_explanation" msgid="3536237105241882679">"IT administratorius užblokavo bendrinimą tarp asmeninių programų ir darbo programų"</string>
- <string name="resolver_turn_on_work_apps" msgid="8987359079870455469">"Įjunkite darbo programas"</string>
- <string name="resolver_turn_on_work_apps_explanation" msgid="6322467455509618928">"Įjunkite darbo programas, kad galėtumėte pasiekti darbo programas ir kontaktus"</string>
+ <!-- no translation found for resolver_cant_share_cross_profile_explanation (5556640604460901386) -->
+ <skip />
+ <!-- no translation found for resolver_cant_access_work_apps (375634344111233790) -->
+ <skip />
+ <!-- no translation found for resolver_cant_access_work_apps_explanation (3958762224516867388) -->
+ <skip />
+ <!-- no translation found for resolver_cant_access_personal_apps (1953215925406474177) -->
+ <skip />
+ <!-- no translation found for resolver_cant_access_personal_apps_explanation (1725572276741281136) -->
+ <skip />
+ <!-- no translation found for resolver_turn_on_work_apps_share (619263911204978175) -->
+ <skip />
+ <!-- no translation found for resolver_turn_on_work_apps_view (3073389230905543680) -->
+ <skip />
<string name="resolver_no_apps_available" msgid="7710339903040989654">"Nėra pasiekiamų programų"</string>
- <string name="resolver_no_apps_available_explanation" msgid="4662694431121196560">"Nepavyko rasti programų"</string>
- <string name="resolver_switch_on_work" msgid="8294542702883688533">"Įjungti darbo profilį"</string>
+ <!-- no translation found for resolver_switch_on_work (2873009160846966379) -->
+ <skip />
<string name="permlab_accessCallAudio" msgid="1682957511874097664">"Telefonų skambučių garso įrašo įrašymas arba leidimas"</string>
<string name="permdesc_accessCallAudio" msgid="8448360894684277823">"Leidžiama šiai programai, esant prisijungus kaip numatytajai numerio rinkiklio programai, įrašyti ar leisti telefonų skambučių garso įrašą."</string>
</resources>
diff --git a/core/res/res/values-lv/strings.xml b/core/res/res/values-lv/strings.xml
index 8aa7e5ae9b5f..afe8f9a99f52 100644
--- a/core/res/res/values-lv/strings.xml
+++ b/core/res/res/values-lv/strings.xml
@@ -252,10 +252,8 @@
<item quantity="one">Pēc <xliff:g id="NUMBER_1">%d</xliff:g> sekundes tiks veikts ekrānuzņēmums kļūdas pārskatam.</item>
<item quantity="other">Pēc <xliff:g id="NUMBER_1">%d</xliff:g> sekundēm tiks veikts ekrānuzņēmums kļūdas pārskatam.</item>
</plurals>
- <!-- no translation found for bugreport_screenshot_success_toast (7986095104151473745) -->
- <skip />
- <!-- no translation found for bugreport_screenshot_failure_toast (6736320861311294294) -->
- <skip />
+ <string name="bugreport_screenshot_success_toast" msgid="7986095104151473745">"Izveidots ekrānuzņēmums ar kļūdas pārskatu."</string>
+ <string name="bugreport_screenshot_failure_toast" msgid="6736320861311294294">"Neizdevās izveidot ekrānuzņēmumu ar kļūdas pārskatu."</string>
<string name="global_action_toggle_silent_mode" msgid="8464352592860372188">"Klusuma režīms"</string>
<string name="global_action_silent_mode_on_status" msgid="2371892537738632013">"Skaņa ir IZSLĒGTA."</string>
<string name="global_action_silent_mode_off_status" msgid="6608006545950920042">"Skaņa ir IESLĒGTA."</string>
@@ -457,9 +455,11 @@
<string name="permdesc_acceptHandovers" msgid="7129026180128626870">"Ļauj lietotnei turpināt zvanu, kas tika sākts citā lietotnē."</string>
<string name="permlab_readPhoneNumbers" msgid="5668704794723365628">"lasīt tālruņa numurus"</string>
<string name="permdesc_readPhoneNumbers" msgid="7368652482818338871">"Ļauj lietotnei piekļūt ierīcē esošajiem tālruņa numuriem."</string>
+ <string name="permlab_wakeLock" product="automotive" msgid="1904736682319375676">"paturēt ieslēgtu automašīnas ekrānu"</string>
<string name="permlab_wakeLock" product="tablet" msgid="1527660973931694000">"novērst planšetdatora pāriešanu miega režīmā"</string>
<string name="permlab_wakeLock" product="tv" msgid="2856941418123343518">"Android TV miega režīma ieslēgšanas liegšana"</string>
<string name="permlab_wakeLock" product="default" msgid="569409726861695115">"novērst tālruņa pāriešanu miega režīmā"</string>
+ <string name="permdesc_wakeLock" product="automotive" msgid="5995045369683254571">"Ļauj lietotnei paturēt ieslēgtu automašīnas ekrānu."</string>
<string name="permdesc_wakeLock" product="tablet" msgid="2441742939101526277">"Ļauj lietotnei novērst planšetdatora pāriešanu miega režīmā."</string>
<string name="permdesc_wakeLock" product="tv" msgid="2329298966735118796">"Ļauj lietotnei novērst Android TV ierīces pāriešanu miega režīmā."</string>
<string name="permdesc_wakeLock" product="default" msgid="3689523792074007163">"Ļauj lietotnei novērst tālruņa pāriešanu miega režīmā."</string>
@@ -1653,6 +1653,12 @@
<string name="safe_media_volume_warning" product="default" msgid="3751676824423049994">"Vai palielināt skaļumu virs ieteicamā līmeņa?\n\nIlgstoši klausoties skaņu lielā skaļumā, var tikt bojāta dzirde."</string>
<string name="accessibility_shortcut_warning_dialog_title" msgid="4017995837692622933">"Vai izmantot pieejamības saīsni?"</string>
<string name="accessibility_shortcut_toogle_warning" msgid="4161716521310929544">"Kad īsinājumtaustiņš ir ieslēgts, nospiežot abas skaļuma pogas un 3 sekundes turot tās, tiks aktivizēta pieejamības funkcija."</string>
+ <!-- no translation found for accessibility_select_shortcut_menu_title (7310194076629867377) -->
+ <skip />
+ <!-- no translation found for accessibility_edit_shortcut_menu_button_title (6096484087245145325) -->
+ <skip />
+ <!-- no translation found for accessibility_edit_shortcut_menu_volume_title (4849108668454490699) -->
+ <skip />
<string name="edit_accessibility_shortcut_menu_button" msgid="8885752738733772935">"Rediģēt īsinājumtaustiņus"</string>
<string name="cancel_accessibility_shortcut_menu_button" msgid="1817413122335452474">"Atcelt"</string>
<string name="disable_accessibility_shortcut" msgid="5806091378745232383">"Izslēgt saīsni"</string>
@@ -1885,8 +1891,7 @@
<string name="default_notification_channel_label" msgid="3697928973567217330">"Nav kategorijas"</string>
<string name="importance_from_user" msgid="2782756722448800447">"Jūs iestatījāt šo paziņojumu svarīguma līmeni."</string>
<string name="importance_from_person" msgid="4235804979664465383">"Tas ir svarīgi iesaistīto personu dēļ."</string>
- <!-- no translation found for notification_history_title_placeholder (7748630986182249599) -->
- <skip />
+ <string name="notification_history_title_placeholder" msgid="7748630986182249599">"Pielāgots lietotnes paziņojums"</string>
<string name="user_creation_account_exists" msgid="2239146360099708035">"Vai atļaut lietotnei <xliff:g id="APP">%1$s</xliff:g> izveidot jaunu lietotāju, izmantojot e-pasta adresi <xliff:g id="ACCOUNT">%2$s</xliff:g> (lietotājs ar šādu kontu jau pastāv)?"</string>
<string name="user_creation_adding" msgid="7305185499667958364">"Vai atļaut lietotnei <xliff:g id="APP">%1$s</xliff:g> izveidot jaunu lietotāju, izmantojot e-pasta adresi <xliff:g id="ACCOUNT">%2$s</xliff:g>?"</string>
<string name="language_selection_title" msgid="52674936078683285">"Pievienot valodu"</string>
@@ -2062,14 +2067,29 @@
<string name="as_app_forced_to_restricted_bucket" msgid="8233871289353898964">"Pakotne “<xliff:g id="PACKAGE_NAME">%1$s</xliff:g>” ir ievietota ierobežotā kopā."</string>
<string name="resolver_personal_tab" msgid="2051260504014442073">"Privātais profils"</string>
<string name="resolver_work_tab" msgid="2690019516263167035">"Darba profils"</string>
+ <!-- no translation found for resolver_personal_tab_accessibility (5739524949153091224) -->
+ <skip />
+ <!-- no translation found for resolver_work_tab_accessibility (4753168230363802734) -->
+ <skip />
<string name="resolver_cant_share_with_work_apps" msgid="7539495559434146897">"Nevar kopīgot ar darba lietotnēm"</string>
<string name="resolver_cant_share_with_personal_apps" msgid="8020581735267157241">"Nevar kopīgot ar personīgajām lietotnēm"</string>
- <string name="resolver_cant_share_cross_profile_explanation" msgid="3536237105241882679">"Jūsu IT administrators bloķēja datu kopīgošanu starp personīgajām un darba lietotnēm."</string>
- <string name="resolver_turn_on_work_apps" msgid="8987359079870455469">"Ieslēdziet darba lietotnes"</string>
- <string name="resolver_turn_on_work_apps_explanation" msgid="6322467455509618928">"Ieslēdziet darba lietotnes, lai piekļūtu darba lietotnēm un kontaktpersonām."</string>
+ <!-- no translation found for resolver_cant_share_cross_profile_explanation (5556640604460901386) -->
+ <skip />
+ <!-- no translation found for resolver_cant_access_work_apps (375634344111233790) -->
+ <skip />
+ <!-- no translation found for resolver_cant_access_work_apps_explanation (3958762224516867388) -->
+ <skip />
+ <!-- no translation found for resolver_cant_access_personal_apps (1953215925406474177) -->
+ <skip />
+ <!-- no translation found for resolver_cant_access_personal_apps_explanation (1725572276741281136) -->
+ <skip />
+ <!-- no translation found for resolver_turn_on_work_apps_share (619263911204978175) -->
+ <skip />
+ <!-- no translation found for resolver_turn_on_work_apps_view (3073389230905543680) -->
+ <skip />
<string name="resolver_no_apps_available" msgid="7710339903040989654">"Nav pieejamu lietotņu"</string>
- <string name="resolver_no_apps_available_explanation" msgid="4662694431121196560">"Netika atrasta neviena lietotne."</string>
- <string name="resolver_switch_on_work" msgid="8294542702883688533">"Ieslēgt darba profilu"</string>
+ <!-- no translation found for resolver_switch_on_work (2873009160846966379) -->
+ <skip />
<string name="permlab_accessCallAudio" msgid="1682957511874097664">"Ierakstīt vai atskaņot audio tālruņa sarunās"</string>
<string name="permdesc_accessCallAudio" msgid="8448360894684277823">"Ļauj šai lietotnei ierakstīt vai atskaņot audio tālruņa sarunās, kad tā ir iestatīta kā noklusējuma tālruņa lietojumprogramma."</string>
</resources>
diff --git a/core/res/res/values-ml/strings.xml b/core/res/res/values-ml/strings.xml
index 1513db16adb7..8bf137f26e9e 100644
--- a/core/res/res/values-ml/strings.xml
+++ b/core/res/res/values-ml/strings.xml
@@ -249,10 +249,8 @@
<item quantity="other">ബഗ് റിപ്പോർട്ടിനായി <xliff:g id="NUMBER_1">%d</xliff:g> സെക്കൻഡിൽ സ്ക്രീൻഷോട്ട് എടുക്കുന്നു.</item>
<item quantity="one">ബഗ് റിപ്പോർട്ടിനായി <xliff:g id="NUMBER_0">%d</xliff:g> സെക്കൻഡിൽ സ്ക്രീൻഷോട്ട് എടുക്കുന്നു.</item>
</plurals>
- <!-- no translation found for bugreport_screenshot_success_toast (7986095104151473745) -->
- <skip />
- <!-- no translation found for bugreport_screenshot_failure_toast (6736320861311294294) -->
- <skip />
+ <string name="bugreport_screenshot_success_toast" msgid="7986095104151473745">"ബഗ് റിപ്പോർട്ടിന്റെ സ്ക്രീൻഷോട്ട് എടുത്തു"</string>
+ <string name="bugreport_screenshot_failure_toast" msgid="6736320861311294294">"ബഗ് റിപ്പോർട്ടിന്റെ സ്ക്രീൻഷോട്ട് എടുക്കാനായില്ല"</string>
<string name="global_action_toggle_silent_mode" msgid="8464352592860372188">"നിശബ്‌ദ മോഡ്"</string>
<string name="global_action_silent_mode_on_status" msgid="2371892537738632013">"ശബ്‌ദം ഓഫാണ്"</string>
<string name="global_action_silent_mode_off_status" msgid="6608006545950920042">"ശബ്‌ദം ഓണാണ്"</string>
@@ -454,9 +452,11 @@
<string name="permdesc_acceptHandovers" msgid="7129026180128626870">"മറ്റൊരു ആപ്പിൽ ആരംഭിച്ച കോൾ തുടരാൻ ആപ്പിനെ അനുവദിക്കുന്നു."</string>
<string name="permlab_readPhoneNumbers" msgid="5668704794723365628">"ഫോൺ നമ്പറുകൾ റീഡുചെയ്യൽ"</string>
<string name="permdesc_readPhoneNumbers" msgid="7368652482818338871">"ഉപകരണത്തിന്റെ ഫോൺ നമ്പറുകൾ ആക്‌സസ് ചെയ്യാൻ ആപ്പിനെ അനുവദിക്കുന്നു."</string>
+ <string name="permlab_wakeLock" product="automotive" msgid="1904736682319375676">"കാറിലെ സ്ക്രീൻ ഓണാക്കി വയ്ക്കുക"</string>
<string name="permlab_wakeLock" product="tablet" msgid="1527660973931694000">"ഉറങ്ങുന്നതിൽ നിന്ന് ടാബ്‌ലെറ്റിനെ തടയുക"</string>
<string name="permlab_wakeLock" product="tv" msgid="2856941418123343518">"നിങ്ങളുടെ Android ടിവി ഉറങ്ങുന്നതിൽ നിന്ന് തടയുക"</string>
<string name="permlab_wakeLock" product="default" msgid="569409726861695115">"ഉറങ്ങുന്നതിൽ നിന്ന് ഫോണിനെ തടയുക"</string>
+ <string name="permdesc_wakeLock" product="automotive" msgid="5995045369683254571">"കാറിലെ സ്ക്രീൻ ഓണാക്കി വയ്ക്കാൻ ആപ്പിനെ അനുവദിക്കുന്നു."</string>
<string name="permdesc_wakeLock" product="tablet" msgid="2441742939101526277">"ടാബ്‌ലെറ്റ് സുഷുപ്തിയിലാകുന്നതിൽ നിന്നും തടയുന്നതിന് അപ്ലിക്കേഷനെ അനുവദിക്കുന്നു."</string>
<string name="permdesc_wakeLock" product="tv" msgid="2329298966735118796">"നിങ്ങളുടെ Android ടിവിയെ ഉറങ്ങുന്നതിൽ നിന്ന് തടയാൻ ആപ്പിനെ അനുവദിക്കുന്നു."</string>
<string name="permdesc_wakeLock" product="default" msgid="3689523792074007163">"ഫോൺ സുഷുപ്തിയിലാകുന്നതിൽ നിന്നും തടയുന്നതിന് അപ്ലിക്കേഷനെ അനുവദിക്കുന്നു."</string>
@@ -1631,6 +1631,12 @@
<string name="safe_media_volume_warning" product="default" msgid="3751676824423049994">"മുകളിൽക്കൊടുത്തിരിക്കുന്ന ശുപാർശചെയ്‌ത ലെവലിലേക്ക് വോളിയം വർദ്ധിപ്പിക്കണോ?\n\nഉയർന്ന വോളിയത്തിൽ ദീർഘനേരം കേൾക്കുന്നത് നിങ്ങളുടെ ശ്രവണ ശേഷിയെ ദോഷകരമായി ബാധിക്കാം."</string>
<string name="accessibility_shortcut_warning_dialog_title" msgid="4017995837692622933">"ഉപയോഗസഹായി കുറുക്കുവഴി ഉപയോഗിക്കണോ?"</string>
<string name="accessibility_shortcut_toogle_warning" msgid="4161716521310929544">"കുറുക്കുവഴി ഓണായിരിക്കുമ്പോൾ, രണ്ട് വോളിയം ബട്ടണുകളും 3 സെക്കൻഡ് നേരത്തേക്ക് അമർത്തുന്നത് ഉപയോഗസഹായി ഫീച്ചർ ആരംഭിക്കും."</string>
+ <!-- no translation found for accessibility_select_shortcut_menu_title (7310194076629867377) -->
+ <skip />
+ <!-- no translation found for accessibility_edit_shortcut_menu_button_title (6096484087245145325) -->
+ <skip />
+ <!-- no translation found for accessibility_edit_shortcut_menu_volume_title (4849108668454490699) -->
+ <skip />
<string name="edit_accessibility_shortcut_menu_button" msgid="8885752738733772935">"കുറുക്കുവഴികൾ തിരുത്തുക"</string>
<string name="cancel_accessibility_shortcut_menu_button" msgid="1817413122335452474">"റദ്ദാക്കുക"</string>
<string name="disable_accessibility_shortcut" msgid="5806091378745232383">"കുറുക്കുവഴി ‌ഓഫാക്കുക"</string>
@@ -2028,14 +2034,29 @@
<string name="as_app_forced_to_restricted_bucket" msgid="8233871289353898964">"<xliff:g id="PACKAGE_NAME">%1$s</xliff:g> നിയന്ത്രിത ബക്കറ്റിലേക്ക് നീക്കി"</string>
<string name="resolver_personal_tab" msgid="2051260504014442073">"വ്യക്തിപരമായത്"</string>
<string name="resolver_work_tab" msgid="2690019516263167035">"ജോലിസ്ഥലം"</string>
+ <!-- no translation found for resolver_personal_tab_accessibility (5739524949153091224) -->
+ <skip />
+ <!-- no translation found for resolver_work_tab_accessibility (4753168230363802734) -->
+ <skip />
<string name="resolver_cant_share_with_work_apps" msgid="7539495559434146897">"ഔദ്യോഗിക ആപ്പുകൾ ഉപയോഗിച്ച് പങ്കിടാനാവില്ല"</string>
<string name="resolver_cant_share_with_personal_apps" msgid="8020581735267157241">"വ്യക്തിപരമാക്കിയ ആപ്പുകൾ ഉപയോഗിച്ച് പങ്കിടാനാവില്ല"</string>
- <string name="resolver_cant_share_cross_profile_explanation" msgid="3536237105241882679">"വ്യക്തിപരമാക്കിയ ആപ്പുകളുടെയും ഔദ്യോഗിക ആപ്പുകളുടെയും ഇടയിലുള്ള പങ്കിടൽ നിങ്ങളുടെ ഐടി അഡ്മിൻ ബ്ലോക്ക് ചെയ്തു"</string>
- <string name="resolver_turn_on_work_apps" msgid="8987359079870455469">"ഔദ്യോഗിക ആപ്പുകൾ ഓണാക്കുക"</string>
- <string name="resolver_turn_on_work_apps_explanation" msgid="6322467455509618928">"ഔദ്യോഗിക ആപ്പുകൾ, കോൺടാക്റ്റുകൾ എന്നിവ ആക്സസ് ചെയ്യാൻ ഔദ്യോഗിക ആപ്പുകൾ ഓണാക്കുക"</string>
+ <!-- no translation found for resolver_cant_share_cross_profile_explanation (5556640604460901386) -->
+ <skip />
+ <!-- no translation found for resolver_cant_access_work_apps (375634344111233790) -->
+ <skip />
+ <!-- no translation found for resolver_cant_access_work_apps_explanation (3958762224516867388) -->
+ <skip />
+ <!-- no translation found for resolver_cant_access_personal_apps (1953215925406474177) -->
+ <skip />
+ <!-- no translation found for resolver_cant_access_personal_apps_explanation (1725572276741281136) -->
+ <skip />
+ <!-- no translation found for resolver_turn_on_work_apps_share (619263911204978175) -->
+ <skip />
+ <!-- no translation found for resolver_turn_on_work_apps_view (3073389230905543680) -->
+ <skip />
<string name="resolver_no_apps_available" msgid="7710339903040989654">"ആപ്പുകളൊന്നും ലഭ്യമല്ല"</string>
- <string name="resolver_no_apps_available_explanation" msgid="4662694431121196560">"ഞങ്ങൾക്ക് ആപ്പുകളൊന്നും കണ്ടെത്താൻ കഴിഞ്ഞില്ല"</string>
- <string name="resolver_switch_on_work" msgid="8294542702883688533">"ഔദ്യോഗിക പ്രൊഫൈൽ ഓണാക്കുക"</string>
+ <!-- no translation found for resolver_switch_on_work (2873009160846966379) -->
+ <skip />
<string name="permlab_accessCallAudio" msgid="1682957511874097664">"ടെലിഫോൺ കോളുകൾ ചെയ്യുമ്പോൾ റെക്കോർഡ് ചെയ്യുക അല്ലെങ്കിൽ ഓഡിയോ പ്ലേ ചെയ്യുക"</string>
<string name="permdesc_accessCallAudio" msgid="8448360894684277823">"ഡിഫോൾട്ട് ഡയലർ ആപ്പായി അസെെൻ ചെയ്യുന്ന സമയത്ത്, ടെലിഫോൺ കോളുകൾ ചെയ്യുമ്പോൾ റെക്കോർഡ് ചെയ്യാൻ അല്ലെങ്കിൽ ഓഡിയോ പ്ലേ ചെയ്യാൻ ഈ ആപ്പിനെ അനുവദിക്കുന്നു."</string>
</resources>
diff --git a/core/res/res/values-mn/strings.xml b/core/res/res/values-mn/strings.xml
index b61474de264c..4054a3abf108 100644
--- a/core/res/res/values-mn/strings.xml
+++ b/core/res/res/values-mn/strings.xml
@@ -249,10 +249,8 @@
<item quantity="other">Алдааны тайлангийн дэлгэцийн зургийг <xliff:g id="NUMBER_1">%d</xliff:g> секундад авна.</item>
<item quantity="one">Алдааны тайлангийн дэлгэцийн зургийг <xliff:g id="NUMBER_0">%d</xliff:g> секундад авна.</item>
</plurals>
- <!-- no translation found for bugreport_screenshot_success_toast (7986095104151473745) -->
- <skip />
- <!-- no translation found for bugreport_screenshot_failure_toast (6736320861311294294) -->
- <skip />
+ <string name="bugreport_screenshot_success_toast" msgid="7986095104151473745">"Алдааны мэдээтэй дэлгэцийн зургийг дарлаа"</string>
+ <string name="bugreport_screenshot_failure_toast" msgid="6736320861311294294">"Алдааны мэдээтэй дэлгэцийн зургийг дарж чадсангүй"</string>
<string name="global_action_toggle_silent_mode" msgid="8464352592860372188">"Дуугүй горим"</string>
<string name="global_action_silent_mode_on_status" msgid="2371892537738632013">"Дуу хаагдсан"</string>
<string name="global_action_silent_mode_off_status" msgid="6608006545950920042">"Дуу асав"</string>
@@ -454,9 +452,11 @@
<string name="permdesc_acceptHandovers" msgid="7129026180128626870">"Аппад өөр аппад эхлүүлсэн дуудлагыг үргэлжлүүлэхийг зөвшөөрдөг."</string>
<string name="permlab_readPhoneNumbers" msgid="5668704794723365628">"утасны дугаарыг унших"</string>
<string name="permdesc_readPhoneNumbers" msgid="7368652482818338871">"Төхөөрөмжийн утасны дугаарт хандах зөвшөөрлийг апп-д олгоно."</string>
+ <string name="permlab_wakeLock" product="automotive" msgid="1904736682319375676">"машины дэлгэцийг асаалттай байлгах"</string>
<string name="permlab_wakeLock" product="tablet" msgid="1527660973931694000">"таблетыг унтуулахгүй байлгах"</string>
<string name="permlab_wakeLock" product="tv" msgid="2856941418123343518">"таны Android TВ төхөөрөмжийг идэвхгүй болохоос сэргийлэх"</string>
<string name="permlab_wakeLock" product="default" msgid="569409726861695115">"утсыг унтуулахгүй байлгах"</string>
+ <string name="permdesc_wakeLock" product="automotive" msgid="5995045369683254571">"Аппад машины дэлгэцийг асаалттай байлгахыг зөвшөөрдөг."</string>
<string name="permdesc_wakeLock" product="tablet" msgid="2441742939101526277">"Апп нь таблетыг унтахаас сэргийлэх боломжтой"</string>
<string name="permdesc_wakeLock" product="tv" msgid="2329298966735118796">"Аппад таны Android ТВ төхөөрөмжийг идэвхгүй болохоос сэргийлэхийг зөвшөөрнө."</string>
<string name="permdesc_wakeLock" product="default" msgid="3689523792074007163">"Апп нь утсыг унтахаас сэргийлэх боломжтой"</string>
@@ -1631,6 +1631,9 @@
<string name="safe_media_volume_warning" product="default" msgid="3751676824423049994">"Дууг санал болгосноос чанга болгож өсгөх үү?\n\nУрт хугацаанд чанга хөгжим сонсох нь таны сонсголыг муутгаж болно."</string>
<string name="accessibility_shortcut_warning_dialog_title" msgid="4017995837692622933">"Хүртээмжийн товчлолыг ашиглах уу?"</string>
<string name="accessibility_shortcut_toogle_warning" msgid="4161716521310929544">"Товчлол асаалттай үед дууны түвшний хоёр товчлуурыг хамтад нь 3 секунд дарснаар хандалтын онцлогийг эхлүүлнэ."</string>
+ <string name="accessibility_select_shortcut_menu_title" msgid="7310194076629867377">"Ашиглахыг хүсэж буй хандалтын аппаа товших"</string>
+ <string name="accessibility_edit_shortcut_menu_button_title" msgid="6096484087245145325">"Хандалтын товчлуурын тусламжтай ашиглахыг хүсэж буй аппуудаа сонгох"</string>
+ <string name="accessibility_edit_shortcut_menu_volume_title" msgid="4849108668454490699">"Дууны түвшин тохируулах түлхүүрийн товчлолын тусламжтай ашиглахыг хүсэж буй аппуудаа сонгох"</string>
<string name="edit_accessibility_shortcut_menu_button" msgid="8885752738733772935">"Товчлолуудыг засах"</string>
<string name="cancel_accessibility_shortcut_menu_button" msgid="1817413122335452474">"Болих"</string>
<string name="disable_accessibility_shortcut" msgid="5806091378745232383">"Товчлолыг унтраах"</string>
@@ -1853,8 +1856,7 @@
<string name="default_notification_channel_label" msgid="3697928973567217330">"Ангилаагүй"</string>
<string name="importance_from_user" msgid="2782756722448800447">"Та эдгээр мэдэгдлийн ач холбогдлыг тогтоосон."</string>
<string name="importance_from_person" msgid="4235804979664465383">"Оролцсон хүмүүсээс шалтгаалан энэ нь өндөр ач холбогдолтой."</string>
- <!-- no translation found for notification_history_title_placeholder (7748630986182249599) -->
- <skip />
+ <string name="notification_history_title_placeholder" msgid="7748630986182249599">"Аппын захиалгат мэдэгдэл"</string>
<string name="user_creation_account_exists" msgid="2239146360099708035">"<xliff:g id="APP">%1$s</xliff:g>-д <xliff:g id="ACCOUNT">%2$s</xliff:g>-тай (ийм бүртгэлтэй хэрэглэгч аль хэдийн байна) шинэ хэрэглэгч үүсгэхийг зөвшөөрөх үү ?"</string>
<string name="user_creation_adding" msgid="7305185499667958364">"<xliff:g id="APP">%1$s</xliff:g>-д <xliff:g id="ACCOUNT">%2$s</xliff:g>-тай шинэ хэрэглэгч үүсгэхийг зөвшөөрөх үү?"</string>
<string name="language_selection_title" msgid="52674936078683285">"Хэл нэмэх"</string>
@@ -2028,14 +2030,19 @@
<string name="as_app_forced_to_restricted_bucket" msgid="8233871289353898964">"<xliff:g id="PACKAGE_NAME">%1$s</xliff:g>-г ХЯЗГААРЛАСАН сагс руу орууллаа"</string>
<string name="resolver_personal_tab" msgid="2051260504014442073">"Хувийн"</string>
<string name="resolver_work_tab" msgid="2690019516263167035">"Ажил"</string>
+ <string name="resolver_personal_tab_accessibility" msgid="5739524949153091224">"Хувийн харагдах байдал"</string>
+ <string name="resolver_work_tab_accessibility" msgid="4753168230363802734">"Ажлын харагдах байдал"</string>
<string name="resolver_cant_share_with_work_apps" msgid="7539495559434146897">"Ажлын аппуудтай хуваалцах боломжгүй"</string>
<string name="resolver_cant_share_with_personal_apps" msgid="8020581735267157241">"Хувийн аппуудтай хуваалцах боломжгүй"</string>
- <string name="resolver_cant_share_cross_profile_explanation" msgid="3536237105241882679">"Танай IT админ хувийн болон ажлын аппуудын хооронд хуваалцахыг блоклосон."</string>
- <string name="resolver_turn_on_work_apps" msgid="8987359079870455469">"Ажлын аппуудыг асаана уу"</string>
- <string name="resolver_turn_on_work_apps_explanation" msgid="6322467455509618928">"Ажлын апп, харилцагчдад хандахын тулд ажлын аппыг асаана уу"</string>
+ <string name="resolver_cant_share_cross_profile_explanation" msgid="5556640604460901386">"Таны IT админ хувийн болон ажлын профайлуудын хооронд хуваалцахыг блоклосон"</string>
+ <string name="resolver_cant_access_work_apps" msgid="375634344111233790">"Ажлын аппуудад хандах боломжгүй байна"</string>
+ <string name="resolver_cant_access_work_apps_explanation" msgid="3958762224516867388">"Таны IT админ ажлын аппууд дахь хувийн контентыг харахыг танд зөвшөөрөхгүй байна"</string>
+ <string name="resolver_cant_access_personal_apps" msgid="1953215925406474177">"Хувийн аппуудад хандах боломжгүй байна"</string>
+ <string name="resolver_cant_access_personal_apps_explanation" msgid="1725572276741281136">"Таны IT админ хувийн аппууд дахь ажлын контентыг харахыг танд зөвшөөрөхгүй байна"</string>
+ <string name="resolver_turn_on_work_apps_share" msgid="619263911204978175">"Контентыг хуваалцахын тулд ажлын профайлыг асаана уу"</string>
+ <string name="resolver_turn_on_work_apps_view" msgid="3073389230905543680">"Контентыг харахын тулд ажлын профайлыг асаана уу"</string>
<string name="resolver_no_apps_available" msgid="7710339903040989654">"Боломжтой апп алга байна"</string>
- <string name="resolver_no_apps_available_explanation" msgid="4662694431121196560">"Бид ямар ч апп олж чадсангүй"</string>
- <string name="resolver_switch_on_work" msgid="8294542702883688533">"Ажил дээр сэлгэх"</string>
+ <string name="resolver_switch_on_work" msgid="2873009160846966379">"Асаах"</string>
<string name="permlab_accessCallAudio" msgid="1682957511874097664">"Утасны дуудлагын үеэр аудио бичих эсвэл тоглуулах"</string>
<string name="permdesc_accessCallAudio" msgid="8448360894684277823">"Энэ аппыг залгагч өгөгдмөл аппликэйшн болгосон үед түүнд утасны дуудлагын үеэр аудио бичих эсвэл тоглуулахыг зөвшөөрдөг."</string>
</resources>
diff --git a/core/res/res/values-mr/strings.xml b/core/res/res/values-mr/strings.xml
index d3c31a5839f1..94b779b54445 100644
--- a/core/res/res/values-mr/strings.xml
+++ b/core/res/res/values-mr/strings.xml
@@ -193,14 +193,10 @@
<string name="network_logging_notification_text" msgid="1327373071132562512">"तुमची संस्था हे डिव्हाइस व्यवस्थापित करते आणि नेटवर्क रहदारीचे निरीक्षण करू शकते. तपशीलांसाठी टॅप करा."</string>
<string name="location_changed_notification_title" msgid="4119726617105166830">"तुमच्या ॲडमिनने स्थान सेटिंग्ज बदलल्या आहेत"</string>
<string name="location_changed_notification_text" msgid="198907268219396399">"तुमची स्थान सेटिंग्ज पाहण्यासाठी टॅप करा."</string>
- <!-- no translation found for country_detector (7023275114706088854) -->
- <skip />
- <!-- no translation found for location_service (2439187616018455546) -->
- <skip />
- <!-- no translation found for sensor_notification_service (7474531979178682676) -->
- <skip />
- <!-- no translation found for twilight_service (8964898045693187224) -->
- <skip />
+ <string name="country_detector" msgid="7023275114706088854">"कंट्री डिटेक्टर"</string>
+ <string name="location_service" msgid="2439187616018455546">"स्थान सेवा"</string>
+ <string name="sensor_notification_service" msgid="7474531979178682676">"सेंसर सूचना सेवा"</string>
+ <string name="twilight_service" msgid="8964898045693187224">"ट्वायलाइट सेवा"</string>
<string name="factory_reset_warning" msgid="6858705527798047809">"तुमचे डिव्हाइस मिटविले जाईल"</string>
<string name="factory_reset_message" msgid="2657049595153992213">"प्रशासक अ‍ॅप वापरता येणार नाही. तुमचे डिव्हाइस आता साफ केले जाईल.\n\nतुम्हाला कुठलेही प्रश्न असल्यास, तुमच्या संस्थेच्या प्रशासकाशी संपर्क साधा."</string>
<string name="printing_disabled_by" msgid="3517499806528864633">"<xliff:g id="OWNER_APP">%s</xliff:g> नी प्रिंट करणे बंद केले आहे."</string>
@@ -253,10 +249,8 @@
<item quantity="other">दोष अहवालासाठी <xliff:g id="NUMBER_1">%d</xliff:g> सेकंदांमध्‍ये स्क्रीनशॉट घेत आहे.</item>
<item quantity="one">दोष अहवालासाठी <xliff:g id="NUMBER_0">%d</xliff:g> सेकंदामध्‍ये स्क्रीनशॉट घेत आहे.</item>
</plurals>
- <!-- no translation found for bugreport_screenshot_success_toast (7986095104151473745) -->
- <skip />
- <!-- no translation found for bugreport_screenshot_failure_toast (6736320861311294294) -->
- <skip />
+ <string name="bugreport_screenshot_success_toast" msgid="7986095104151473745">"बग रिपोर्टसह घेतलेला स्क्रीनशॉट"</string>
+ <string name="bugreport_screenshot_failure_toast" msgid="6736320861311294294">"बग रिपोर्टसह स्क्रीनशॉट घेता आला नाही"</string>
<string name="global_action_toggle_silent_mode" msgid="8464352592860372188">"मूक मोड"</string>
<string name="global_action_silent_mode_on_status" msgid="2371892537738632013">"ध्वनी बंद आहे"</string>
<string name="global_action_silent_mode_off_status" msgid="6608006545950920042">"ध्वनी चालू आहे"</string>
@@ -458,9 +452,11 @@
<string name="permdesc_acceptHandovers" msgid="7129026180128626870">"दुसऱ्या ॲपमध्ये सुरू झालेल्या कॉलला पुढे सुरू ठेवण्याची ॲपला अनुमती देते."</string>
<string name="permlab_readPhoneNumbers" msgid="5668704794723365628">"फोन नंबर वाचा"</string>
<string name="permdesc_readPhoneNumbers" msgid="7368652482818338871">"ॲपला डिव्हाइसच्या फोन नंबरमध्ये प्रवेश करण्याची अनुमती देते."</string>
+ <string name="permlab_wakeLock" product="automotive" msgid="1904736682319375676">"कारची स्क्रीन सुरू ठेवा"</string>
<string name="permlab_wakeLock" product="tablet" msgid="1527660973931694000">"टॅबलेट निष्क्रिय होण्यापासून प्रतिबंधित करा"</string>
<string name="permlab_wakeLock" product="tv" msgid="2856941418123343518">"तुमच्या Android TV डिव्हाइसला स्लीप मोडमध्ये जाण्यापासून थांबवा"</string>
<string name="permlab_wakeLock" product="default" msgid="569409726861695115">"फोन निष्‍क्रिय होण्‍यापासून प्रतिबंधित करा"</string>
+ <string name="permdesc_wakeLock" product="automotive" msgid="5995045369683254571">"ॲपला कारची स्क्रीन सुरू ठेवण्याची अनुमती देते."</string>
<string name="permdesc_wakeLock" product="tablet" msgid="2441742939101526277">"टॅब्लेटला निष्क्रिय होण्यापासून प्रतिबंधित करण्यासाठी अ‍ॅप ला अनुमती देते."</string>
<string name="permdesc_wakeLock" product="tv" msgid="2329298966735118796">"Android TV डिव्हाइसला स्लीप मोडमध्ये जाण्यापासून प्रतिबंधित करण्यासाठी ॲपला अनुमती देते."</string>
<string name="permdesc_wakeLock" product="default" msgid="3689523792074007163">"फोनला निष्क्रिय होण्यापासून प्रतिबंधित करण्यासाठी अ‍ॅप ला अनुमती देते."</string>
@@ -1635,6 +1631,12 @@
<string name="safe_media_volume_warning" product="default" msgid="3751676824423049994">"शिफारस केलेल्‍या पातळीच्या वर आवाज वाढवायचा?\n\nउच्च आवाजात दीर्घ काळ ऐकण्‍याने आपल्‍या श्रवणशक्तीची हानी होऊ शकते."</string>
<string name="accessibility_shortcut_warning_dialog_title" msgid="4017995837692622933">"प्रवेशयोग्यता शॉर्टकट वापरायचा?"</string>
<string name="accessibility_shortcut_toogle_warning" msgid="4161716521310929544">"शॉर्टकट सुरू असताना, दोन्ही व्‍हॉल्‍यूम बटणे तीन सेकंदांसाठी दाबून ठेवल्याने अ‍ॅक्सेसिबिलिटी वैशिष्ट्य सुरू होईल."</string>
+ <!-- no translation found for accessibility_select_shortcut_menu_title (7310194076629867377) -->
+ <skip />
+ <!-- no translation found for accessibility_edit_shortcut_menu_button_title (6096484087245145325) -->
+ <skip />
+ <!-- no translation found for accessibility_edit_shortcut_menu_volume_title (4849108668454490699) -->
+ <skip />
<string name="edit_accessibility_shortcut_menu_button" msgid="8885752738733772935">"शॉर्टकट संपादित करा"</string>
<string name="cancel_accessibility_shortcut_menu_button" msgid="1817413122335452474">"रद्द करा"</string>
<string name="disable_accessibility_shortcut" msgid="5806091378745232383">"शॉर्टकट बंद करा"</string>
@@ -2032,14 +2034,29 @@
<string name="as_app_forced_to_restricted_bucket" msgid="8233871289353898964">"<xliff:g id="PACKAGE_NAME">%1$s</xliff:g> हे प्रतिबंधित बादलीमध्ये ठेवण्यात आले आहे"</string>
<string name="resolver_personal_tab" msgid="2051260504014442073">"वैयक्तिक"</string>
<string name="resolver_work_tab" msgid="2690019516263167035">"ऑफिस"</string>
+ <!-- no translation found for resolver_personal_tab_accessibility (5739524949153091224) -->
+ <skip />
+ <!-- no translation found for resolver_work_tab_accessibility (4753168230363802734) -->
+ <skip />
<string name="resolver_cant_share_with_work_apps" msgid="7539495559434146897">"ऑफिस ॲप्स सोबत शेअर करू शकत नाही"</string>
<string name="resolver_cant_share_with_personal_apps" msgid="8020581735267157241">"वैयक्तिक अ‍ॅप्स सोबत शेअर करू शकत नाही"</string>
- <string name="resolver_cant_share_cross_profile_explanation" msgid="3536237105241882679">"तुमच्या आयटी ॲडमिनने वैयक्तिक आणि ऑफिस ॲप्स दरम्यान शेअर करणे ब्लॉक केले आहे"</string>
- <string name="resolver_turn_on_work_apps" msgid="8987359079870455469">"ऑफिस अ‍ॅप्स सुरू करा"</string>
- <string name="resolver_turn_on_work_apps_explanation" msgid="6322467455509618928">"ऑफिस ॲप्स &amp; संपर्क अ‍ॅक्सेस करण्यासाठी ऑफिस ॲप्स सुरू करा"</string>
+ <!-- no translation found for resolver_cant_share_cross_profile_explanation (5556640604460901386) -->
+ <skip />
+ <!-- no translation found for resolver_cant_access_work_apps (375634344111233790) -->
+ <skip />
+ <!-- no translation found for resolver_cant_access_work_apps_explanation (3958762224516867388) -->
+ <skip />
+ <!-- no translation found for resolver_cant_access_personal_apps (1953215925406474177) -->
+ <skip />
+ <!-- no translation found for resolver_cant_access_personal_apps_explanation (1725572276741281136) -->
+ <skip />
+ <!-- no translation found for resolver_turn_on_work_apps_share (619263911204978175) -->
+ <skip />
+ <!-- no translation found for resolver_turn_on_work_apps_view (3073389230905543680) -->
+ <skip />
<string name="resolver_no_apps_available" msgid="7710339903040989654">"कोणतीही अ‍ॅप्स उपलब्ध नाहीत"</string>
- <string name="resolver_no_apps_available_explanation" msgid="4662694431121196560">"आम्हाला कोणतीही अ‍ॅप्स सापडली नाहीत"</string>
- <string name="resolver_switch_on_work" msgid="8294542702883688533">"ऑफिस प्रोफाइलवर स्विच करा"</string>
+ <!-- no translation found for resolver_switch_on_work (2873009160846966379) -->
+ <skip />
<string name="permlab_accessCallAudio" msgid="1682957511874097664">"टेलिफोनी कॉलमध्ये ऑडिओ रेकॉर्ड करा किंवा प्ले करा"</string>
<string name="permdesc_accessCallAudio" msgid="8448360894684277823">"टेलिफोनी कॉलमध्ये ऑडिओ रेकॉर्ड करण्याची किंवा प्ले करण्यासाठी डीफॉल्ट डायलर अ‍ॅप्लिकेशन म्हणून असाइन केले असताना या ॲपला परवानगी देते."</string>
</resources>
diff --git a/core/res/res/values-ms/strings.xml b/core/res/res/values-ms/strings.xml
index 909fcc9ed473..23606c00eeca 100644
--- a/core/res/res/values-ms/strings.xml
+++ b/core/res/res/values-ms/strings.xml
@@ -249,10 +249,8 @@
<item quantity="other">Mengambil tangkapan skrin untuk laporan pepijat dalam masa <xliff:g id="NUMBER_1">%d</xliff:g> saat.</item>
<item quantity="one">Mengambil tangkapan skrin untuk laporan pepijat dalam masa <xliff:g id="NUMBER_0">%d</xliff:g> saat.</item>
</plurals>
- <!-- no translation found for bugreport_screenshot_success_toast (7986095104151473745) -->
- <skip />
- <!-- no translation found for bugreport_screenshot_failure_toast (6736320861311294294) -->
- <skip />
+ <string name="bugreport_screenshot_success_toast" msgid="7986095104151473745">"Tangkapan skrin diambil dengan laporan pepijat"</string>
+ <string name="bugreport_screenshot_failure_toast" msgid="6736320861311294294">"Gagal mengambil tangkapan skrin dengan laporan pepijat"</string>
<string name="global_action_toggle_silent_mode" msgid="8464352592860372188">"Mod senyap"</string>
<string name="global_action_silent_mode_on_status" msgid="2371892537738632013">"Bunyi DIMATIKAN"</string>
<string name="global_action_silent_mode_off_status" msgid="6608006545950920042">"Bunyi DIHIDUPKAN"</string>
@@ -454,9 +452,11 @@
<string name="permdesc_acceptHandovers" msgid="7129026180128626870">"Membenarkan apl meneruskan panggilan yang dimulakan dalam apl lain."</string>
<string name="permlab_readPhoneNumbers" msgid="5668704794723365628">"baca nombor telefon"</string>
<string name="permdesc_readPhoneNumbers" msgid="7368652482818338871">"Membenarkan apl mengakses nombor telefon peranti."</string>
+ <string name="permlab_wakeLock" product="automotive" msgid="1904736682319375676">"pastikan skrin kereta sentiasa hidup"</string>
<string name="permlab_wakeLock" product="tablet" msgid="1527660973931694000">"menghalang tablet daripada tidur"</string>
<string name="permlab_wakeLock" product="tv" msgid="2856941418123343518">"menghalang peranti Android TV anda daripada tidur"</string>
<string name="permlab_wakeLock" product="default" msgid="569409726861695115">"halang telefon daripada tidur"</string>
+ <string name="permdesc_wakeLock" product="automotive" msgid="5995045369683254571">"Membenarkan apl memastikan skrin kereta sentiasa hidup."</string>
<string name="permdesc_wakeLock" product="tablet" msgid="2441742939101526277">"Membenarkan apl menghalang tablet daripada tidur."</string>
<string name="permdesc_wakeLock" product="tv" msgid="2329298966735118796">"Membenarkan apl menghalang peranti Android TV anda daripada tidur."</string>
<string name="permdesc_wakeLock" product="default" msgid="3689523792074007163">"Membenarkan apl menghalang telefon daripada tidur."</string>
@@ -1631,6 +1631,12 @@
<string name="safe_media_volume_warning" product="default" msgid="3751676824423049994">"Naikkan kelantangan melebihi paras yang disyokorkan?\n\nMendengar pada kelantangan yang tinggi untuk tempoh yang lama boleh merosakkan pendengaran anda."</string>
<string name="accessibility_shortcut_warning_dialog_title" msgid="4017995837692622933">"Gunakan Pintasan Kebolehaksesan?"</string>
<string name="accessibility_shortcut_toogle_warning" msgid="4161716521310929544">"Apabila pintasan dihidupkan, tindakan menekan kedua-dua butang kelantangan selama 3 saat akan memulakan ciri kebolehaksesan."</string>
+ <!-- no translation found for accessibility_select_shortcut_menu_title (7310194076629867377) -->
+ <skip />
+ <!-- no translation found for accessibility_edit_shortcut_menu_button_title (6096484087245145325) -->
+ <skip />
+ <!-- no translation found for accessibility_edit_shortcut_menu_volume_title (4849108668454490699) -->
+ <skip />
<string name="edit_accessibility_shortcut_menu_button" msgid="8885752738733772935">"Edit pintasan"</string>
<string name="cancel_accessibility_shortcut_menu_button" msgid="1817413122335452474">"Batal"</string>
<string name="disable_accessibility_shortcut" msgid="5806091378745232383">"Matikan pintasan"</string>
@@ -1853,8 +1859,7 @@
<string name="default_notification_channel_label" msgid="3697928973567217330">"Tidak dikategorikan"</string>
<string name="importance_from_user" msgid="2782756722448800447">"Anda menetapkan kepentingan pemberitahuan ini."</string>
<string name="importance_from_person" msgid="4235804979664465383">"Mesej ini penting disebabkan orang yang terlibat."</string>
- <!-- no translation found for notification_history_title_placeholder (7748630986182249599) -->
- <skip />
+ <string name="notification_history_title_placeholder" msgid="7748630986182249599">"Pemberitahuan apl tersuai"</string>
<string name="user_creation_account_exists" msgid="2239146360099708035">"Benarkan <xliff:g id="APP">%1$s</xliff:g> membuat Pengguna baharu dengan <xliff:g id="ACCOUNT">%2$s</xliff:g> (Pengguna dengan akaun ini sudah wujud) ?"</string>
<string name="user_creation_adding" msgid="7305185499667958364">"Benarkan <xliff:g id="APP">%1$s</xliff:g> membuat Pengguna baharu dengan <xliff:g id="ACCOUNT">%2$s</xliff:g>?"</string>
<string name="language_selection_title" msgid="52674936078683285">"Tambahkan bahasa"</string>
@@ -2028,14 +2033,29 @@
<string name="as_app_forced_to_restricted_bucket" msgid="8233871289353898964">"<xliff:g id="PACKAGE_NAME">%1$s</xliff:g> telah diletakkan dalam baldi TERHAD"</string>
<string name="resolver_personal_tab" msgid="2051260504014442073">"Peribadi"</string>
<string name="resolver_work_tab" msgid="2690019516263167035">"Kerja"</string>
+ <!-- no translation found for resolver_personal_tab_accessibility (5739524949153091224) -->
+ <skip />
+ <!-- no translation found for resolver_work_tab_accessibility (4753168230363802734) -->
+ <skip />
<string name="resolver_cant_share_with_work_apps" msgid="7539495559434146897">"Tidak dapat berkongsi dengan apl kerja"</string>
<string name="resolver_cant_share_with_personal_apps" msgid="8020581735267157241">"Tidak dapat berkongsi dengan apl peribadi"</string>
- <string name="resolver_cant_share_cross_profile_explanation" msgid="3536237105241882679">"Pentadbir IT anda menyekat perkongsian antara apl peribadi dan kerja"</string>
- <string name="resolver_turn_on_work_apps" msgid="8987359079870455469">"Hidupkan apl kerja"</string>
- <string name="resolver_turn_on_work_apps_explanation" msgid="6322467455509618928">"Hidupkan apl kerja untuk mengakses apl &amp; kenalan kerja"</string>
+ <!-- no translation found for resolver_cant_share_cross_profile_explanation (5556640604460901386) -->
+ <skip />
+ <!-- no translation found for resolver_cant_access_work_apps (375634344111233790) -->
+ <skip />
+ <!-- no translation found for resolver_cant_access_work_apps_explanation (3958762224516867388) -->
+ <skip />
+ <!-- no translation found for resolver_cant_access_personal_apps (1953215925406474177) -->
+ <skip />
+ <!-- no translation found for resolver_cant_access_personal_apps_explanation (1725572276741281136) -->
+ <skip />
+ <!-- no translation found for resolver_turn_on_work_apps_share (619263911204978175) -->
+ <skip />
+ <!-- no translation found for resolver_turn_on_work_apps_view (3073389230905543680) -->
+ <skip />
<string name="resolver_no_apps_available" msgid="7710339903040989654">"Tiada rangkaian yang tersedia"</string>
- <string name="resolver_no_apps_available_explanation" msgid="4662694431121196560">"Kami tidak menemukan sebarang apl"</string>
- <string name="resolver_switch_on_work" msgid="8294542702883688533">"Hidupkan kerja"</string>
+ <!-- no translation found for resolver_switch_on_work (2873009160846966379) -->
+ <skip />
<string name="permlab_accessCallAudio" msgid="1682957511874097664">"Rakam atau mainkan audio dalam panggilan telefoni"</string>
<string name="permdesc_accessCallAudio" msgid="8448360894684277823">"Apabila ditetapkan sebagai apl pendail lalai, membenarkan apl ini merakam atau memainkan audio dalam panggilan telefoni."</string>
</resources>
diff --git a/core/res/res/values-my/strings.xml b/core/res/res/values-my/strings.xml
index 9a902c8db193..05dadf08d57b 100644
--- a/core/res/res/values-my/strings.xml
+++ b/core/res/res/values-my/strings.xml
@@ -249,10 +249,8 @@
<item quantity="other"><xliff:g id="NUMBER_1">%d</xliff:g> စက္ကန့်အတွင်း ချွတ်ယွင်းချက် အစီရင်ခံရန်အတွက် မျက်နှာပြင်ဓာတ်ပုံ ရိုက်ပါမည်။</item>
<item quantity="one"><xliff:g id="NUMBER_0">%d</xliff:g> စက္ကန့်အတွင်း ချွတ်ယွင်းချက် အစီရင်ခံရန်အတွက် မျက်နှာပြင်ဓာတ်ပုံ ရိုက်ပါမည်။</item>
</plurals>
- <!-- no translation found for bugreport_screenshot_success_toast (7986095104151473745) -->
- <skip />
- <!-- no translation found for bugreport_screenshot_failure_toast (6736320861311294294) -->
- <skip />
+ <string name="bugreport_screenshot_success_toast" msgid="7986095104151473745">"ချွတ်ယွင်းချက်အစီရင်ခံချက်နှင့်အတူ ဖန်သားပြင်ဓာတ်ပုံရိုက်ထားသည်"</string>
+ <string name="bugreport_screenshot_failure_toast" msgid="6736320861311294294">"ချွတ်ယွင်းချက်အစီရင်ခံချက်နှင့်အတူ ဖန်သားပြင်ဓာတ်ပုံရိုက်၍မရခဲ့ပါ"</string>
<string name="global_action_toggle_silent_mode" msgid="8464352592860372188">"အသံတိတ်စနစ်"</string>
<string name="global_action_silent_mode_on_status" msgid="2371892537738632013">"အသံပိတ်ထားသည်"</string>
<string name="global_action_silent_mode_off_status" msgid="6608006545950920042">"အသံဖွင့်ထားသည်"</string>
@@ -454,9 +452,11 @@
<string name="permdesc_acceptHandovers" msgid="7129026180128626870">"အခြားအက်ပ်တွင် စတင်ထားသည့် ဖုန်းခေါ်ဆိုမှုကို ဆက်လက်ပြုလုပ်ရန် ဤအက်ပ်ကို ခွင့်ပြုသည်။"</string>
<string name="permlab_readPhoneNumbers" msgid="5668704794723365628">"ဖုန်းနံပါတ်များကို ဖတ်ရန်"</string>
<string name="permdesc_readPhoneNumbers" msgid="7368652482818338871">"အက်ပ်ကို စက်ပစ္စည်း၏ ဖုန်းနံပါတ်များအား အသုံးပြုခွင့်ပေးပါ။"</string>
+ <string name="permlab_wakeLock" product="automotive" msgid="1904736682319375676">"ကားဖန်သားပြင်ကို ဖွင့်ထားပါ"</string>
<string name="permlab_wakeLock" product="tablet" msgid="1527660973931694000">"တက်ပလက်အား ပိတ်ခြင်းမှ ကာကွယ်ခြင်း"</string>
<string name="permlab_wakeLock" product="tv" msgid="2856941418123343518">"သင်၏ Android TV စက်ပစ္စည်း နားခြင်းမရှိစေရန် ပြုလုပ်ခြင်း"</string>
<string name="permlab_wakeLock" product="default" msgid="569409726861695115">"ဖုန်းအနားယူခြင်းမပြုလုပ်စေရန်"</string>
+ <string name="permdesc_wakeLock" product="automotive" msgid="5995045369683254571">"ကားဖန်သားပြင် ဖွင့်ထားနိုင်စေရန် အက်ပ်ကို ခွင့်ပြုပေးပါ။"</string>
<string name="permdesc_wakeLock" product="tablet" msgid="2441742939101526277">"အက်ပ်အား တက်ဘလက်ကို အနားမယူနိုင်အောင် ဟန့်တားခွင့် ပြုသည်။"</string>
<string name="permdesc_wakeLock" product="tv" msgid="2329298966735118796">"သင့် Android TV စက်ပစ္စည်း နားခြင်း မရှိစေရန်အတွက် အက်ပ်အား လုပ်ဆောင်ခွင့်ပြုသည်။"</string>
<string name="permdesc_wakeLock" product="default" msgid="3689523792074007163">"အက်ပ်အား ဖုန်းကို အနားမယူနိုင်အောင် ဟန့်တားခွင့် ပြုသည်။"</string>
@@ -1631,6 +1631,12 @@
<string name="safe_media_volume_warning" product="default" msgid="3751676824423049994">"အသံကို အကြံပြုထားသည့် ပမာဏထက် မြှင့်ပေးရမလား?\n\nအသံကို မြင့်သည့် အဆင့်မှာ ကြာရှည်စွာ နားထောင်ခြင်းက သင်၏ နားကို ထိခိုက်စေနိုင်သည်။"</string>
<string name="accessibility_shortcut_warning_dialog_title" msgid="4017995837692622933">"အများသုံးစွဲနိုင်မှု ဖြတ်လမ်းလင့်ခ်ကို အသုံးပြုလိုပါသလား။"</string>
<string name="accessibility_shortcut_toogle_warning" msgid="4161716521310929544">"ဖြတ်လမ်းလင့်ခ်ကို ဖွင့်ထားစဉ် အသံထိန်းခလုတ် နှစ်ခုစလုံးကို ၃ စက္ကန့်ခန့် ဖိထားခြင်းဖြင့် အများသုံးစွဲနိုင်မှုဆိုင်ရာ ဝန်ဆောင်မှုကို ဖွင့်နိုင်သည်။"</string>
+ <!-- no translation found for accessibility_select_shortcut_menu_title (7310194076629867377) -->
+ <skip />
+ <!-- no translation found for accessibility_edit_shortcut_menu_button_title (6096484087245145325) -->
+ <skip />
+ <!-- no translation found for accessibility_edit_shortcut_menu_volume_title (4849108668454490699) -->
+ <skip />
<string name="edit_accessibility_shortcut_menu_button" msgid="8885752738733772935">"ဖြတ်လမ်းများကို တည်းဖြတ်ရန်"</string>
<string name="cancel_accessibility_shortcut_menu_button" msgid="1817413122335452474">"မလုပ်တော့"</string>
<string name="disable_accessibility_shortcut" msgid="5806091378745232383">"ဖြတ်လမ်းလင့်ခ်ကို ပိတ်ရန်"</string>
@@ -1853,8 +1859,7 @@
<string name="default_notification_channel_label" msgid="3697928973567217330">"အမျိုးအစားမခွဲရသေးပါ"</string>
<string name="importance_from_user" msgid="2782756722448800447">"ဤသတိပေးချက်များ၏ အရေးပါမှုကိုသတ်မှတ်ပြီးပါပြီ။"</string>
<string name="importance_from_person" msgid="4235804979664465383">"ပါဝင်သည့်လူများကြောင့် အရေးပါပါသည်။"</string>
- <!-- no translation found for notification_history_title_placeholder (7748630986182249599) -->
- <skip />
+ <string name="notification_history_title_placeholder" msgid="7748630986182249599">"စိတ်ကြိုက်အက်ပ် အကြောင်းကြားချက်"</string>
<string name="user_creation_account_exists" msgid="2239146360099708035">"<xliff:g id="ACCOUNT">%2$s</xliff:g> ဖြင့်အသုံးပြုသူအသစ်ကို <xliff:g id="APP">%1$s</xliff:g> အား ဖန်တီးခွင့်ပြုလိုပါသလား (ဤအကောင့်ဖြင့် အသုံးပြုသူ ရှိနှင့်ပြီးဖြစ်သည်) ။"</string>
<string name="user_creation_adding" msgid="7305185499667958364">"<xliff:g id="ACCOUNT">%2$s</xliff:g> ဖြင့်အသုံးပြုသူအသစ်ကို <xliff:g id="APP">%1$s</xliff:g> အား ဖန်တီးခွင့်ပြုလိုပါသလား ။"</string>
<string name="language_selection_title" msgid="52674936078683285">"ဘာသာစကားတစ်ခု ထည့်ပါ"</string>
@@ -2028,14 +2033,29 @@
<string name="as_app_forced_to_restricted_bucket" msgid="8233871289353898964">"<xliff:g id="PACKAGE_NAME">%1$s</xliff:g> ကို တားမြစ်ထားသော သိမ်းဆည်းမှုအတွင်းသို့ ထည့်ပြီးပါပြီ"</string>
<string name="resolver_personal_tab" msgid="2051260504014442073">"ကိုယ်ပိုင်"</string>
<string name="resolver_work_tab" msgid="2690019516263167035">"အလုပ်"</string>
+ <!-- no translation found for resolver_personal_tab_accessibility (5739524949153091224) -->
+ <skip />
+ <!-- no translation found for resolver_work_tab_accessibility (4753168230363802734) -->
+ <skip />
<string name="resolver_cant_share_with_work_apps" msgid="7539495559434146897">"အလုပ်သုံးအက်ပ်များနှင့် မျှဝေ၍ မရပါ"</string>
<string name="resolver_cant_share_with_personal_apps" msgid="8020581735267157241">"ကိုယ်ပိုင်သုံးအက်ပ်များနှင့် မျှဝေ၍ မရပါ"</string>
- <string name="resolver_cant_share_cross_profile_explanation" msgid="3536237105241882679">"သင့်အိုင်တီ စီမံခန့်ခွဲသူက ကိုယ်ပိုင်သုံးနှင့် အလုပ်သုံးအက်ပ်များအကြား မျှဝေခြင်းကို ပိတ်ထားသည်"</string>
- <string name="resolver_turn_on_work_apps" msgid="8987359079870455469">"အလုပ်သုံးအက်ပ်များကို ဖွင့်ပါ"</string>
- <string name="resolver_turn_on_work_apps_explanation" msgid="6322467455509618928">"အလုပ်သုံးအက်ပ်နှင့် အဆက်အသွယ်များကို သုံးရန် အလုပ်သုံးအက်ပ်များကို ဖွင့်ပါ"</string>
+ <!-- no translation found for resolver_cant_share_cross_profile_explanation (5556640604460901386) -->
+ <skip />
+ <!-- no translation found for resolver_cant_access_work_apps (375634344111233790) -->
+ <skip />
+ <!-- no translation found for resolver_cant_access_work_apps_explanation (3958762224516867388) -->
+ <skip />
+ <!-- no translation found for resolver_cant_access_personal_apps (1953215925406474177) -->
+ <skip />
+ <!-- no translation found for resolver_cant_access_personal_apps_explanation (1725572276741281136) -->
+ <skip />
+ <!-- no translation found for resolver_turn_on_work_apps_share (619263911204978175) -->
+ <skip />
+ <!-- no translation found for resolver_turn_on_work_apps_view (3073389230905543680) -->
+ <skip />
<string name="resolver_no_apps_available" msgid="7710339903040989654">"မည်သည့်အက်ပ်မျှ မရှိပါ"</string>
- <string name="resolver_no_apps_available_explanation" msgid="4662694431121196560">"မည်သည့်အက်ပ်ကိုမျှ မတွေ့ပါ"</string>
- <string name="resolver_switch_on_work" msgid="8294542702883688533">"အလုပ်သုံးအနေအထားကို ဖွင့်ပါ"</string>
+ <!-- no translation found for resolver_switch_on_work (2873009160846966379) -->
+ <skip />
<string name="permlab_accessCallAudio" msgid="1682957511874097664">"ဖုန်းခေါ်ဆိုမှုများအတွင်း အသံဖမ်းခြင်း သို့မဟုတ် ဖွင့်ခြင်း"</string>
<string name="permdesc_accessCallAudio" msgid="8448360894684277823">"ဤအက်ပ်အား မူလ dialer အပလီကေးရှင်းအဖြစ် သတ်မှတ်ထားစဉ် ဖုန်းခေါ်ဆိုမှုများအတွင်း အသံဖမ်းခြင်း သို့မဟုတ် ဖွင့်ခြင်း ပြုလုပ်ရန် ခွင့်ပြုပါ။"</string>
</resources>
diff --git a/core/res/res/values-nb/strings.xml b/core/res/res/values-nb/strings.xml
index 93afcb204cf2..8848a3e98c64 100644
--- a/core/res/res/values-nb/strings.xml
+++ b/core/res/res/values-nb/strings.xml
@@ -249,10 +249,8 @@
<item quantity="other">Tar skjermdump for feilrapporten om <xliff:g id="NUMBER_1">%d</xliff:g> sekunder.</item>
<item quantity="one">Tar skjermdump for feilrapporten om <xliff:g id="NUMBER_0">%d</xliff:g> sekund.</item>
</plurals>
- <!-- no translation found for bugreport_screenshot_success_toast (7986095104151473745) -->
- <skip />
- <!-- no translation found for bugreport_screenshot_failure_toast (6736320861311294294) -->
- <skip />
+ <string name="bugreport_screenshot_success_toast" msgid="7986095104151473745">"En skjermdump er tatt med feilrapporten"</string>
+ <string name="bugreport_screenshot_failure_toast" msgid="6736320861311294294">"Kunne ikke ta skjermdump med feilrapporten"</string>
<string name="global_action_toggle_silent_mode" msgid="8464352592860372188">"Stillemodus"</string>
<string name="global_action_silent_mode_on_status" msgid="2371892537738632013">"Lyden er av"</string>
<string name="global_action_silent_mode_off_status" msgid="6608006545950920042">"Lyden er på"</string>
@@ -454,9 +452,11 @@
<string name="permdesc_acceptHandovers" msgid="7129026180128626870">"Lar appen fortsette et anrop som ble startet i en annen app."</string>
<string name="permlab_readPhoneNumbers" msgid="5668704794723365628">"les telefonnumre"</string>
<string name="permdesc_readPhoneNumbers" msgid="7368652482818338871">"Gir appen tilgang til telefonnumrene til enheten."</string>
+ <string name="permlab_wakeLock" product="automotive" msgid="1904736682319375676">"hold bilskjermen på"</string>
<string name="permlab_wakeLock" product="tablet" msgid="1527660973931694000">"hindre nettbrettet fra å gå over til sovemodus"</string>
<string name="permlab_wakeLock" product="tv" msgid="2856941418123343518">"forhindre at Android TV-enheten din settes i hvilemodus"</string>
<string name="permlab_wakeLock" product="default" msgid="569409726861695115">"forhindre telefonen fra å sove"</string>
+ <string name="permdesc_wakeLock" product="automotive" msgid="5995045369683254571">"Tillater at appen holder bilskjermen på."</string>
<string name="permdesc_wakeLock" product="tablet" msgid="2441742939101526277">"Lar appen hindre nettbrettet fra å gå over i sovemodus."</string>
<string name="permdesc_wakeLock" product="tv" msgid="2329298966735118796">"Lar appen hindre Android TV-enheten fra å settes i hvilemodus."</string>
<string name="permdesc_wakeLock" product="default" msgid="3689523792074007163">"Lar appen hindre telefonen fra å gå over i sovemodus."</string>
@@ -1631,6 +1631,12 @@
<string name="safe_media_volume_warning" product="default" msgid="3751676824423049994">"Vil du øke volumet til over anbefalt nivå?\n\nHvis du hører på et høyt volum over lengre perioder, kan det skade hørselen din."</string>
<string name="accessibility_shortcut_warning_dialog_title" msgid="4017995837692622933">"Vil du bruke tilgjengelighetssnarveien?"</string>
<string name="accessibility_shortcut_toogle_warning" msgid="4161716521310929544">"Når snarveien er på, starter en tilgjengelighetsfunksjon når du trykker inn begge volumknappene i tre sekunder."</string>
+ <!-- no translation found for accessibility_select_shortcut_menu_title (7310194076629867377) -->
+ <skip />
+ <!-- no translation found for accessibility_edit_shortcut_menu_button_title (6096484087245145325) -->
+ <skip />
+ <!-- no translation found for accessibility_edit_shortcut_menu_volume_title (4849108668454490699) -->
+ <skip />
<string name="edit_accessibility_shortcut_menu_button" msgid="8885752738733772935">"Endre snarveier"</string>
<string name="cancel_accessibility_shortcut_menu_button" msgid="1817413122335452474">"Avbryt"</string>
<string name="disable_accessibility_shortcut" msgid="5806091378745232383">"Slå av snarveien"</string>
@@ -1853,8 +1859,7 @@
<string name="default_notification_channel_label" msgid="3697928973567217330">"Uten kategori"</string>
<string name="importance_from_user" msgid="2782756722448800447">"Du angir viktigheten for disse varslene."</string>
<string name="importance_from_person" msgid="4235804979664465383">"Dette er viktig på grunn av folkene som er involvert."</string>
- <!-- no translation found for notification_history_title_placeholder (7748630986182249599) -->
- <skip />
+ <string name="notification_history_title_placeholder" msgid="7748630986182249599">"Tilpasset appvarsel"</string>
<string name="user_creation_account_exists" msgid="2239146360099708035">"Vil du la <xliff:g id="APP">%1$s</xliff:g> opprette en ny bruker med <xliff:g id="ACCOUNT">%2$s</xliff:g> (en bruker med denne kontoen eksisterer allerede)?"</string>
<string name="user_creation_adding" msgid="7305185499667958364">"Vil du la <xliff:g id="APP">%1$s</xliff:g> opprette en ny bruker med <xliff:g id="ACCOUNT">%2$s</xliff:g>?"</string>
<string name="language_selection_title" msgid="52674936078683285">"Legg til et språk"</string>
@@ -2028,14 +2033,29 @@
<string name="as_app_forced_to_restricted_bucket" msgid="8233871289353898964">"<xliff:g id="PACKAGE_NAME">%1$s</xliff:g> er blitt plassert i TILGANGSBEGRENSET-toppmappen"</string>
<string name="resolver_personal_tab" msgid="2051260504014442073">"Personlig"</string>
<string name="resolver_work_tab" msgid="2690019516263167035">"Jobb"</string>
+ <!-- no translation found for resolver_personal_tab_accessibility (5739524949153091224) -->
+ <skip />
+ <!-- no translation found for resolver_work_tab_accessibility (4753168230363802734) -->
+ <skip />
<string name="resolver_cant_share_with_work_apps" msgid="7539495559434146897">"Kan ikke dele med jobbapper"</string>
<string name="resolver_cant_share_with_personal_apps" msgid="8020581735267157241">"Kan ikke dele med personlige apper"</string>
- <string name="resolver_cant_share_cross_profile_explanation" msgid="3536237105241882679">"IT-administratoren din har blokkert deling mellom personlige apper og jobbapper"</string>
- <string name="resolver_turn_on_work_apps" msgid="8987359079870455469">"Slå på jobbapper"</string>
- <string name="resolver_turn_on_work_apps_explanation" msgid="6322467455509618928">"Slå på jobbapper for å få tilgang til jobbapper og kontakter"</string>
+ <!-- no translation found for resolver_cant_share_cross_profile_explanation (5556640604460901386) -->
+ <skip />
+ <!-- no translation found for resolver_cant_access_work_apps (375634344111233790) -->
+ <skip />
+ <!-- no translation found for resolver_cant_access_work_apps_explanation (3958762224516867388) -->
+ <skip />
+ <!-- no translation found for resolver_cant_access_personal_apps (1953215925406474177) -->
+ <skip />
+ <!-- no translation found for resolver_cant_access_personal_apps_explanation (1725572276741281136) -->
+ <skip />
+ <!-- no translation found for resolver_turn_on_work_apps_share (619263911204978175) -->
+ <skip />
+ <!-- no translation found for resolver_turn_on_work_apps_view (3073389230905543680) -->
+ <skip />
<string name="resolver_no_apps_available" msgid="7710339903040989654">"Ingen apper er tilgjengelige"</string>
- <string name="resolver_no_apps_available_explanation" msgid="4662694431121196560">"Vi fant ingen apper"</string>
- <string name="resolver_switch_on_work" msgid="8294542702883688533">"Slå på jobbprofilen"</string>
+ <!-- no translation found for resolver_switch_on_work (2873009160846966379) -->
+ <skip />
<string name="permlab_accessCallAudio" msgid="1682957511874097664">"Ta opp eller spill av lyd i telefonsamtaler"</string>
<string name="permdesc_accessCallAudio" msgid="8448360894684277823">"Tillater at denne appen tar opp eller spiller av lyd i telefonsamtaler når den er angitt som standard ringeapp."</string>
</resources>
diff --git a/core/res/res/values-ne/strings.xml b/core/res/res/values-ne/strings.xml
index d47a8ed50e0d..a6d0dbd65499 100644
--- a/core/res/res/values-ne/strings.xml
+++ b/core/res/res/values-ne/strings.xml
@@ -249,10 +249,8 @@
<item quantity="other"> बग रिपोर्टको लागि <xliff:g id="NUMBER_1">%d</xliff:g> सेकेन्डमा स्क्रिसट लिँदै।</item>
<item quantity="one"> बग रिपोर्टको लागि <xliff:g id="NUMBER_0">%d</xliff:g> सेकेन्डमा स्क्रिसट लिँदै।</item>
</plurals>
- <!-- no translation found for bugreport_screenshot_success_toast (7986095104151473745) -->
- <skip />
- <!-- no translation found for bugreport_screenshot_failure_toast (6736320861311294294) -->
- <skip />
+ <string name="bugreport_screenshot_success_toast" msgid="7986095104151473745">"बग रिपोर्टको स्क्रिनसट खिचियो"</string>
+ <string name="bugreport_screenshot_failure_toast" msgid="6736320861311294294">"बग रिपोर्टको स्क्रिनसट खिच्न सकिएन"</string>
<string name="global_action_toggle_silent_mode" msgid="8464352592860372188">"मौन मोड"</string>
<string name="global_action_silent_mode_on_status" msgid="2371892537738632013">"आवाज बन्द छ"</string>
<string name="global_action_silent_mode_off_status" msgid="6608006545950920042">"ध्वनि खुल्ला छ"</string>
@@ -454,9 +452,11 @@
<string name="permdesc_acceptHandovers" msgid="7129026180128626870">"यस अनुप्रयोगलाई अर्को अनुप्रयोगमा सुरु गरिएको कल जारी राख्ने अनुमति दिन्छ।"</string>
<string name="permlab_readPhoneNumbers" msgid="5668704794723365628">"फोन नम्बरहरू पढ्ने"</string>
<string name="permdesc_readPhoneNumbers" msgid="7368652482818338871">"उक्त अनुप्रयोगलाई यस यन्त्रको फोन नम्बरहरूमाथि पहुँच राख्न दिनुहोस्।"</string>
+ <string name="permlab_wakeLock" product="automotive" msgid="1904736682319375676">"कारको स्क्रिन सक्रिय राख्नुहोस्"</string>
<string name="permlab_wakeLock" product="tablet" msgid="1527660973931694000">"ट्याब्लेटलाई निन्द्रामा जानबाट रोक्नुहोस्"</string>
<string name="permlab_wakeLock" product="tv" msgid="2856941418123343518">"आफ्नो Android TV यन्त्रलाई शयन अवस्थामा जान नदिनुहोस्"</string>
<string name="permlab_wakeLock" product="default" msgid="569409726861695115">"फोनलाई निदाउनबाट रोक्नुहोस्"</string>
+ <string name="permdesc_wakeLock" product="automotive" msgid="5995045369683254571">"यो अनुमतिले यस अनुप्रयोगलाई कारको स्क्रिन सक्रिय राख्न दिन्छ।"</string>
<string name="permdesc_wakeLock" product="tablet" msgid="2441742939101526277">"ट्याब्लेटलाई निस्क्रिय हुनबाट रोक्नको लागि अनुप्रयोगलाई अनुमति दिन्छ।"</string>
<string name="permdesc_wakeLock" product="tv" msgid="2329298966735118796">"अनुप्रयोगलाई तपाईंको Android TV यन्त्रलाई शयन अवस्थामा जानबाट रोक्ने अनुमति दिन्छ।"</string>
<string name="permdesc_wakeLock" product="default" msgid="3689523792074007163">"फोनलाई निस्क्रिय हुनबाट रोक्नको लागि अनुप्रयोगलाई अनुमति दिन्छ।"</string>
@@ -1637,6 +1637,12 @@
<string name="safe_media_volume_warning" product="default" msgid="3751676824423049994">"सिफारिस तहभन्दा आवाज ठुलो गर्नुहुन्छ?\n\nलामो समय सम्म उच्च आवाजमा सुन्दा तपाईँको सुन्ने शक्तिलाई हानी गर्न सक्छ।"</string>
<string name="accessibility_shortcut_warning_dialog_title" msgid="4017995837692622933">"पहुँच सम्बन्धी सर्टकट प्रयोग गर्ने हो?"</string>
<string name="accessibility_shortcut_toogle_warning" msgid="4161716521310929544">"यो सर्टकट सक्रिय हुँदा, ३ सेकेन्डसम्म दुवै भोल्युम बटन थिच्नुले पहुँचसम्बन्धी कुनै सुविधा सुरु गर्ने छ।"</string>
+ <!-- no translation found for accessibility_select_shortcut_menu_title (7310194076629867377) -->
+ <skip />
+ <!-- no translation found for accessibility_edit_shortcut_menu_button_title (6096484087245145325) -->
+ <skip />
+ <!-- no translation found for accessibility_edit_shortcut_menu_volume_title (4849108668454490699) -->
+ <skip />
<string name="edit_accessibility_shortcut_menu_button" msgid="8885752738733772935">"सर्टकटहरू सम्पादन गर्नुहोस्"</string>
<string name="cancel_accessibility_shortcut_menu_button" msgid="1817413122335452474">"रद्द गर्नुहोस्"</string>
<string name="disable_accessibility_shortcut" msgid="5806091378745232383">"सर्टकटलाई निष्क्रिय पार्नुहोस्"</string>
@@ -2034,14 +2040,29 @@
<string name="as_app_forced_to_restricted_bucket" msgid="8233871289353898964">"<xliff:g id="PACKAGE_NAME">%1$s</xliff:g> लाई प्रतिबन्धित बाल्टीमा राखियो"</string>
<string name="resolver_personal_tab" msgid="2051260504014442073">"व्यक्तिगत"</string>
<string name="resolver_work_tab" msgid="2690019516263167035">"काम"</string>
+ <!-- no translation found for resolver_personal_tab_accessibility (5739524949153091224) -->
+ <skip />
+ <!-- no translation found for resolver_work_tab_accessibility (4753168230363802734) -->
+ <skip />
<string name="resolver_cant_share_with_work_apps" msgid="7539495559434146897">"कामसम्बन्धी अनुप्रयोगहरूसँग आदान प्रदान गर्न सकिँदैन"</string>
<string name="resolver_cant_share_with_personal_apps" msgid="8020581735267157241">"व्यक्तिगत अनुप्रयोगहरूसँग आदान प्रदान गर्न सकिँदैन"</string>
- <string name="resolver_cant_share_cross_profile_explanation" msgid="3536237105241882679">"तपाईंका IT प्रशासकले व्यक्तिगत र कामसम्बन्धी अनुप्रयोगहरूबिच आदान प्रदान गर्ने सुविधामाथि रोक लगाउनुभयो"</string>
- <string name="resolver_turn_on_work_apps" msgid="8987359079870455469">"कामसम्बन्धी अनुप्रयोगहरू सक्रिय गर्नुहोस्"</string>
- <string name="resolver_turn_on_work_apps_explanation" msgid="6322467455509618928">"कामसम्बन्धी अनुप्रयोग र सम्पर्क ठेगानाहरूमाथि पहुँच राख्न कामसम्बन्धी अनुप्रयोगहरू सक्रिय गर्नुहोस्"</string>
+ <!-- no translation found for resolver_cant_share_cross_profile_explanation (5556640604460901386) -->
+ <skip />
+ <!-- no translation found for resolver_cant_access_work_apps (375634344111233790) -->
+ <skip />
+ <!-- no translation found for resolver_cant_access_work_apps_explanation (3958762224516867388) -->
+ <skip />
+ <!-- no translation found for resolver_cant_access_personal_apps (1953215925406474177) -->
+ <skip />
+ <!-- no translation found for resolver_cant_access_personal_apps_explanation (1725572276741281136) -->
+ <skip />
+ <!-- no translation found for resolver_turn_on_work_apps_share (619263911204978175) -->
+ <skip />
+ <!-- no translation found for resolver_turn_on_work_apps_view (3073389230905543680) -->
+ <skip />
<string name="resolver_no_apps_available" msgid="7710339903040989654">"कुनै पनि अनुप्रयोग उपलब्ध छैन"</string>
- <string name="resolver_no_apps_available_explanation" msgid="4662694431121196560">"हामीले कुनै पनि अनुप्रयोग फेला पार्न सकेनौँ"</string>
- <string name="resolver_switch_on_work" msgid="8294542702883688533">"कार्य प्रोफाइल सक्षम पार्नुहोस्"</string>
+ <!-- no translation found for resolver_switch_on_work (2873009160846966379) -->
+ <skip />
<string name="permlab_accessCallAudio" msgid="1682957511874097664">"टेलिफोन कल गर्दै गर्दा अडियो रेकर्ड गर्नुहोस् वा प्ले गर्नुहोस्"</string>
<string name="permdesc_accessCallAudio" msgid="8448360894684277823">"यस अनुप्रयोगलाई पूर्वनिर्धारित डायलर अनुप्रयोग निर्धारण गर्दा टेलिफोन कलको अडियो रेकर्ड गर्ने र प्ले गर्ने अनुमति दिन्छ।"</string>
</resources>
diff --git a/core/res/res/values-nl/strings.xml b/core/res/res/values-nl/strings.xml
index df2f96300baf..c4c9bbe9c0ed 100644
--- a/core/res/res/values-nl/strings.xml
+++ b/core/res/res/values-nl/strings.xml
@@ -249,10 +249,8 @@
<item quantity="other">Er wordt over <xliff:g id="NUMBER_1">%d</xliff:g> seconden een screenshot gemaakt voor het bugrapport.</item>
<item quantity="one">Er wordt over <xliff:g id="NUMBER_0">%d</xliff:g> seconde een screenshot gemaakt voor het bugrapport.</item>
</plurals>
- <!-- no translation found for bugreport_screenshot_success_toast (7986095104151473745) -->
- <skip />
- <!-- no translation found for bugreport_screenshot_failure_toast (6736320861311294294) -->
- <skip />
+ <string name="bugreport_screenshot_success_toast" msgid="7986095104151473745">"Screenshot gemaakt voor bugrapport"</string>
+ <string name="bugreport_screenshot_failure_toast" msgid="6736320861311294294">"Kan geen screenshot maken voor bugrapport"</string>
<string name="global_action_toggle_silent_mode" msgid="8464352592860372188">"Stille modus"</string>
<string name="global_action_silent_mode_on_status" msgid="2371892537738632013">"Geluid is UIT"</string>
<string name="global_action_silent_mode_off_status" msgid="6608006545950920042">"Geluid is AAN"</string>
@@ -454,9 +452,11 @@
<string name="permdesc_acceptHandovers" msgid="7129026180128626870">"Hiermee kan de app een gesprek voortzetten dat is gestart in een andere app."</string>
<string name="permlab_readPhoneNumbers" msgid="5668704794723365628">"telefoonnummers lezen"</string>
<string name="permdesc_readPhoneNumbers" msgid="7368652482818338871">"Hiermee kan de app toegang krijgen tot de telefoonnummers van het apparaat."</string>
+ <string name="permlab_wakeLock" product="automotive" msgid="1904736682319375676">"autoscherm ingeschakeld houden"</string>
<string name="permlab_wakeLock" product="tablet" msgid="1527660973931694000">"voorkomen dat tablet overschakelt naar slaapmodus"</string>
<string name="permlab_wakeLock" product="tv" msgid="2856941418123343518">"voorkomen dat je Android TV overschakelt naar slaapstand"</string>
<string name="permlab_wakeLock" product="default" msgid="569409726861695115">"voorkomen dat telefoon overschakelt naar slaapmodus"</string>
+ <string name="permdesc_wakeLock" product="automotive" msgid="5995045369683254571">"Hiermee kan de app het autoscherm ingeschakeld houden."</string>
<string name="permdesc_wakeLock" product="tablet" msgid="2441742939101526277">"Hiermee kan de app voorkomen dat de tablet overschakelt naar de slaapmodus."</string>
<string name="permdesc_wakeLock" product="tv" msgid="2329298966735118796">"Hiermee kan de app voorkomen dat het Android TV-apparaat overschakelt naar de slaapstand."</string>
<string name="permdesc_wakeLock" product="default" msgid="3689523792074007163">"Hiermee kan de app voorkomen dat de telefoon overschakelt naar de slaapmodus."</string>
@@ -1631,6 +1631,12 @@
<string name="safe_media_volume_warning" product="default" msgid="3751676824423049994">"Volume verhogen tot boven het aanbevolen niveau?\n\nAls je langere tijd op hoog volume naar muziek luistert, raakt je gehoor mogelijk beschadigd."</string>
<string name="accessibility_shortcut_warning_dialog_title" msgid="4017995837692622933">"Snelkoppeling toegankelijkheid gebruiken?"</string>
<string name="accessibility_shortcut_toogle_warning" msgid="4161716521310929544">"Als de snelkoppeling is ingeschakeld, kun je drie seconden op beide volumeknoppen drukken om een toegankelijkheidsfunctie te starten."</string>
+ <!-- no translation found for accessibility_select_shortcut_menu_title (7310194076629867377) -->
+ <skip />
+ <!-- no translation found for accessibility_edit_shortcut_menu_button_title (6096484087245145325) -->
+ <skip />
+ <!-- no translation found for accessibility_edit_shortcut_menu_volume_title (4849108668454490699) -->
+ <skip />
<string name="edit_accessibility_shortcut_menu_button" msgid="8885752738733772935">"Snelkoppelingen bewerken"</string>
<string name="cancel_accessibility_shortcut_menu_button" msgid="1817413122335452474">"Annuleren"</string>
<string name="disable_accessibility_shortcut" msgid="5806091378745232383">"Sneltoets uitschakelen"</string>
@@ -1853,8 +1859,7 @@
<string name="default_notification_channel_label" msgid="3697928973567217330">"Geen categorie"</string>
<string name="importance_from_user" msgid="2782756722448800447">"Je stelt het belang van deze meldingen in."</string>
<string name="importance_from_person" msgid="4235804979664465383">"Dit is belangrijk vanwege de betrokken mensen."</string>
- <!-- no translation found for notification_history_title_placeholder (7748630986182249599) -->
- <skip />
+ <string name="notification_history_title_placeholder" msgid="7748630986182249599">"Aangepaste app-melding"</string>
<string name="user_creation_account_exists" msgid="2239146360099708035">"Toestaan dat <xliff:g id="APP">%1$s</xliff:g> een nieuwe gebruiker met <xliff:g id="ACCOUNT">%2$s</xliff:g> maakt (er is al een gebruiker met dit account)?"</string>
<string name="user_creation_adding" msgid="7305185499667958364">"Toestaan dat <xliff:g id="APP">%1$s</xliff:g> een nieuwe gebruiker met <xliff:g id="ACCOUNT">%2$s</xliff:g> maakt?"</string>
<string name="language_selection_title" msgid="52674936078683285">"Een taal toevoegen"</string>
@@ -2028,14 +2033,29 @@
<string name="as_app_forced_to_restricted_bucket" msgid="8233871289353898964">"<xliff:g id="PACKAGE_NAME">%1$s</xliff:g> is in de bucket RESTRICTED geplaatst"</string>
<string name="resolver_personal_tab" msgid="2051260504014442073">"Persoonlijk"</string>
<string name="resolver_work_tab" msgid="2690019516263167035">"Werk"</string>
+ <!-- no translation found for resolver_personal_tab_accessibility (5739524949153091224) -->
+ <skip />
+ <!-- no translation found for resolver_work_tab_accessibility (4753168230363802734) -->
+ <skip />
<string name="resolver_cant_share_with_work_apps" msgid="7539495559434146897">"Kan niet delen met werk-apps"</string>
<string name="resolver_cant_share_with_personal_apps" msgid="8020581735267157241">"Kan niet delen met persoonlijke apps"</string>
- <string name="resolver_cant_share_cross_profile_explanation" msgid="3536237105241882679">"Je IT-beheerder heeft delen tussen persoonlijke en werk-apps geblokkeerd"</string>
- <string name="resolver_turn_on_work_apps" msgid="8987359079870455469">"Schakel werk-apps in"</string>
- <string name="resolver_turn_on_work_apps_explanation" msgid="6322467455509618928">"Schakel werk-apps in om toegang tot werk-apps en -contacten te krijgen"</string>
+ <!-- no translation found for resolver_cant_share_cross_profile_explanation (5556640604460901386) -->
+ <skip />
+ <!-- no translation found for resolver_cant_access_work_apps (375634344111233790) -->
+ <skip />
+ <!-- no translation found for resolver_cant_access_work_apps_explanation (3958762224516867388) -->
+ <skip />
+ <!-- no translation found for resolver_cant_access_personal_apps (1953215925406474177) -->
+ <skip />
+ <!-- no translation found for resolver_cant_access_personal_apps_explanation (1725572276741281136) -->
+ <skip />
+ <!-- no translation found for resolver_turn_on_work_apps_share (619263911204978175) -->
+ <skip />
+ <!-- no translation found for resolver_turn_on_work_apps_view (3073389230905543680) -->
+ <skip />
<string name="resolver_no_apps_available" msgid="7710339903040989654">"Geen apps beschikbaar"</string>
- <string name="resolver_no_apps_available_explanation" msgid="4662694431121196560">"We kunnen geen apps vinden"</string>
- <string name="resolver_switch_on_work" msgid="8294542702883688533">"Werkprofiel inschakelen"</string>
+ <!-- no translation found for resolver_switch_on_work (2873009160846966379) -->
+ <skip />
<string name="permlab_accessCallAudio" msgid="1682957511874097664">"Audio opnemen of afspelen in telefoongesprekken"</string>
<string name="permdesc_accessCallAudio" msgid="8448360894684277823">"Hiermee mag deze app (indien toegewezen als standaard dialer-app) audio opnemen of afspelen in telefoongesprekken."</string>
</resources>
diff --git a/core/res/res/values-or/strings.xml b/core/res/res/values-or/strings.xml
index cc5aa2811e65..1ea50eeda829 100644
--- a/core/res/res/values-or/strings.xml
+++ b/core/res/res/values-or/strings.xml
@@ -249,10 +249,8 @@
<item quantity="other"><xliff:g id="NUMBER_1">%d</xliff:g> ସେକେଣ୍ଡରେ ବଗ୍‍ ରିପୋର୍ଟ ପାଇଁ ସ୍କ୍ରୀନଶଟ୍‍ ନେଉଛି।</item>
<item quantity="one"><xliff:g id="NUMBER_0">%d</xliff:g> ସେକେଣ୍ଡରେ ବଗ୍‍ ରିପୋର୍ଟ ପାଇଁ ସ୍କ୍ରୀନଶଟ୍‍ ନେଉଛି।</item>
</plurals>
- <!-- no translation found for bugreport_screenshot_success_toast (7986095104151473745) -->
- <skip />
- <!-- no translation found for bugreport_screenshot_failure_toast (6736320861311294294) -->
- <skip />
+ <string name="bugreport_screenshot_success_toast" msgid="7986095104151473745">"ବଗ୍ ରିପୋର୍ଟ ସହ ସ୍କ୍ରିନସଟ୍ ନିଆଯାଇଛି"</string>
+ <string name="bugreport_screenshot_failure_toast" msgid="6736320861311294294">"ବଗ୍ ରିପୋର୍ଟ ସହ ସ୍କ୍ରିନସଟ୍ ନେବାରେ ବିଫଳ ହୋଇଛି"</string>
<string name="global_action_toggle_silent_mode" msgid="8464352592860372188">"ସାଇଲେଣ୍ଟ ମୋଡ୍"</string>
<string name="global_action_silent_mode_on_status" msgid="2371892537738632013">"ସାଉଣ୍ଡ ଅଫ୍ ଅଛି"</string>
<string name="global_action_silent_mode_off_status" msgid="6608006545950920042">"ସାଉଣ୍ଡ ଅନ୍ ଅଛି"</string>
@@ -454,9 +452,11 @@
<string name="permdesc_acceptHandovers" msgid="7129026180128626870">"ଅନ୍ୟ ଆପ୍‌ରେ ଆରମ୍ଭ ହୋଇଥିବା ଗୋଟିଏ କଲ୍‌କୁ ଜାରି ରଖିବା ପାଇଁ ଆପ୍‌କୁ ଅନୁମତି ଦିଅନ୍ତୁ।"</string>
<string name="permlab_readPhoneNumbers" msgid="5668704794723365628">"ଫୋନ୍‍ ନମ୍ବର ପଢ଼େ"</string>
<string name="permdesc_readPhoneNumbers" msgid="7368652482818338871">"ଏହି ଡିଭାଇସର ଫୋନ୍‍ ନମ୍ବର ଆକ୍ସେସ୍‍ କରିବାକୁ ଆପକୁ ଅନୁମତି ଦିଏ।"</string>
+ <string name="permlab_wakeLock" product="automotive" msgid="1904736682319375676">"କାର ସ୍କ୍ରିନକୁ ଚାଲୁ ରଖନ୍ତୁ"</string>
<string name="permlab_wakeLock" product="tablet" msgid="1527660973931694000">"ଟାବଲେଟ୍‌କୁ ସ୍ଲୀପିଙ୍ଗ ମୋଡ୍‌କୁ ଯିବାକୁ ରୋକନ୍ତୁ"</string>
<string name="permlab_wakeLock" product="tv" msgid="2856941418123343518">"ସ୍ଲିପିଂରୁ ଆପଣଙ୍କର Android ଟିଭି ଡିଭାଇସ୍‌କୁ ପ୍ରତିରୋଧ କରନ୍ତୁ"</string>
<string name="permlab_wakeLock" product="default" msgid="569409726861695115">"ଫୋନକୁ ସ୍ଲୀପିଙ୍ଗ ମୋଡ୍‌କୁ ଯିବାକୁ ରୋକନ୍ତୁ"</string>
+ <string name="permdesc_wakeLock" product="automotive" msgid="5995045369683254571">"କାର ସ୍କ୍ରିନକୁ ଚାଲୁ ରଖିବା ପାଇଁ ଆପକୁ ଅନୁମତି ଦେଇଥାଏ।"</string>
<string name="permdesc_wakeLock" product="tablet" msgid="2441742939101526277">"ଆପ୍‍କୁ, ଟାବଲେଟ୍‍ଟିକୁ ସ୍ଲୀପ୍‍ ମୋଡ୍‍କୁ ଯିବାରେ ପ୍ରତିରୋଧ କରିବାକୁ ଦେଇଥାଏ।"</string>
<string name="permdesc_wakeLock" product="tv" msgid="2329298966735118796">"ଏହି ଆପ୍ ଆପଣଙ୍କର Android ଟିଭି ଡିଭାଇସ୍‌କୁ ସ୍ଲିପ୍ ମୋଡ୍‍କୁ ଯିବାରେ ପ୍ରତିରୋଧ କରିବା ପାଇଁ ଅନୁମତି ଦେଇଥାଏ।"</string>
<string name="permdesc_wakeLock" product="default" msgid="3689523792074007163">"ଆପ୍‍କୁ, ଫୋନ୍‌ଟିକୁ ସ୍ଲୀପ୍‍ ମୋଡ୍‍କୁ ଯିବାରେ ପ୍ରତିରୋଧ କରିବାକୁ ଦେଇଥାଏ।"</string>
@@ -1631,6 +1631,12 @@
<string name="safe_media_volume_warning" product="default" msgid="3751676824423049994">"ମାତ୍ରା ବଢ଼ାଇ ସୁପାରିଶ ସ୍ତର ବଢ଼ାଉଛନ୍ତି? \n\n ଲମ୍ବା ସମୟ ପର୍ଯ୍ୟନ୍ତ ଉଚ୍ଚ ଶବ୍ଦରେ ଶୁଣିଲେ ଆପଣଙ୍କ ଶ୍ରବଣ ଶକ୍ତି ଖରାପ ହୋଇପାରେ।"</string>
<string name="accessibility_shortcut_warning_dialog_title" msgid="4017995837692622933">"ଆକ୍ସେସବିଲିଟି ଶର୍ଟକଟ୍‍ ବ୍ୟବହାର କରିବେ?"</string>
<string name="accessibility_shortcut_toogle_warning" msgid="4161716521310929544">"ସର୍ଟକଟ୍ ଚାଲୁ ଥିବା ବେଳେ, ଉଭୟ ଭଲ୍ୟୁମ୍ ବଟନ୍ 3 ସେକେଣ୍ଡ ପାଇଁ ଦବାଇବା ଦ୍ୱାରା ଏକ ଆକ୍ସେସବିଲିଟି ଫିଚର୍ ଆରମ୍ଭ ହେବ।"</string>
+ <!-- no translation found for accessibility_select_shortcut_menu_title (7310194076629867377) -->
+ <skip />
+ <!-- no translation found for accessibility_edit_shortcut_menu_button_title (6096484087245145325) -->
+ <skip />
+ <!-- no translation found for accessibility_edit_shortcut_menu_volume_title (4849108668454490699) -->
+ <skip />
<string name="edit_accessibility_shortcut_menu_button" msgid="8885752738733772935">"ସର୍ଟକଟଗୁଡ଼ିକୁ ସମ୍ପାଦନ କରନ୍ତୁ"</string>
<string name="cancel_accessibility_shortcut_menu_button" msgid="1817413122335452474">"ବାତିଲ୍ କରନ୍ତୁ"</string>
<string name="disable_accessibility_shortcut" msgid="5806091378745232383">"ଶର୍ଟକଟ୍‍ ବନ୍ଦ କରନ୍ତୁ"</string>
@@ -2028,14 +2034,29 @@
<string name="as_app_forced_to_restricted_bucket" msgid="8233871289353898964">"<xliff:g id="PACKAGE_NAME">%1$s</xliff:g>କୁ ପ୍ରତିବନ୍ଧିତ ବକେଟରେ ରଖାଯାଇଛି"</string>
<string name="resolver_personal_tab" msgid="2051260504014442073">"ବ୍ୟକ୍ତିଗତ"</string>
<string name="resolver_work_tab" msgid="2690019516263167035">"କାର୍ଯ୍ୟ"</string>
+ <!-- no translation found for resolver_personal_tab_accessibility (5739524949153091224) -->
+ <skip />
+ <!-- no translation found for resolver_work_tab_accessibility (4753168230363802734) -->
+ <skip />
<string name="resolver_cant_share_with_work_apps" msgid="7539495559434146897">"କାର୍ଯ୍ୟସ୍ଥଳୀ ଆପଗୁଡ଼ିକ ସହ ସେୟାର୍ କରିପାରିବ ନାହିଁ"</string>
<string name="resolver_cant_share_with_personal_apps" msgid="8020581735267157241">"ବ୍ୟକ୍ତିଗତ ଆପଗୁଡ଼ିକ ସହ ସେୟାର୍ କରିପାରିବ ନାହିଁ"</string>
- <string name="resolver_cant_share_cross_profile_explanation" msgid="3536237105241882679">"ଆପଣଙ୍କର IT ଆଡମିନ୍ ବ୍ୟକ୍ତିଗତ ଏବଂ କାର୍ଯ୍ୟସ୍ଥଳୀ ଆପଗୁଡ଼ିକ ମଧ୍ୟରେ ସେୟାରିଂ ବ୍ଲକ୍ କରିଛନ୍ତି"</string>
- <string name="resolver_turn_on_work_apps" msgid="8987359079870455469">"କାର୍ଯ୍ୟସ୍ଥଳୀ ଆପଗୁଡ଼ିକୁ ଚାଲୁ କରନ୍ତୁ"</string>
- <string name="resolver_turn_on_work_apps_explanation" msgid="6322467455509618928">"କାର୍ଯ୍ୟସ୍ଥଳୀ ଆପ୍ ଏବଂ ଯୋଗାଯୋଗଗୁଡ଼ିକୁ ଆକ୍ସେସ୍ କରିବା ପାଇଁ କାର୍ଯ୍ୟସ୍ଥଳୀ ଆପଗୁଡ଼ିକୁ ଚାଲୁ କରନ୍ତୁ"</string>
+ <!-- no translation found for resolver_cant_share_cross_profile_explanation (5556640604460901386) -->
+ <skip />
+ <!-- no translation found for resolver_cant_access_work_apps (375634344111233790) -->
+ <skip />
+ <!-- no translation found for resolver_cant_access_work_apps_explanation (3958762224516867388) -->
+ <skip />
+ <!-- no translation found for resolver_cant_access_personal_apps (1953215925406474177) -->
+ <skip />
+ <!-- no translation found for resolver_cant_access_personal_apps_explanation (1725572276741281136) -->
+ <skip />
+ <!-- no translation found for resolver_turn_on_work_apps_share (619263911204978175) -->
+ <skip />
+ <!-- no translation found for resolver_turn_on_work_apps_view (3073389230905543680) -->
+ <skip />
<string name="resolver_no_apps_available" msgid="7710339903040989654">"କୌଣସି ଆପ୍ ଉପଲବ୍ଧ ନାହିଁ"</string>
- <string name="resolver_no_apps_available_explanation" msgid="4662694431121196560">"ଆମେ କୌଣସି ଆପ୍ ପାଇଲୁ ନାହିଁ"</string>
- <string name="resolver_switch_on_work" msgid="8294542702883688533">"କାର୍ଯ୍ୟସ୍ଥଳୀ ପ୍ରୋଫାଇଲରେ ସ୍ୱିଚ୍ କରନ୍ତୁ"</string>
+ <!-- no translation found for resolver_switch_on_work (2873009160846966379) -->
+ <skip />
<string name="permlab_accessCallAudio" msgid="1682957511874097664">"ଟେଲିଫୋନି କଲଗୁଡ଼ିକରେ ଅଡିଓ ରେକର୍ଡ କରନ୍ତୁ ବା ଚଲାନ୍ତୁ"</string>
<string name="permdesc_accessCallAudio" msgid="8448360894684277823">"ଏହି ଆପ୍ ଡିଫଲ୍ଟ ଡାଏଲର୍ ଆପ୍ଲିକେସନ୍ ଭାବରେ ଆସାଇନ୍ ହୋଇଥିଲେ ଟେଲିଫୋନି କଲଗୁଡ଼ିକରେ ଅଡିଓ ରେକର୍ଡ କରିବା ବା ଚଲାଇବା ପାଇଁ ଅନୁମତି ଦିଅନ୍ତୁ।"</string>
</resources>
diff --git a/core/res/res/values-pa/strings.xml b/core/res/res/values-pa/strings.xml
index 6c8b5c3e3ef4..8e5ae7dc8ccd 100644
--- a/core/res/res/values-pa/strings.xml
+++ b/core/res/res/values-pa/strings.xml
@@ -193,14 +193,10 @@
<string name="network_logging_notification_text" msgid="1327373071132562512">"ਤੁਹਾਡਾ ਸੰਗਠਨ ਇਸ ਡੀਵਾਈਸ ਦਾ ਪ੍ਰਬੰਧਨ ਕਰਦਾ ਹੈ ਅਤੇ ਨੈੱਟਵਰਕ ਟਰੈਫਿਕ ਦੀ ਨਿਗਰਾਨੀ ਕਰ ਸਕਦਾ ਹੈ। ਵੇਰਵਿਆਂ ਲਈ ਟੈਪ ਕਰੋ।"</string>
<string name="location_changed_notification_title" msgid="4119726617105166830">"ਤੁਹਾਡੇ ਪ੍ਰਸ਼ਾਸਕ ਨੇ ਟਿਕਾਣਾ ਸੈਟਿੰਗਾਂ ਨੂੰ ਬਦਲ ਦਿੱਤਾ ਹੈ"</string>
<string name="location_changed_notification_text" msgid="198907268219396399">"ਆਪਣੀਆਂ ਟਿਕਾਣਾ ਸੈਟਿੰਗਾਂ ਨੂੰ ਦੇਖਣ ਲਈ ਟੈਪ ਕਰੋ।"</string>
- <!-- no translation found for country_detector (7023275114706088854) -->
- <skip />
- <!-- no translation found for location_service (2439187616018455546) -->
- <skip />
- <!-- no translation found for sensor_notification_service (7474531979178682676) -->
- <skip />
- <!-- no translation found for twilight_service (8964898045693187224) -->
- <skip />
+ <string name="country_detector" msgid="7023275114706088854">"ਦੇਸ਼ ਦਾ ਪਤਾ ਲਗਾਉਣ ਦੀ ਸੁਵਿਧਾ"</string>
+ <string name="location_service" msgid="2439187616018455546">"ਟਿਕਾਣਾ ਸੇਵਾ"</string>
+ <string name="sensor_notification_service" msgid="7474531979178682676">"ਸੈਂਸਰ ਸੂਚਨਾ ਸੇਵਾ"</string>
+ <string name="twilight_service" msgid="8964898045693187224">"ਟਵੀਲਾਈਟ ਸੇਵਾ"</string>
<string name="factory_reset_warning" msgid="6858705527798047809">"ਤੁਹਾਡਾ ਡੀਵਾਈਸ ਮਿਟਾਇਆ ਜਾਏਗਾ"</string>
<string name="factory_reset_message" msgid="2657049595153992213">"ਪ੍ਰਸ਼ਾਸਕ ਐਪ ਵਰਤੀ ਨਹੀਂ ਜਾ ਸਕਦੀ। ਹੁਣ ਤੁਹਾਡੇ ਡੀਵਾਈਸ ਦਾ ਡਾਟਾ ਮਿਟਾਇਆ ਜਾਵੇਗਾ।\n\nਜੇਕਰ ਤੁਹਾਡੇ ਕੋਲ ਕੋਈ ਸਵਾਲ ਹਨ, ਤਾਂ ਆਪਣੀ ਸੰਸਥਾ ਦੇ ਪ੍ਰਸ਼ਾਸਕ ਨੂੰ ਸੰਪਰਕ ਕਰੋ।"</string>
<string name="printing_disabled_by" msgid="3517499806528864633">"<xliff:g id="OWNER_APP">%s</xliff:g> ਵੱਲੋਂ ਪ੍ਰਿੰਟ ਕਰਨਾ ਬੰਦ ਕੀਤਾ ਗਿਆ।"</string>
@@ -253,10 +249,8 @@
<item quantity="one">ਬੱਗ ਰਿਪੋਰਟ ਲਈ <xliff:g id="NUMBER_1">%d</xliff:g> ਸਕਿੰਟਾਂ ਵਿੱਚ ਸਕ੍ਰੀਨਸ਼ਾਟ ਲਿਆ ਜਾ ਰਿਹਾ ਹੈ।</item>
<item quantity="other">ਬੱਗ ਰਿਪੋਰਟ ਲਈ <xliff:g id="NUMBER_1">%d</xliff:g> ਸਕਿੰਟਾਂ ਵਿੱਚ ਸਕ੍ਰੀਨਸ਼ਾਟ ਲਿਆ ਜਾ ਰਿਹਾ ਹੈ।</item>
</plurals>
- <!-- no translation found for bugreport_screenshot_success_toast (7986095104151473745) -->
- <skip />
- <!-- no translation found for bugreport_screenshot_failure_toast (6736320861311294294) -->
- <skip />
+ <string name="bugreport_screenshot_success_toast" msgid="7986095104151473745">"ਬੱਗ ਰਿਪੋਰਟ ਦਾ ਸਕ੍ਰੀਨਸ਼ਾਟ ਲਿਆ ਗਿਆ"</string>
+ <string name="bugreport_screenshot_failure_toast" msgid="6736320861311294294">"ਬੱਗ ਰਿਪੋਰਟ ਦਾ ਸਕ੍ਰੀਨਸ਼ਾਟ ਲੈਣਾ ਅਸਫਲ ਰਿਹਾ"</string>
<string name="global_action_toggle_silent_mode" msgid="8464352592860372188">"ਸਾਈਲੈਂਟ ਮੋਡ"</string>
<string name="global_action_silent_mode_on_status" msgid="2371892537738632013">"ਅਵਾਜ਼ ਬੰਦ ਹੈ"</string>
<string name="global_action_silent_mode_off_status" msgid="6608006545950920042">"ਅਵਾਜ਼ ਚਾਲੂ ਹੈ"</string>
@@ -458,9 +452,11 @@
<string name="permdesc_acceptHandovers" msgid="7129026180128626870">"ਐਪ ਨੂੰ ਉਹ ਕਾਲ ਜਾਰੀ ਰੱਖਣ ਦਿਓ ਜਿਸਨੂੰ ਹੋਰ ਐਪ ਤੋਂ ਚਾਲੂ ਕੀਤਾ ਗਿਆ ਸੀ।"</string>
<string name="permlab_readPhoneNumbers" msgid="5668704794723365628">"ਫ਼ੋਨ ਨੰਬਰ ਪੜ੍ਹੋ"</string>
<string name="permdesc_readPhoneNumbers" msgid="7368652482818338871">"ਐਪ ਨੂੰ ਡੀਵਾਈਸ ਦੇ ਫ਼ੋਨ ਨੰਬਰਾਂ \'ਤੇ ਪਹੁੰਚ ਕਰਨ ਦੀ ਇਜਾਜ਼ਤ ਦਿੰਦੀ ਹੈ।"</string>
+ <string name="permlab_wakeLock" product="automotive" msgid="1904736682319375676">"ਕਾਰ ਦੀ ਸਕ੍ਰੀਨ ਚਾਲੂ ਰੱਖੋ"</string>
<string name="permlab_wakeLock" product="tablet" msgid="1527660973931694000">"ਟੈਬਲੈੱਟ ਨੂੰ ਸਲੀਪ ਤੇ ਜਾਣ ਤੋਂ ਰੋਕੋ"</string>
<string name="permlab_wakeLock" product="tv" msgid="2856941418123343518">"ਆਪਣੇ Android TV ਡੀਵਾਈਸ ਨੂੰ ਸਲੀਪ ਮੋਡ ਵਿੱਚ ਜਾਣ ਤੋਂ ਰੋਕੋੇ"</string>
<string name="permlab_wakeLock" product="default" msgid="569409726861695115">"ਫ਼ੋਨ ਨੂੰ ਸਲੀਪਿੰਗ ਤੋਂ ਰੋਕੋ"</string>
+ <string name="permdesc_wakeLock" product="automotive" msgid="5995045369683254571">"ਐਪ ਨੂੰ ਕਾਰ ਦੀ ਸਕ੍ਰੀਨ ਹਰ ਵੇਲੇ ਚਾਲੂ ਰੱਖਣ ਦਿੰਦਾ ਹੈ।"</string>
<string name="permdesc_wakeLock" product="tablet" msgid="2441742939101526277">"ਐਪ ਨੂੰ ਟੈਬਲੈੱਟ ਨੂੰ ਸਲੀਪ ਤੇ ਜਾਣ ਤੋਂ ਰੋਕਣ ਦੀ ਆਗਿਆ ਦਿੰਦਾ ਹੈ।"</string>
<string name="permdesc_wakeLock" product="tv" msgid="2329298966735118796">"ਐਪ ਨੂੰ ਤੁਹਾਡੇ Android TV ਡੀਵਾਈਸ ਨੂੰ ਸਲੀਪ ਮੋਡ \'ਤੇ ਜਾਣ ਤੋਂ ਰੋਕਣ ਦਿੰਦੀ ਹੈ।"</string>
<string name="permdesc_wakeLock" product="default" msgid="3689523792074007163">"ਐਪ ਨੂੰ ਫ਼ੋਨ ਨੂੰ ਸਲੀਪ ਤੇ ਜਾਣ ਤੋਂ ਰੋਕਣ ਦੀ ਆਗਿਆ ਦਿੰਦਾ ਹੈ।"</string>
@@ -1635,6 +1631,12 @@
<string name="safe_media_volume_warning" product="default" msgid="3751676824423049994">"ਕੀ ਵੌਲਿਊਮ ਸਿਫ਼ਾਰਸ਼ ਕੀਤੇ ਪੱਧਰ ਤੋਂ ਵਧਾਉਣੀ ਹੈ?\n\nਲੰਮੇ ਸਮੇਂ ਤੱਕ ਉੱਚ ਵੌਲਿਊਮ ਤੇ ਸੁਣਨ ਨਾਲ ਤੁਹਾਡੀ ਸੁਣਨ ਸ਼ਕਤੀ ਨੂੰ ਨੁਕਸਾਨ ਪਹੁੰਚ ਸਕਦਾ ਹੈ।"</string>
<string name="accessibility_shortcut_warning_dialog_title" msgid="4017995837692622933">"ਕੀ ਪਹੁੰਚਯੋਗਤਾ ਸ਼ਾਰਟਕੱਟ ਵਰਤਣਾ ਹੈ?"</string>
<string name="accessibility_shortcut_toogle_warning" msgid="4161716521310929544">"ਸ਼ਾਰਟਕੱਟ ਚਾਲੂ ਹੋਣ \'ਤੇ, ਕਿਸੇ ਪਹੁੰਚਯੋਗਤਾ ਵਿਸ਼ੇਸ਼ਤਾ ਨੂੰ ਸ਼ੁਰੂ ਕਰਨ ਲਈ ਦੋਵੇਂ ਅਵਾਜ਼ ਬਟਨਾਂ ਨੂੰ 3 ਸਕਿੰਟ ਲਈ ਦਬਾ ਕੇ ਰੱਖੋ।"</string>
+ <!-- no translation found for accessibility_select_shortcut_menu_title (7310194076629867377) -->
+ <skip />
+ <!-- no translation found for accessibility_edit_shortcut_menu_button_title (6096484087245145325) -->
+ <skip />
+ <!-- no translation found for accessibility_edit_shortcut_menu_volume_title (4849108668454490699) -->
+ <skip />
<string name="edit_accessibility_shortcut_menu_button" msgid="8885752738733772935">"ਸ਼ਾਰਟਕੱਟਾਂ ਦਾ ਸੰਪਾਦਨ ਕਰੋ"</string>
<string name="cancel_accessibility_shortcut_menu_button" msgid="1817413122335452474">"ਰੱਦ ਕਰੋ"</string>
<string name="disable_accessibility_shortcut" msgid="5806091378745232383">"ਸ਼ਾਰਟਕੱਟ ਬੰਦ ਕਰੋ"</string>
@@ -2032,14 +2034,29 @@
<string name="as_app_forced_to_restricted_bucket" msgid="8233871289353898964">"<xliff:g id="PACKAGE_NAME">%1$s</xliff:g> ਨੂੰ ਪ੍ਰਤਿਬੰਧਿਤ ਖਾਨੇ ਵਿੱਚ ਪਾਇਆ ਗਿਆ ਹੈ"</string>
<string name="resolver_personal_tab" msgid="2051260504014442073">"ਨਿੱਜੀ"</string>
<string name="resolver_work_tab" msgid="2690019516263167035">"ਕੰਮ"</string>
+ <!-- no translation found for resolver_personal_tab_accessibility (5739524949153091224) -->
+ <skip />
+ <!-- no translation found for resolver_work_tab_accessibility (4753168230363802734) -->
+ <skip />
<string name="resolver_cant_share_with_work_apps" msgid="7539495559434146897">"ਕੰਮ ਸੰਬੰਧੀ ਐਪਾਂ ਨਾਲ ਸਾਂਝਾ ਨਹੀਂ ਕੀਤਾ ਜਾ ਸਕਦਾ"</string>
<string name="resolver_cant_share_with_personal_apps" msgid="8020581735267157241">"ਨਿੱਜੀ ਐਪਾਂ ਨਾਲ ਸਾਂਝਾ ਨਹੀਂ ਕੀਤਾ ਜਾ ਸਕਦਾ"</string>
- <string name="resolver_cant_share_cross_profile_explanation" msgid="3536237105241882679">"ਤੁਹਾਡੇ ਆਈ.ਟੀ. ਪ੍ਰਸ਼ਾਸਕ ਨੇ ਨਿੱਜੀ ਅਤੇ ਕੰਮ ਸੰਬੰਧੀ ਐਪਾਂ ਵਿਚਕਾਰ ਸਾਂਝਾਕਰਨ ਨੂੰ ਬਲਾਕ ਕੀਤਾ ਹੈ"</string>
- <string name="resolver_turn_on_work_apps" msgid="8987359079870455469">"ਕੰਮ ਸੰਬੰਧੀ ਐਪਾਂ ਚਾਲੂ ਕਰੋ"</string>
- <string name="resolver_turn_on_work_apps_explanation" msgid="6322467455509618928">"ਕੰਮ ਸੰਬੰਧੀ ਐਪਾਂ ਅਤੇ ਸੰਪਰਕਾਂ ਤੱਕ ਪਹੁੰਚ ਕਰਨ ਲਈ ਕੰਮ ਸੰਬੰਧੀ ਐਪਾਂ ਨੂੰ ਚਾਲੂ ਕਰੋ"</string>
+ <!-- no translation found for resolver_cant_share_cross_profile_explanation (5556640604460901386) -->
+ <skip />
+ <!-- no translation found for resolver_cant_access_work_apps (375634344111233790) -->
+ <skip />
+ <!-- no translation found for resolver_cant_access_work_apps_explanation (3958762224516867388) -->
+ <skip />
+ <!-- no translation found for resolver_cant_access_personal_apps (1953215925406474177) -->
+ <skip />
+ <!-- no translation found for resolver_cant_access_personal_apps_explanation (1725572276741281136) -->
+ <skip />
+ <!-- no translation found for resolver_turn_on_work_apps_share (619263911204978175) -->
+ <skip />
+ <!-- no translation found for resolver_turn_on_work_apps_view (3073389230905543680) -->
+ <skip />
<string name="resolver_no_apps_available" msgid="7710339903040989654">"ਕੋਈ ਐਪ ਉਪਲਬਧ ਨਹੀਂ"</string>
- <string name="resolver_no_apps_available_explanation" msgid="4662694431121196560">"ਅਸੀਂ ਕੋਈ ਐਪ ਨਹੀਂ ਲੱਭ ਸਕੇ"</string>
- <string name="resolver_switch_on_work" msgid="8294542702883688533">"ਕਾਰਜ ਪ੍ਰੋਫਾਈਲ \'ਤੇ ਜਾਓ"</string>
+ <!-- no translation found for resolver_switch_on_work (2873009160846966379) -->
+ <skip />
<string name="permlab_accessCallAudio" msgid="1682957511874097664">"ਟੈਲੀਫ਼ੋਨੀ ਕਾਲਾਂ ਵਿੱਚ ਰਿਕਾਰਡ ਕਰੋ ਜਾਂ ਆਡੀਓ ਚਲਾਓ"</string>
<string name="permdesc_accessCallAudio" msgid="8448360894684277823">"ਇਹ ਇਸ ਐਪ ਨੂੰ, ਪੂਰਵ-ਨਿਰਧਾਰਤ ਡਾਇਲਰ ਐਪਲੀਕੇਸ਼ਨ ਵਜੋਂ ਜਿੰਮੇ ਲਾਏ ਜਾਣ \'ਤੇ, ਟੈਲੀਫ਼ੋਨੀ ਕਾਲਾਂ ਵਿੱਚ ਰਿਕਾਰਡ ਕਰਨ ਜਾਂ ਆਡੀਓ ਚਲਾਉਣ ਦਿੰਦਾ ਹੈ।"</string>
</resources>
diff --git a/core/res/res/values-pl/strings.xml b/core/res/res/values-pl/strings.xml
index c4246fad9a3e..91c8c703880d 100644
--- a/core/res/res/values-pl/strings.xml
+++ b/core/res/res/values-pl/strings.xml
@@ -255,10 +255,8 @@
<item quantity="other">Zrzut ekranu do raportu o błędzie zostanie zrobiony za <xliff:g id="NUMBER_1">%d</xliff:g> sekundy.</item>
<item quantity="one">Zrzut ekranu do raportu o błędzie zostanie zrobiony za <xliff:g id="NUMBER_0">%d</xliff:g> sekundę.</item>
</plurals>
- <!-- no translation found for bugreport_screenshot_success_toast (7986095104151473745) -->
- <skip />
- <!-- no translation found for bugreport_screenshot_failure_toast (6736320861311294294) -->
- <skip />
+ <string name="bugreport_screenshot_success_toast" msgid="7986095104151473745">"Zrobiono zrzut ekranu z raportem o błędzie"</string>
+ <string name="bugreport_screenshot_failure_toast" msgid="6736320861311294294">"Nie udało się zrobić zrzutu ekranu z raportem o błędzie"</string>
<string name="global_action_toggle_silent_mode" msgid="8464352592860372188">"Tryb cichy"</string>
<string name="global_action_silent_mode_on_status" msgid="2371892537738632013">"Dźwięk jest wyłączony"</string>
<string name="global_action_silent_mode_off_status" msgid="6608006545950920042">"Dźwięk jest włączony"</string>
@@ -460,9 +458,11 @@
<string name="permdesc_acceptHandovers" msgid="7129026180128626870">"Zezwala na kontynuowanie przez aplikację połączenia rozpoczętego w innej aplikacji."</string>
<string name="permlab_readPhoneNumbers" msgid="5668704794723365628">"odczytywanie numerów telefonów"</string>
<string name="permdesc_readPhoneNumbers" msgid="7368652482818338871">"Zezwala aplikacji na dostęp do numerów telefonów na urządzeniu."</string>
+ <string name="permlab_wakeLock" product="automotive" msgid="1904736682319375676">"utrzymuj włączony ekran samochodu"</string>
<string name="permlab_wakeLock" product="tablet" msgid="1527660973931694000">"zapobieganie przechodzeniu tabletu do trybu uśpienia"</string>
<string name="permlab_wakeLock" product="tv" msgid="2856941418123343518">"zapobieganie uśpieniu urządzenia z Androidem TV"</string>
<string name="permlab_wakeLock" product="default" msgid="569409726861695115">"zapobieganie przejściu telefonu w stan uśpienia"</string>
+ <string name="permdesc_wakeLock" product="automotive" msgid="5995045369683254571">"Zezwala aplikacji na utrzymywanie włączonego ekranu samochodu"</string>
<string name="permdesc_wakeLock" product="tablet" msgid="2441742939101526277">"Pozwala aplikacji na zapobieganie przechodzeniu tabletu do trybu uśpienia."</string>
<string name="permdesc_wakeLock" product="tv" msgid="2329298966735118796">"Pozwala aplikacji zapobiegać przechodzeniu urządzenia z Androidem TV w tryb uśpienia."</string>
<string name="permdesc_wakeLock" product="default" msgid="3689523792074007163">"Pozwala aplikacji na zapobieganie przechodzeniu telefonu w tryb uśpienia."</string>
@@ -1675,6 +1675,12 @@
<string name="safe_media_volume_warning" product="default" msgid="3751676824423049994">"Zwiększyć głośność ponad zalecany poziom?\n\nSłuchanie głośno przez długi czas może uszkodzić Twój słuch."</string>
<string name="accessibility_shortcut_warning_dialog_title" msgid="4017995837692622933">"Użyć skrótu do ułatwień dostępu?"</string>
<string name="accessibility_shortcut_toogle_warning" msgid="4161716521310929544">"Gdy skrót jest włączony, jednoczesne naciskanie przez trzy sekundy obu przycisków głośności uruchamia funkcję ułatwień dostępu."</string>
+ <!-- no translation found for accessibility_select_shortcut_menu_title (7310194076629867377) -->
+ <skip />
+ <!-- no translation found for accessibility_edit_shortcut_menu_button_title (6096484087245145325) -->
+ <skip />
+ <!-- no translation found for accessibility_edit_shortcut_menu_volume_title (4849108668454490699) -->
+ <skip />
<string name="edit_accessibility_shortcut_menu_button" msgid="8885752738733772935">"Edytuj skróty"</string>
<string name="cancel_accessibility_shortcut_menu_button" msgid="1817413122335452474">"Anuluj"</string>
<string name="disable_accessibility_shortcut" msgid="5806091378745232383">"Wyłącz skrót"</string>
@@ -1917,8 +1923,7 @@
<string name="default_notification_channel_label" msgid="3697928973567217330">"Bez kategorii"</string>
<string name="importance_from_user" msgid="2782756722448800447">"Ustawiłeś ważność tych powiadomień."</string>
<string name="importance_from_person" msgid="4235804979664465383">"Ta wiadomość jest ważna ze względu na osoby uczestniczące w wątku."</string>
- <!-- no translation found for notification_history_title_placeholder (7748630986182249599) -->
- <skip />
+ <string name="notification_history_title_placeholder" msgid="7748630986182249599">"Niestandardowe powiadomienie z aplikacji"</string>
<string name="user_creation_account_exists" msgid="2239146360099708035">"Zezwolić aplikacji <xliff:g id="APP">%1$s</xliff:g> na utworzenie nowego użytkownika dla konta <xliff:g id="ACCOUNT">%2$s</xliff:g> (użytkownik dla tego konta już istnieje)?"</string>
<string name="user_creation_adding" msgid="7305185499667958364">"Zezwolić aplikacji <xliff:g id="APP">%1$s</xliff:g> na utworzenie nowego użytkownika dla konta <xliff:g id="ACCOUNT">%2$s</xliff:g>?"</string>
<string name="language_selection_title" msgid="52674936078683285">"Dodaj język"</string>
@@ -2096,14 +2101,29 @@
<string name="as_app_forced_to_restricted_bucket" msgid="8233871289353898964">"Umieszczono pakiet <xliff:g id="PACKAGE_NAME">%1$s</xliff:g> w zasobniku danych RESTRICTED"</string>
<string name="resolver_personal_tab" msgid="2051260504014442073">"Osobiste"</string>
<string name="resolver_work_tab" msgid="2690019516263167035">"Do pracy"</string>
+ <!-- no translation found for resolver_personal_tab_accessibility (5739524949153091224) -->
+ <skip />
+ <!-- no translation found for resolver_work_tab_accessibility (4753168230363802734) -->
+ <skip />
<string name="resolver_cant_share_with_work_apps" msgid="7539495559434146897">"Nie można udostępnić aplikacji do pracy"</string>
<string name="resolver_cant_share_with_personal_apps" msgid="8020581735267157241">"Nie można udostępnić aplikacji osobistej"</string>
- <string name="resolver_cant_share_cross_profile_explanation" msgid="3536237105241882679">"Administrator IT zablokował udostępnianie między aplikacjami osobistymi i aplikacjami do pracy"</string>
- <string name="resolver_turn_on_work_apps" msgid="8987359079870455469">"Włącz aplikacje do pracy"</string>
- <string name="resolver_turn_on_work_apps_explanation" msgid="6322467455509618928">"Włącz aplikacje do pracy, aby uzyskać dostęp do kontaktów i aplikacji do pracy"</string>
+ <!-- no translation found for resolver_cant_share_cross_profile_explanation (5556640604460901386) -->
+ <skip />
+ <!-- no translation found for resolver_cant_access_work_apps (375634344111233790) -->
+ <skip />
+ <!-- no translation found for resolver_cant_access_work_apps_explanation (3958762224516867388) -->
+ <skip />
+ <!-- no translation found for resolver_cant_access_personal_apps (1953215925406474177) -->
+ <skip />
+ <!-- no translation found for resolver_cant_access_personal_apps_explanation (1725572276741281136) -->
+ <skip />
+ <!-- no translation found for resolver_turn_on_work_apps_share (619263911204978175) -->
+ <skip />
+ <!-- no translation found for resolver_turn_on_work_apps_view (3073389230905543680) -->
+ <skip />
<string name="resolver_no_apps_available" msgid="7710339903040989654">"Brak dostępnych aplikacji"</string>
- <string name="resolver_no_apps_available_explanation" msgid="4662694431121196560">"Nie znaleźliśmy żadnych aplikacji"</string>
- <string name="resolver_switch_on_work" msgid="8294542702883688533">"Włącz profil do pracy"</string>
+ <!-- no translation found for resolver_switch_on_work (2873009160846966379) -->
+ <skip />
<string name="permlab_accessCallAudio" msgid="1682957511874097664">"Nagrywanie lub odtwarzanie dźwięku podczas połączeń telefonicznych"</string>
<string name="permdesc_accessCallAudio" msgid="8448360894684277823">"Zezwala na odtwarzanie dźwięku podczas rozmów telefonicznych przez aplikację przypisaną jako domyślnie wybierającą numery."</string>
</resources>
diff --git a/core/res/res/values-pt-rBR/strings.xml b/core/res/res/values-pt-rBR/strings.xml
index dfb5beff86b5..7bdfffad2d65 100644
--- a/core/res/res/values-pt-rBR/strings.xml
+++ b/core/res/res/values-pt-rBR/strings.xml
@@ -249,10 +249,8 @@
<item quantity="one">Capturas de tela para o relatório de bug serão feitas em <xliff:g id="NUMBER_1">%d</xliff:g> segundos.</item>
<item quantity="other">Capturas de tela para o relatório de bug serão feitas em <xliff:g id="NUMBER_1">%d</xliff:g> segundos.</item>
</plurals>
- <!-- no translation found for bugreport_screenshot_success_toast (7986095104151473745) -->
- <skip />
- <!-- no translation found for bugreport_screenshot_failure_toast (6736320861311294294) -->
- <skip />
+ <string name="bugreport_screenshot_success_toast" msgid="7986095104151473745">"Captura de tela com o relatório do bug concluída"</string>
+ <string name="bugreport_screenshot_failure_toast" msgid="6736320861311294294">"Falha ao capturar a tela com o relatório do bug"</string>
<string name="global_action_toggle_silent_mode" msgid="8464352592860372188">"Modo silencioso"</string>
<string name="global_action_silent_mode_on_status" msgid="2371892537738632013">"Som DESATIVADO"</string>
<string name="global_action_silent_mode_off_status" msgid="6608006545950920042">"O som está ATIVADO"</string>
@@ -454,9 +452,11 @@
<string name="permdesc_acceptHandovers" msgid="7129026180128626870">"Permite que o app continue uma chamada que foi iniciada em outro app."</string>
<string name="permlab_readPhoneNumbers" msgid="5668704794723365628">"ler números de telefone"</string>
<string name="permdesc_readPhoneNumbers" msgid="7368652482818338871">"Permite que o app acesse os número de telefone do dispositivo."</string>
+ <string name="permlab_wakeLock" product="automotive" msgid="1904736682319375676">"manter a tela do carro ativada"</string>
<string name="permlab_wakeLock" product="tablet" msgid="1527660973931694000">"impedir modo de inatividade do tablet"</string>
<string name="permlab_wakeLock" product="tv" msgid="2856941418123343518">"evitar que seu dispositivo Android TV entre no modo de suspensão"</string>
<string name="permlab_wakeLock" product="default" msgid="569409726861695115">"impedir modo de inatividade do telefone"</string>
+ <string name="permdesc_wakeLock" product="automotive" msgid="5995045369683254571">"Permite que o app mantenha a tela do carro ativada."</string>
<string name="permdesc_wakeLock" product="tablet" msgid="2441742939101526277">"Permite que o app impeça a suspensão do tablet."</string>
<string name="permdesc_wakeLock" product="tv" msgid="2329298966735118796">"Permite que o app impeça o dispositivo Android TV de entrar no modo de suspensão."</string>
<string name="permdesc_wakeLock" product="default" msgid="3689523792074007163">"Permite que o app impeça a suspensão do telefone."</string>
@@ -1631,6 +1631,12 @@
<string name="safe_media_volume_warning" product="default" msgid="3751676824423049994">"Aumentar o volume acima do nível recomendado?\n\nOuvir em volume alto por longos períodos pode danificar sua audição."</string>
<string name="accessibility_shortcut_warning_dialog_title" msgid="4017995837692622933">"Usar atalho de Acessibilidade?"</string>
<string name="accessibility_shortcut_toogle_warning" msgid="4161716521310929544">"Quando o atalho estiver ativado, pressione os dois botões de volume por três segundos para iniciar um recurso de acessibilidade."</string>
+ <!-- no translation found for accessibility_select_shortcut_menu_title (7310194076629867377) -->
+ <skip />
+ <!-- no translation found for accessibility_edit_shortcut_menu_button_title (6096484087245145325) -->
+ <skip />
+ <!-- no translation found for accessibility_edit_shortcut_menu_volume_title (4849108668454490699) -->
+ <skip />
<string name="edit_accessibility_shortcut_menu_button" msgid="8885752738733772935">"Editar atalhos"</string>
<string name="cancel_accessibility_shortcut_menu_button" msgid="1817413122335452474">"Cancelar"</string>
<string name="disable_accessibility_shortcut" msgid="5806091378745232383">"Desativar atalho"</string>
@@ -1853,8 +1859,7 @@
<string name="default_notification_channel_label" msgid="3697928973567217330">"Sem classificação"</string>
<string name="importance_from_user" msgid="2782756722448800447">"Você definiu a importância dessas notificações."</string>
<string name="importance_from_person" msgid="4235804979664465383">"Isso é importante por causa das pessoas envolvidas."</string>
- <!-- no translation found for notification_history_title_placeholder (7748630986182249599) -->
- <skip />
+ <string name="notification_history_title_placeholder" msgid="7748630986182249599">"Notificação personalizada do app"</string>
<string name="user_creation_account_exists" msgid="2239146360099708035">"Permitir que o app <xliff:g id="APP">%1$s</xliff:g> crie um novo usuário com <xliff:g id="ACCOUNT">%2$s</xliff:g> (já existe um usuário com essa conta)?"</string>
<string name="user_creation_adding" msgid="7305185499667958364">"Permitir que o app <xliff:g id="APP">%1$s</xliff:g> crie um novo usuário com <xliff:g id="ACCOUNT">%2$s</xliff:g>?"</string>
<string name="language_selection_title" msgid="52674936078683285">"Adicionar um idioma"</string>
@@ -2028,14 +2033,29 @@
<string name="as_app_forced_to_restricted_bucket" msgid="8233871289353898964">"<xliff:g id="PACKAGE_NAME">%1$s</xliff:g> foi colocado no intervalo \"RESTRITO\""</string>
<string name="resolver_personal_tab" msgid="2051260504014442073">"Pessoal"</string>
<string name="resolver_work_tab" msgid="2690019516263167035">"Trabalho"</string>
+ <!-- no translation found for resolver_personal_tab_accessibility (5739524949153091224) -->
+ <skip />
+ <!-- no translation found for resolver_work_tab_accessibility (4753168230363802734) -->
+ <skip />
<string name="resolver_cant_share_with_work_apps" msgid="7539495559434146897">"Não é possível compartilhar com apps de trabalho"</string>
<string name="resolver_cant_share_with_personal_apps" msgid="8020581735267157241">"Não é possível compartilhar com apps pessoais"</string>
- <string name="resolver_cant_share_cross_profile_explanation" msgid="3536237105241882679">"Seu administrador de TI bloqueou o compartilhamento entre apps pessoais e de trabalho"</string>
- <string name="resolver_turn_on_work_apps" msgid="8987359079870455469">"Ativar apps de trabalho"</string>
- <string name="resolver_turn_on_work_apps_explanation" msgid="6322467455509618928">"Ative os apps de trabalho para acessar apps e contatos profissionais"</string>
+ <!-- no translation found for resolver_cant_share_cross_profile_explanation (5556640604460901386) -->
+ <skip />
+ <!-- no translation found for resolver_cant_access_work_apps (375634344111233790) -->
+ <skip />
+ <!-- no translation found for resolver_cant_access_work_apps_explanation (3958762224516867388) -->
+ <skip />
+ <!-- no translation found for resolver_cant_access_personal_apps (1953215925406474177) -->
+ <skip />
+ <!-- no translation found for resolver_cant_access_personal_apps_explanation (1725572276741281136) -->
+ <skip />
+ <!-- no translation found for resolver_turn_on_work_apps_share (619263911204978175) -->
+ <skip />
+ <!-- no translation found for resolver_turn_on_work_apps_view (3073389230905543680) -->
+ <skip />
<string name="resolver_no_apps_available" msgid="7710339903040989654">"Nenhum app disponível"</string>
- <string name="resolver_no_apps_available_explanation" msgid="4662694431121196560">"Não foi possível encontrar nenhum app"</string>
- <string name="resolver_switch_on_work" msgid="8294542702883688533">"Ativar perfil de trabalho"</string>
+ <!-- no translation found for resolver_switch_on_work (2873009160846966379) -->
+ <skip />
<string name="permlab_accessCallAudio" msgid="1682957511874097664">"Gravar ou tocar áudio em chamadas telefônicas"</string>
<string name="permdesc_accessCallAudio" msgid="8448360894684277823">"Permitir que esse app grave ou toque áudio em chamadas telefônicas quando for usado como aplicativo discador padrão."</string>
</resources>
diff --git a/core/res/res/values-pt-rPT/strings.xml b/core/res/res/values-pt-rPT/strings.xml
index 00c56dd8be21..da2207e93c92 100644
--- a/core/res/res/values-pt-rPT/strings.xml
+++ b/core/res/res/values-pt-rPT/strings.xml
@@ -249,10 +249,8 @@
<item quantity="other">A tirar uma captura de ecrã do relatório de erro dentro de <xliff:g id="NUMBER_1">%d</xliff:g> segundos.</item>
<item quantity="one">A tirar uma captura de ecrã do relatório de erro dentro de <xliff:g id="NUMBER_0">%d</xliff:g> segundo…</item>
</plurals>
- <!-- no translation found for bugreport_screenshot_success_toast (7986095104151473745) -->
- <skip />
- <!-- no translation found for bugreport_screenshot_failure_toast (6736320861311294294) -->
- <skip />
+ <string name="bugreport_screenshot_success_toast" msgid="7986095104151473745">"Captura de ecrã tirada com o relatório de erro."</string>
+ <string name="bugreport_screenshot_failure_toast" msgid="6736320861311294294">"Falha ao tirar captura de ecrã com o relatório de erro."</string>
<string name="global_action_toggle_silent_mode" msgid="8464352592860372188">"Modo silencioso"</string>
<string name="global_action_silent_mode_on_status" msgid="2371892537738632013">"Som desativado"</string>
<string name="global_action_silent_mode_off_status" msgid="6608006545950920042">"O som está ativado"</string>
@@ -454,9 +452,11 @@
<string name="permdesc_acceptHandovers" msgid="7129026180128626870">"Permite à aplicação continuar uma chamada iniciada noutra aplicação."</string>
<string name="permlab_readPhoneNumbers" msgid="5668704794723365628">"ler os números de telefone"</string>
<string name="permdesc_readPhoneNumbers" msgid="7368652482818338871">"Permite à aplicação aceder aos números de telefone do dispositivo."</string>
+ <string name="permlab_wakeLock" product="automotive" msgid="1904736682319375676">"manter o ecrã do automóvel ligado"</string>
<string name="permlab_wakeLock" product="tablet" msgid="1527660973931694000">"impedir que o tablet entre em inactividade"</string>
<string name="permlab_wakeLock" product="tv" msgid="2856941418123343518">"impedir o seu dispositivo Android TV de entrar no modo de suspensão"</string>
<string name="permlab_wakeLock" product="default" msgid="569409726861695115">"impedir modo de inactividade do telefone"</string>
+ <string name="permdesc_wakeLock" product="automotive" msgid="5995045369683254571">"Permite que a app mantenha o ecrã do automóvel ligado."</string>
<string name="permdesc_wakeLock" product="tablet" msgid="2441742939101526277">"Permite que a aplicação impeça o tablet de entrar no modo de suspensão."</string>
<string name="permdesc_wakeLock" product="tv" msgid="2329298966735118796">"Permite que a aplicação impeça o seu dispositivo Android TV de entrar no modo de suspensão."</string>
<string name="permdesc_wakeLock" product="default" msgid="3689523792074007163">"Permite que a aplicação impeça o telemóvel de entrar em inatividade."</string>
@@ -1631,6 +1631,12 @@
<string name="safe_media_volume_warning" product="default" msgid="3751676824423049994">"Aumentar o volume acima do nível recomendado?\n\nOuvir com um volume elevado durante longos períodos poderá ser prejudicial para a sua audição."</string>
<string name="accessibility_shortcut_warning_dialog_title" msgid="4017995837692622933">"Pretende utilizar o atalho de acessibilidade?"</string>
<string name="accessibility_shortcut_toogle_warning" msgid="4161716521310929544">"Quando o atalho está ativado, premir ambos os botões de volume durante 3 segundos inicia uma funcionalidade de acessibilidade."</string>
+ <!-- no translation found for accessibility_select_shortcut_menu_title (7310194076629867377) -->
+ <skip />
+ <!-- no translation found for accessibility_edit_shortcut_menu_button_title (6096484087245145325) -->
+ <skip />
+ <!-- no translation found for accessibility_edit_shortcut_menu_volume_title (4849108668454490699) -->
+ <skip />
<string name="edit_accessibility_shortcut_menu_button" msgid="8885752738733772935">"Editar atalhos"</string>
<string name="cancel_accessibility_shortcut_menu_button" msgid="1817413122335452474">"Cancelar"</string>
<string name="disable_accessibility_shortcut" msgid="5806091378745232383">"Desativar atalho"</string>
@@ -1853,8 +1859,7 @@
<string name="default_notification_channel_label" msgid="3697928973567217330">"Sem categoria"</string>
<string name="importance_from_user" msgid="2782756722448800447">"Definiu a importância destas notificações."</string>
<string name="importance_from_person" msgid="4235804979664465383">"É importante devido às pessoas envolvidas."</string>
- <!-- no translation found for notification_history_title_placeholder (7748630986182249599) -->
- <skip />
+ <string name="notification_history_title_placeholder" msgid="7748630986182249599">"Notificação de app personalizada"</string>
<string name="user_creation_account_exists" msgid="2239146360099708035">"Pretende permitir que a aplicação <xliff:g id="APP">%1$s</xliff:g> crie um novo utilizador com a conta <xliff:g id="ACCOUNT">%2$s</xliff:g> (já existe um utilizador com esta conta)?"</string>
<string name="user_creation_adding" msgid="7305185499667958364">"Pretende permitir que a aplicação <xliff:g id="APP">%1$s</xliff:g> crie um novo utilizador com a conta <xliff:g id="ACCOUNT">%2$s</xliff:g>?"</string>
<string name="language_selection_title" msgid="52674936078683285">"Adicionar um idioma"</string>
@@ -2028,14 +2033,29 @@
<string name="as_app_forced_to_restricted_bucket" msgid="8233871289353898964">"<xliff:g id="PACKAGE_NAME">%1$s</xliff:g> foi colocado no contentor RESTRITO."</string>
<string name="resolver_personal_tab" msgid="2051260504014442073">"Pessoal"</string>
<string name="resolver_work_tab" msgid="2690019516263167035">"Trabalho"</string>
+ <!-- no translation found for resolver_personal_tab_accessibility (5739524949153091224) -->
+ <skip />
+ <!-- no translation found for resolver_work_tab_accessibility (4753168230363802734) -->
+ <skip />
<string name="resolver_cant_share_with_work_apps" msgid="7539495559434146897">"Não é possível partilhar com apps de trabalho."</string>
<string name="resolver_cant_share_with_personal_apps" msgid="8020581735267157241">"Não é possível partilhar com apps pessoais."</string>
- <string name="resolver_cant_share_cross_profile_explanation" msgid="3536237105241882679">"O seu administrador de TI bloqueou a partilha entre as apps de trabalho e pessoais."</string>
- <string name="resolver_turn_on_work_apps" msgid="8987359079870455469">"Ative as apps de trabalho."</string>
- <string name="resolver_turn_on_work_apps_explanation" msgid="6322467455509618928">"Ative as apps de trabalho para aceder às apps de trabalho e aos contactos."</string>
+ <!-- no translation found for resolver_cant_share_cross_profile_explanation (5556640604460901386) -->
+ <skip />
+ <!-- no translation found for resolver_cant_access_work_apps (375634344111233790) -->
+ <skip />
+ <!-- no translation found for resolver_cant_access_work_apps_explanation (3958762224516867388) -->
+ <skip />
+ <!-- no translation found for resolver_cant_access_personal_apps (1953215925406474177) -->
+ <skip />
+ <!-- no translation found for resolver_cant_access_personal_apps_explanation (1725572276741281136) -->
+ <skip />
+ <!-- no translation found for resolver_turn_on_work_apps_share (619263911204978175) -->
+ <skip />
+ <!-- no translation found for resolver_turn_on_work_apps_view (3073389230905543680) -->
+ <skip />
<string name="resolver_no_apps_available" msgid="7710339903040989654">"Nenhuma app disponível."</string>
- <string name="resolver_no_apps_available_explanation" msgid="4662694431121196560">"Não foi possível encontrar quaisquer apps."</string>
- <string name="resolver_switch_on_work" msgid="8294542702883688533">"Ativar perfil de trabalho"</string>
+ <!-- no translation found for resolver_switch_on_work (2873009160846966379) -->
+ <skip />
<string name="permlab_accessCallAudio" msgid="1682957511874097664">"Gravar ou reproduzir áudio em chamadas telefónicas"</string>
<string name="permdesc_accessCallAudio" msgid="8448360894684277823">"Permite que esta app, quando atribuída como uma aplicação de telefone predefinida, grave ou reproduza áudio em chamadas telefónicas."</string>
</resources>
diff --git a/core/res/res/values-pt/strings.xml b/core/res/res/values-pt/strings.xml
index dfb5beff86b5..7bdfffad2d65 100644
--- a/core/res/res/values-pt/strings.xml
+++ b/core/res/res/values-pt/strings.xml
@@ -249,10 +249,8 @@
<item quantity="one">Capturas de tela para o relatório de bug serão feitas em <xliff:g id="NUMBER_1">%d</xliff:g> segundos.</item>
<item quantity="other">Capturas de tela para o relatório de bug serão feitas em <xliff:g id="NUMBER_1">%d</xliff:g> segundos.</item>
</plurals>
- <!-- no translation found for bugreport_screenshot_success_toast (7986095104151473745) -->
- <skip />
- <!-- no translation found for bugreport_screenshot_failure_toast (6736320861311294294) -->
- <skip />
+ <string name="bugreport_screenshot_success_toast" msgid="7986095104151473745">"Captura de tela com o relatório do bug concluída"</string>
+ <string name="bugreport_screenshot_failure_toast" msgid="6736320861311294294">"Falha ao capturar a tela com o relatório do bug"</string>
<string name="global_action_toggle_silent_mode" msgid="8464352592860372188">"Modo silencioso"</string>
<string name="global_action_silent_mode_on_status" msgid="2371892537738632013">"Som DESATIVADO"</string>
<string name="global_action_silent_mode_off_status" msgid="6608006545950920042">"O som está ATIVADO"</string>
@@ -454,9 +452,11 @@
<string name="permdesc_acceptHandovers" msgid="7129026180128626870">"Permite que o app continue uma chamada que foi iniciada em outro app."</string>
<string name="permlab_readPhoneNumbers" msgid="5668704794723365628">"ler números de telefone"</string>
<string name="permdesc_readPhoneNumbers" msgid="7368652482818338871">"Permite que o app acesse os número de telefone do dispositivo."</string>
+ <string name="permlab_wakeLock" product="automotive" msgid="1904736682319375676">"manter a tela do carro ativada"</string>
<string name="permlab_wakeLock" product="tablet" msgid="1527660973931694000">"impedir modo de inatividade do tablet"</string>
<string name="permlab_wakeLock" product="tv" msgid="2856941418123343518">"evitar que seu dispositivo Android TV entre no modo de suspensão"</string>
<string name="permlab_wakeLock" product="default" msgid="569409726861695115">"impedir modo de inatividade do telefone"</string>
+ <string name="permdesc_wakeLock" product="automotive" msgid="5995045369683254571">"Permite que o app mantenha a tela do carro ativada."</string>
<string name="permdesc_wakeLock" product="tablet" msgid="2441742939101526277">"Permite que o app impeça a suspensão do tablet."</string>
<string name="permdesc_wakeLock" product="tv" msgid="2329298966735118796">"Permite que o app impeça o dispositivo Android TV de entrar no modo de suspensão."</string>
<string name="permdesc_wakeLock" product="default" msgid="3689523792074007163">"Permite que o app impeça a suspensão do telefone."</string>
@@ -1631,6 +1631,12 @@
<string name="safe_media_volume_warning" product="default" msgid="3751676824423049994">"Aumentar o volume acima do nível recomendado?\n\nOuvir em volume alto por longos períodos pode danificar sua audição."</string>
<string name="accessibility_shortcut_warning_dialog_title" msgid="4017995837692622933">"Usar atalho de Acessibilidade?"</string>
<string name="accessibility_shortcut_toogle_warning" msgid="4161716521310929544">"Quando o atalho estiver ativado, pressione os dois botões de volume por três segundos para iniciar um recurso de acessibilidade."</string>
+ <!-- no translation found for accessibility_select_shortcut_menu_title (7310194076629867377) -->
+ <skip />
+ <!-- no translation found for accessibility_edit_shortcut_menu_button_title (6096484087245145325) -->
+ <skip />
+ <!-- no translation found for accessibility_edit_shortcut_menu_volume_title (4849108668454490699) -->
+ <skip />
<string name="edit_accessibility_shortcut_menu_button" msgid="8885752738733772935">"Editar atalhos"</string>
<string name="cancel_accessibility_shortcut_menu_button" msgid="1817413122335452474">"Cancelar"</string>
<string name="disable_accessibility_shortcut" msgid="5806091378745232383">"Desativar atalho"</string>
@@ -1853,8 +1859,7 @@
<string name="default_notification_channel_label" msgid="3697928973567217330">"Sem classificação"</string>
<string name="importance_from_user" msgid="2782756722448800447">"Você definiu a importância dessas notificações."</string>
<string name="importance_from_person" msgid="4235804979664465383">"Isso é importante por causa das pessoas envolvidas."</string>
- <!-- no translation found for notification_history_title_placeholder (7748630986182249599) -->
- <skip />
+ <string name="notification_history_title_placeholder" msgid="7748630986182249599">"Notificação personalizada do app"</string>
<string name="user_creation_account_exists" msgid="2239146360099708035">"Permitir que o app <xliff:g id="APP">%1$s</xliff:g> crie um novo usuário com <xliff:g id="ACCOUNT">%2$s</xliff:g> (já existe um usuário com essa conta)?"</string>
<string name="user_creation_adding" msgid="7305185499667958364">"Permitir que o app <xliff:g id="APP">%1$s</xliff:g> crie um novo usuário com <xliff:g id="ACCOUNT">%2$s</xliff:g>?"</string>
<string name="language_selection_title" msgid="52674936078683285">"Adicionar um idioma"</string>
@@ -2028,14 +2033,29 @@
<string name="as_app_forced_to_restricted_bucket" msgid="8233871289353898964">"<xliff:g id="PACKAGE_NAME">%1$s</xliff:g> foi colocado no intervalo \"RESTRITO\""</string>
<string name="resolver_personal_tab" msgid="2051260504014442073">"Pessoal"</string>
<string name="resolver_work_tab" msgid="2690019516263167035">"Trabalho"</string>
+ <!-- no translation found for resolver_personal_tab_accessibility (5739524949153091224) -->
+ <skip />
+ <!-- no translation found for resolver_work_tab_accessibility (4753168230363802734) -->
+ <skip />
<string name="resolver_cant_share_with_work_apps" msgid="7539495559434146897">"Não é possível compartilhar com apps de trabalho"</string>
<string name="resolver_cant_share_with_personal_apps" msgid="8020581735267157241">"Não é possível compartilhar com apps pessoais"</string>
- <string name="resolver_cant_share_cross_profile_explanation" msgid="3536237105241882679">"Seu administrador de TI bloqueou o compartilhamento entre apps pessoais e de trabalho"</string>
- <string name="resolver_turn_on_work_apps" msgid="8987359079870455469">"Ativar apps de trabalho"</string>
- <string name="resolver_turn_on_work_apps_explanation" msgid="6322467455509618928">"Ative os apps de trabalho para acessar apps e contatos profissionais"</string>
+ <!-- no translation found for resolver_cant_share_cross_profile_explanation (5556640604460901386) -->
+ <skip />
+ <!-- no translation found for resolver_cant_access_work_apps (375634344111233790) -->
+ <skip />
+ <!-- no translation found for resolver_cant_access_work_apps_explanation (3958762224516867388) -->
+ <skip />
+ <!-- no translation found for resolver_cant_access_personal_apps (1953215925406474177) -->
+ <skip />
+ <!-- no translation found for resolver_cant_access_personal_apps_explanation (1725572276741281136) -->
+ <skip />
+ <!-- no translation found for resolver_turn_on_work_apps_share (619263911204978175) -->
+ <skip />
+ <!-- no translation found for resolver_turn_on_work_apps_view (3073389230905543680) -->
+ <skip />
<string name="resolver_no_apps_available" msgid="7710339903040989654">"Nenhum app disponível"</string>
- <string name="resolver_no_apps_available_explanation" msgid="4662694431121196560">"Não foi possível encontrar nenhum app"</string>
- <string name="resolver_switch_on_work" msgid="8294542702883688533">"Ativar perfil de trabalho"</string>
+ <!-- no translation found for resolver_switch_on_work (2873009160846966379) -->
+ <skip />
<string name="permlab_accessCallAudio" msgid="1682957511874097664">"Gravar ou tocar áudio em chamadas telefônicas"</string>
<string name="permdesc_accessCallAudio" msgid="8448360894684277823">"Permitir que esse app grave ou toque áudio em chamadas telefônicas quando for usado como aplicativo discador padrão."</string>
</resources>
diff --git a/core/res/res/values-ro/strings.xml b/core/res/res/values-ro/strings.xml
index e4eaf803c5ab..e4892493e921 100644
--- a/core/res/res/values-ro/strings.xml
+++ b/core/res/res/values-ro/strings.xml
@@ -252,10 +252,8 @@
<item quantity="other">Peste <xliff:g id="NUMBER_1">%d</xliff:g> de secunde se va realiza o captură de ecran pentru raportul de eroare.</item>
<item quantity="one">Peste <xliff:g id="NUMBER_0">%d</xliff:g> secundă se va realiza o captură de ecran pentru raportul de eroare.</item>
</plurals>
- <!-- no translation found for bugreport_screenshot_success_toast (7986095104151473745) -->
- <skip />
- <!-- no translation found for bugreport_screenshot_failure_toast (6736320861311294294) -->
- <skip />
+ <string name="bugreport_screenshot_success_toast" msgid="7986095104151473745">"S-a realizat captura de ecran a raportului de eroare"</string>
+ <string name="bugreport_screenshot_failure_toast" msgid="6736320861311294294">"Nu s-a realizat captura de ecran a raportului de eroare"</string>
<string name="global_action_toggle_silent_mode" msgid="8464352592860372188">"Mod Silențios"</string>
<string name="global_action_silent_mode_on_status" msgid="2371892537738632013">"Sunetul este DEZACTIVAT"</string>
<string name="global_action_silent_mode_off_status" msgid="6608006545950920042">"Sunetul este ACTIVAT"</string>
@@ -457,9 +455,11 @@
<string name="permdesc_acceptHandovers" msgid="7129026180128626870">"Permite aplicației să continue un apel care a fost inițiat dintr-o altă aplicație."</string>
<string name="permlab_readPhoneNumbers" msgid="5668704794723365628">"să citească numerele de telefon"</string>
<string name="permdesc_readPhoneNumbers" msgid="7368652482818338871">"Permite aplicației să acceseze numerele de telefon ale dispozitivului."</string>
+ <string name="permlab_wakeLock" product="automotive" msgid="1904736682319375676">"menține ecranul mașinii activat"</string>
<string name="permlab_wakeLock" product="tablet" msgid="1527660973931694000">"împiedicarea computerului tablet PC să intre în repaus"</string>
<string name="permlab_wakeLock" product="tv" msgid="2856941418123343518">"împiedică dispozitivul Android TV să intre în repaus"</string>
<string name="permlab_wakeLock" product="default" msgid="569409726861695115">"împiedicare intrare telefon în repaus"</string>
+ <string name="permdesc_wakeLock" product="automotive" msgid="5995045369683254571">"Permite aplicației să mențină ecranul mașinii activat."</string>
<string name="permdesc_wakeLock" product="tablet" msgid="2441742939101526277">"Permite aplicației să împiedice intrarea tabletei în stare de repaus."</string>
<string name="permdesc_wakeLock" product="tv" msgid="2329298966735118796">"Permite aplicației să împiedice intrarea dispozitivului Android TV în stare de inactivitate."</string>
<string name="permdesc_wakeLock" product="default" msgid="3689523792074007163">"Permite aplicației să împiedice intrarea telefonului în stare de repaus."</string>
@@ -1653,6 +1653,12 @@
<string name="safe_media_volume_warning" product="default" msgid="3751676824423049994">"Ridicați volumul mai sus de nivelul recomandat?\n\nAscultarea la volum ridicat pe perioade lungi de timp vă poate afecta auzul."</string>
<string name="accessibility_shortcut_warning_dialog_title" msgid="4017995837692622933">"Utilizați comanda rapidă pentru accesibilitate?"</string>
<string name="accessibility_shortcut_toogle_warning" msgid="4161716521310929544">"Atunci când comanda rapidă este activată, dacă apăsați ambele butoane de volum timp de trei secunde, veți lansa o funcție de accesibilitate."</string>
+ <!-- no translation found for accessibility_select_shortcut_menu_title (7310194076629867377) -->
+ <skip />
+ <!-- no translation found for accessibility_edit_shortcut_menu_button_title (6096484087245145325) -->
+ <skip />
+ <!-- no translation found for accessibility_edit_shortcut_menu_volume_title (4849108668454490699) -->
+ <skip />
<string name="edit_accessibility_shortcut_menu_button" msgid="8885752738733772935">"Editați comenzile rapide"</string>
<string name="cancel_accessibility_shortcut_menu_button" msgid="1817413122335452474">"Anulați"</string>
<string name="disable_accessibility_shortcut" msgid="5806091378745232383">"Dezactivați comanda rapidă"</string>
@@ -1885,8 +1891,7 @@
<string name="default_notification_channel_label" msgid="3697928973567217330">"Neclasificate"</string>
<string name="importance_from_user" msgid="2782756722448800447">"Dvs. setați importanța acestor notificări."</string>
<string name="importance_from_person" msgid="4235804979664465383">"Notificarea este importantă având în vedere persoanele implicate."</string>
- <!-- no translation found for notification_history_title_placeholder (7748630986182249599) -->
- <skip />
+ <string name="notification_history_title_placeholder" msgid="7748630986182249599">"Notificare de aplicație personalizată"</string>
<string name="user_creation_account_exists" msgid="2239146360099708035">"Permiteți ca <xliff:g id="APP">%1$s</xliff:g> să creeze un nou utilizator folosind <xliff:g id="ACCOUNT">%2$s</xliff:g>? (există deja un utilizator cu acest cont)"</string>
<string name="user_creation_adding" msgid="7305185499667958364">"Permiteți ca <xliff:g id="APP">%1$s</xliff:g> să creeze un nou utilizator folosind <xliff:g id="ACCOUNT">%2$s</xliff:g>?"</string>
<string name="language_selection_title" msgid="52674936078683285">"Adăugați o limbă"</string>
@@ -2062,14 +2067,29 @@
<string name="as_app_forced_to_restricted_bucket" msgid="8233871289353898964">"<xliff:g id="PACKAGE_NAME">%1$s</xliff:g> a fost adăugat la grupul RESTRICȚIONATE"</string>
<string name="resolver_personal_tab" msgid="2051260504014442073">"Personal"</string>
<string name="resolver_work_tab" msgid="2690019516263167035">"Serviciu"</string>
+ <!-- no translation found for resolver_personal_tab_accessibility (5739524949153091224) -->
+ <skip />
+ <!-- no translation found for resolver_work_tab_accessibility (4753168230363802734) -->
+ <skip />
<string name="resolver_cant_share_with_work_apps" msgid="7539495559434146897">"Nu se poate trimite către aplicații pentru lucru"</string>
<string name="resolver_cant_share_with_personal_apps" msgid="8020581735267157241">"Nu se poate trimite către aplicații personale"</string>
- <string name="resolver_cant_share_cross_profile_explanation" msgid="3536237105241882679">"Administratorul IT a blocat trimiterea între aplicațiile personale și pentru lucru"</string>
- <string name="resolver_turn_on_work_apps" msgid="8987359079870455469">"Activați aplicațiile pentru lucru"</string>
- <string name="resolver_turn_on_work_apps_explanation" msgid="6322467455509618928">"Activați aplicațiile pentru lucru ca să le accesați pe acestea și persoanele de contact"</string>
+ <!-- no translation found for resolver_cant_share_cross_profile_explanation (5556640604460901386) -->
+ <skip />
+ <!-- no translation found for resolver_cant_access_work_apps (375634344111233790) -->
+ <skip />
+ <!-- no translation found for resolver_cant_access_work_apps_explanation (3958762224516867388) -->
+ <skip />
+ <!-- no translation found for resolver_cant_access_personal_apps (1953215925406474177) -->
+ <skip />
+ <!-- no translation found for resolver_cant_access_personal_apps_explanation (1725572276741281136) -->
+ <skip />
+ <!-- no translation found for resolver_turn_on_work_apps_share (619263911204978175) -->
+ <skip />
+ <!-- no translation found for resolver_turn_on_work_apps_view (3073389230905543680) -->
+ <skip />
<string name="resolver_no_apps_available" msgid="7710339903040989654">"Nicio aplicație disponibilă"</string>
- <string name="resolver_no_apps_available_explanation" msgid="4662694431121196560">"Nu s-a găsit nicio aplicație"</string>
- <string name="resolver_switch_on_work" msgid="8294542702883688533">"Comutați la profilul de lucru"</string>
+ <!-- no translation found for resolver_switch_on_work (2873009160846966379) -->
+ <skip />
<string name="permlab_accessCallAudio" msgid="1682957511874097664">"Înregistrează sau redă conținut audio în apelurile telefonice"</string>
<string name="permdesc_accessCallAudio" msgid="8448360894684277823">"Permite acestei aplicații, atunci când este setată ca aplicație telefon prestabilită, să înregistreze sau să redea conținut audio în apelurile telefonice."</string>
</resources>
diff --git a/core/res/res/values-ru/strings.xml b/core/res/res/values-ru/strings.xml
index 7cd16332740d..7abf646c97df 100644
--- a/core/res/res/values-ru/strings.xml
+++ b/core/res/res/values-ru/strings.xml
@@ -255,10 +255,8 @@
<item quantity="many">Скриншот будет сделан через <xliff:g id="NUMBER_1">%d</xliff:g> секунд</item>
<item quantity="other">Скриншот будет сделан через <xliff:g id="NUMBER_1">%d</xliff:g> секунды</item>
</plurals>
- <!-- no translation found for bugreport_screenshot_success_toast (7986095104151473745) -->
- <skip />
- <!-- no translation found for bugreport_screenshot_failure_toast (6736320861311294294) -->
- <skip />
+ <string name="bugreport_screenshot_success_toast" msgid="7986095104151473745">"Сделан скриншот с информацией об ошибке."</string>
+ <string name="bugreport_screenshot_failure_toast" msgid="6736320861311294294">"Не удалось сделать скриншот с информацией об ошибке."</string>
<string name="global_action_toggle_silent_mode" msgid="8464352592860372188">"Режим без звука"</string>
<string name="global_action_silent_mode_on_status" msgid="2371892537738632013">"Выключить"</string>
<string name="global_action_silent_mode_off_status" msgid="6608006545950920042">"Включить"</string>
@@ -460,9 +458,11 @@
<string name="permdesc_acceptHandovers" msgid="7129026180128626870">"Разрешает приложению продолжить вызов, начатый в другом приложении."</string>
<string name="permlab_readPhoneNumbers" msgid="5668704794723365628">"чтение номеров телефонов"</string>
<string name="permdesc_readPhoneNumbers" msgid="7368652482818338871">"Разрешает приложению доступ к телефонным номерам устройства."</string>
+ <string name="permlab_wakeLock" product="automotive" msgid="1904736682319375676">"Не выключать экран автомобиля"</string>
<string name="permlab_wakeLock" product="tablet" msgid="1527660973931694000">"Отключение спящего режима"</string>
<string name="permlab_wakeLock" product="tv" msgid="2856941418123343518">"запрещать переход устройства Android TV в спящий режим"</string>
<string name="permlab_wakeLock" product="default" msgid="569409726861695115">"Отключение спящего режима"</string>
+ <string name="permdesc_wakeLock" product="automotive" msgid="5995045369683254571">"Приложение сможет держать экран автомобиля включенным."</string>
<string name="permdesc_wakeLock" product="tablet" msgid="2441742939101526277">"Приложение сможет запрещать перевод планшетного ПК в спящий режим."</string>
<string name="permdesc_wakeLock" product="tv" msgid="2329298966735118796">"Приложение сможет препятствовать переводу устройства Android TV в спящий режим."</string>
<string name="permdesc_wakeLock" product="default" msgid="3689523792074007163">"Приложение сможет запрещать перевод телефона в спящий режим."</string>
@@ -1675,6 +1675,12 @@
<string name="safe_media_volume_warning" product="default" msgid="3751676824423049994">"Установить громкость выше рекомендуемого уровня?\n\nВоздействие громкого звука в течение долгого времени может привести к повреждению слуха."</string>
<string name="accessibility_shortcut_warning_dialog_title" msgid="4017995837692622933">"Использовать быстрое включение?"</string>
<string name="accessibility_shortcut_toogle_warning" msgid="4161716521310929544">"Чтобы использовать функцию специальных возможностей, когда она включена, нажмите и удерживайте обе кнопки регулировки громкости в течение трех секунд."</string>
+ <!-- no translation found for accessibility_select_shortcut_menu_title (7310194076629867377) -->
+ <skip />
+ <!-- no translation found for accessibility_edit_shortcut_menu_button_title (6096484087245145325) -->
+ <skip />
+ <!-- no translation found for accessibility_edit_shortcut_menu_volume_title (4849108668454490699) -->
+ <skip />
<string name="edit_accessibility_shortcut_menu_button" msgid="8885752738733772935">"Изменить быстрые клавиши"</string>
<string name="cancel_accessibility_shortcut_menu_button" msgid="1817413122335452474">"Отмена"</string>
<string name="disable_accessibility_shortcut" msgid="5806091378745232383">"Деактивировать быстрое включение"</string>
@@ -1917,8 +1923,7 @@
<string name="default_notification_channel_label" msgid="3697928973567217330">"Без категории"</string>
<string name="importance_from_user" msgid="2782756722448800447">"Вы определяете важность этих уведомлений."</string>
<string name="importance_from_person" msgid="4235804979664465383">"Важное (люди)"</string>
- <!-- no translation found for notification_history_title_placeholder (7748630986182249599) -->
- <skip />
+ <string name="notification_history_title_placeholder" msgid="7748630986182249599">"Уведомление пользовательского приложения"</string>
<string name="user_creation_account_exists" msgid="2239146360099708035">"Разрешить приложению \"<xliff:g id="APP">%1$s</xliff:g>\" создать нового пользователя с аккаунтом <xliff:g id="ACCOUNT">%2$s</xliff:g> (пользователь с этим аккаунтом уже существует)?"</string>
<string name="user_creation_adding" msgid="7305185499667958364">"Разрешить приложению \"<xliff:g id="APP">%1$s</xliff:g>\" создать нового пользователя с аккаунтом <xliff:g id="ACCOUNT">%2$s</xliff:g>?"</string>
<string name="language_selection_title" msgid="52674936078683285">"Добавьте язык"</string>
@@ -2096,14 +2101,29 @@
<string name="as_app_forced_to_restricted_bucket" msgid="8233871289353898964">"Приложение \"<xliff:g id="PACKAGE_NAME">%1$s</xliff:g>\" помещено в категорию с ограниченным доступом."</string>
<string name="resolver_personal_tab" msgid="2051260504014442073">"Личный"</string>
<string name="resolver_work_tab" msgid="2690019516263167035">"Рабочий"</string>
+ <!-- no translation found for resolver_personal_tab_accessibility (5739524949153091224) -->
+ <skip />
+ <!-- no translation found for resolver_work_tab_accessibility (4753168230363802734) -->
+ <skip />
<string name="resolver_cant_share_with_work_apps" msgid="7539495559434146897">"Нельзя обмениваться данными с рабочими приложениями"</string>
<string name="resolver_cant_share_with_personal_apps" msgid="8020581735267157241">"Нельзя обмениваться данными с личными приложениями"</string>
- <string name="resolver_cant_share_cross_profile_explanation" msgid="3536237105241882679">"Обмен данными между личными и рабочими приложениями заблокирован системным администратором."</string>
- <string name="resolver_turn_on_work_apps" msgid="8987359079870455469">"Включите рабочие приложения"</string>
- <string name="resolver_turn_on_work_apps_explanation" msgid="6322467455509618928">"Включите рабочие приложения, чтобы получить доступ к ним и контактам."</string>
+ <!-- no translation found for resolver_cant_share_cross_profile_explanation (5556640604460901386) -->
+ <skip />
+ <!-- no translation found for resolver_cant_access_work_apps (375634344111233790) -->
+ <skip />
+ <!-- no translation found for resolver_cant_access_work_apps_explanation (3958762224516867388) -->
+ <skip />
+ <!-- no translation found for resolver_cant_access_personal_apps (1953215925406474177) -->
+ <skip />
+ <!-- no translation found for resolver_cant_access_personal_apps_explanation (1725572276741281136) -->
+ <skip />
+ <!-- no translation found for resolver_turn_on_work_apps_share (619263911204978175) -->
+ <skip />
+ <!-- no translation found for resolver_turn_on_work_apps_view (3073389230905543680) -->
+ <skip />
<string name="resolver_no_apps_available" msgid="7710339903040989654">"Нет доступных приложений"</string>
- <string name="resolver_no_apps_available_explanation" msgid="4662694431121196560">"Приложения не найдены."</string>
- <string name="resolver_switch_on_work" msgid="8294542702883688533">"Включить рабочий профиль"</string>
+ <!-- no translation found for resolver_switch_on_work (2873009160846966379) -->
+ <skip />
<string name="permlab_accessCallAudio" msgid="1682957511874097664">"Запись и воспроизведение телефонных разговоров"</string>
<string name="permdesc_accessCallAudio" msgid="8448360894684277823">"Если это приложение используется для звонков по умолчанию, оно сможет записывать и воспроизводить телефонные разговоры."</string>
</resources>
diff --git a/core/res/res/values-si/strings.xml b/core/res/res/values-si/strings.xml
index 37db789d1c32..67f1ca1bee83 100644
--- a/core/res/res/values-si/strings.xml
+++ b/core/res/res/values-si/strings.xml
@@ -249,10 +249,8 @@
<item quantity="one">තත්පර <xliff:g id="NUMBER_1">%d</xliff:g>කින් දෝෂ වාර්තාව සඳහා තිර රුවක් ලබා ගනිමින්</item>
<item quantity="other">තත්පර <xliff:g id="NUMBER_1">%d</xliff:g>කින් දෝෂ වාර්තාව සඳහා තිර රුවක් ලබා ගනිමින්</item>
</plurals>
- <!-- no translation found for bugreport_screenshot_success_toast (7986095104151473745) -->
- <skip />
- <!-- no translation found for bugreport_screenshot_failure_toast (6736320861311294294) -->
- <skip />
+ <string name="bugreport_screenshot_success_toast" msgid="7986095104151473745">"දෝෂ වාර්තාව සමගින් ගත් තිර රුව"</string>
+ <string name="bugreport_screenshot_failure_toast" msgid="6736320861311294294">"දෝෂ වාර්තාව සමගින් තිර රුව ගැනීමට අසමත් විය"</string>
<string name="global_action_toggle_silent_mode" msgid="8464352592860372188">"නිහඬ ආකාරය"</string>
<string name="global_action_silent_mode_on_status" msgid="2371892537738632013">"ශබ්දය අක්‍රියයි"</string>
<string name="global_action_silent_mode_off_status" msgid="6608006545950920042">"හඬ ක්‍රියාත්මකයි"</string>
@@ -454,9 +452,11 @@
<string name="permdesc_acceptHandovers" msgid="7129026180128626870">"වෙනත් යෙදුමක ආරම්භ කරන ලද ඇමතුමක් දිගටම කරගෙන යාමට යෙදුමට ඉඩ දෙයි."</string>
<string name="permlab_readPhoneNumbers" msgid="5668704794723365628">"දුරකථන අංක කියවන්න"</string>
<string name="permdesc_readPhoneNumbers" msgid="7368652482818338871">"උපාංගයේ දුරකථන අංක වෙත ප්‍රවේශයට යෙදුමට ඉඩ දෙයි."</string>
+ <string name="permlab_wakeLock" product="automotive" msgid="1904736682319375676">"මෝටර් රථ තිරය ක්‍රියාත්මකව තබා ගන්න"</string>
<string name="permlab_wakeLock" product="tablet" msgid="1527660973931694000">"ටැබ්ලටය නින්දෙන් වැළක්වීම"</string>
<string name="permlab_wakeLock" product="tv" msgid="2856941418123343518">"ඔබගේ Android TV උපාංගය නිදා ගැනීමෙන් වැළැක්වීම"</string>
<string name="permlab_wakeLock" product="default" msgid="569409726861695115">"දුරකථනය නින්දට යාමෙන් වළකන්න"</string>
+ <string name="permdesc_wakeLock" product="automotive" msgid="5995045369683254571">"යෙදුමට මෝටර් රථ තිරය ක්‍රියාත්මකව තබා ගැනීමට ඉඩ දෙයි."</string>
<string name="permdesc_wakeLock" product="tablet" msgid="2441742939101526277">"ටැබ්ලටය නින්දට යාමෙන් වැලැක්වීමට යෙදුමට අවසර දෙන්න."</string>
<string name="permdesc_wakeLock" product="tv" msgid="2329298966735118796">"යෙදුමට ඔබේ Android TV උපාංගය නින්දට යාමට වැළැක්වීමට ඉඩ දෙයි."</string>
<string name="permdesc_wakeLock" product="default" msgid="3689523792074007163">"දුරකථනය නින්දට යාමෙන් වැලැක්වීමට යෙදුමට අවසර දෙන්න."</string>
@@ -1633,6 +1633,12 @@
<string name="safe_media_volume_warning" product="default" msgid="3751676824423049994">"නිර්දේශිතයි මට්ටමට වඩා ශබ්දය වැඩිද?\n\nදිගු කාලයක් සඳහා ඉහළ ශබ්දයක් ඇසීමෙන් ඇතැම් විට ඔබගේ ඇසීමට හානි විය හැක."</string>
<string name="accessibility_shortcut_warning_dialog_title" msgid="4017995837692622933">"ප්‍රවේශ්‍යතා කෙටිමඟ භාවිතා කරන්නද?"</string>
<string name="accessibility_shortcut_toogle_warning" msgid="4161716521310929544">"කෙටිමග ක්‍රියාත්මක විට, හඬ පරිමා බොත්තම් දෙකම තත්පර 3ක් තිස්සේ එබීමෙන් ප්‍රවේශ්‍යතා විශේෂාංගය ආරම්භ වනු ඇත."</string>
+ <!-- no translation found for accessibility_select_shortcut_menu_title (7310194076629867377) -->
+ <skip />
+ <!-- no translation found for accessibility_edit_shortcut_menu_button_title (6096484087245145325) -->
+ <skip />
+ <!-- no translation found for accessibility_edit_shortcut_menu_volume_title (4849108668454490699) -->
+ <skip />
<string name="edit_accessibility_shortcut_menu_button" msgid="8885752738733772935">"කෙටිමං සංස්කරණ කරන්න"</string>
<string name="cancel_accessibility_shortcut_menu_button" msgid="1817413122335452474">"අවලංගු කරන්න"</string>
<string name="disable_accessibility_shortcut" msgid="5806091378745232383">"කෙටිමඟ ක්‍රියාවිරහිත කරන්න"</string>
@@ -1855,8 +1861,7 @@
<string name="default_notification_channel_label" msgid="3697928973567217330">"වර්ගීකරණය නොකළ"</string>
<string name="importance_from_user" msgid="2782756722448800447">"ඔබ මෙම දැනුම්දීම්වල වැදගත්කම සකසා ඇත."</string>
<string name="importance_from_person" msgid="4235804979664465383">"සම්බන්ධ වූ පුද්ගලයන් නිසා මෙය වැදගත් වේ."</string>
- <!-- no translation found for notification_history_title_placeholder (7748630986182249599) -->
- <skip />
+ <string name="notification_history_title_placeholder" msgid="7748630986182249599">"අභිරුචි යෙදුම් දැනුම් දීම"</string>
<string name="user_creation_account_exists" msgid="2239146360099708035">"<xliff:g id="APP">%1$s</xliff:g> හට <xliff:g id="ACCOUNT">%2$s</xliff:g> සමගින් නව පරිශීලකයෙකු සෑදීමට ඉඩ දෙන්නද (මෙම ගිණුම සහිත පරිශීලකයෙකු දැනටමත් සිටී) ?"</string>
<string name="user_creation_adding" msgid="7305185499667958364">"<xliff:g id="APP">%1$s</xliff:g> හට <xliff:g id="ACCOUNT">%2$s</xliff:g> සමගින් නව පරිශීලකයෙකු සෑදීමට ඉඩ දෙන්නද ?"</string>
<string name="language_selection_title" msgid="52674936078683285">"භාෂාවක් එක් කරන්න"</string>
@@ -2030,14 +2035,29 @@
<string name="as_app_forced_to_restricted_bucket" msgid="8233871289353898964">"<xliff:g id="PACKAGE_NAME">%1$s</xliff:g> අවහිර කළ බාල්දියට දමා ඇත"</string>
<string name="resolver_personal_tab" msgid="2051260504014442073">"පුද්ගලික"</string>
<string name="resolver_work_tab" msgid="2690019516263167035">"කාර්යාල"</string>
+ <!-- no translation found for resolver_personal_tab_accessibility (5739524949153091224) -->
+ <skip />
+ <!-- no translation found for resolver_work_tab_accessibility (4753168230363802734) -->
+ <skip />
<string name="resolver_cant_share_with_work_apps" msgid="7539495559434146897">"කාර්යාල යෙදුම් සමග බෙදා ගැනීමට නොහැකිය"</string>
<string name="resolver_cant_share_with_personal_apps" msgid="8020581735267157241">"පෞද්ගලික යෙදුම් සමග බෙදා ගැනීමට නොහැකිය"</string>
- <string name="resolver_cant_share_cross_profile_explanation" msgid="3536237105241882679">"ඔබේ IT පරිපාලක පෞද්ගලික සහ කාර්යාල යෙදුම් අතර බෙදා ගැනීම අවහිර කළා"</string>
- <string name="resolver_turn_on_work_apps" msgid="8987359079870455469">"කාර්යාල යෙදුම් ක්‍රියාත්මක කරන්න"</string>
- <string name="resolver_turn_on_work_apps_explanation" msgid="6322467455509618928">"කාර්යාල යෙදුම් &amp; සම්බන්ධතා වෙත ප්‍රවේශ වීමට කාර්යාල යෙදුම් ක්‍රියාත්මක කරන්න"</string>
+ <!-- no translation found for resolver_cant_share_cross_profile_explanation (5556640604460901386) -->
+ <skip />
+ <!-- no translation found for resolver_cant_access_work_apps (375634344111233790) -->
+ <skip />
+ <!-- no translation found for resolver_cant_access_work_apps_explanation (3958762224516867388) -->
+ <skip />
+ <!-- no translation found for resolver_cant_access_personal_apps (1953215925406474177) -->
+ <skip />
+ <!-- no translation found for resolver_cant_access_personal_apps_explanation (1725572276741281136) -->
+ <skip />
+ <!-- no translation found for resolver_turn_on_work_apps_share (619263911204978175) -->
+ <skip />
+ <!-- no translation found for resolver_turn_on_work_apps_view (3073389230905543680) -->
+ <skip />
<string name="resolver_no_apps_available" msgid="7710339903040989654">"ලබා ගත හැකි යෙදුම් නැත"</string>
- <string name="resolver_no_apps_available_explanation" msgid="4662694431121196560">"අපට කිසිදු යෙදුමක් සොයා ගැනීමට නොහැකි විය"</string>
- <string name="resolver_switch_on_work" msgid="8294542702883688533">"කාර්යාලයට මාරු කරන්න"</string>
+ <!-- no translation found for resolver_switch_on_work (2873009160846966379) -->
+ <skip />
<string name="permlab_accessCallAudio" msgid="1682957511874097664">"ටෙලිෆොනි ඇමතුම්වලින් ඕඩියෝ පටිගත කරන්න නැතහොත් වාදනය කරන්න"</string>
<string name="permdesc_accessCallAudio" msgid="8448360894684277823">"පෙරනිමි ඩයලන යෙදුමක් ලෙස පැවරූ විට, මෙම යෙදුමට ටෙලිෆොනි ඇමතුම්වලින් ඕඩියෝ පටිගත කිරීමට හෝ වාදනය කිරීමට ඉඩ දෙයි."</string>
</resources>
diff --git a/core/res/res/values-sk/strings.xml b/core/res/res/values-sk/strings.xml
index 3be2f09bb621..de9175d0a0fd 100644
--- a/core/res/res/values-sk/strings.xml
+++ b/core/res/res/values-sk/strings.xml
@@ -255,10 +255,8 @@
<item quantity="other">Snímka obrazovky pre hlásenie chyby sa vytvorí o <xliff:g id="NUMBER_1">%d</xliff:g> sekúnd.</item>
<item quantity="one">Snímka obrazovky pre hlásenie chyby sa vytvorí o <xliff:g id="NUMBER_0">%d</xliff:g> sekundu.</item>
</plurals>
- <!-- no translation found for bugreport_screenshot_success_toast (7986095104151473745) -->
- <skip />
- <!-- no translation found for bugreport_screenshot_failure_toast (6736320861311294294) -->
- <skip />
+ <string name="bugreport_screenshot_success_toast" msgid="7986095104151473745">"Bola vytvorená snímka obrazovky s hlásením chyby"</string>
+ <string name="bugreport_screenshot_failure_toast" msgid="6736320861311294294">"Nepodarilo sa vytvoriť snímku obrazovky s hlásením chyby"</string>
<string name="global_action_toggle_silent_mode" msgid="8464352592860372188">"Tichý režim"</string>
<string name="global_action_silent_mode_on_status" msgid="2371892537738632013">"Zvuk je VYPNUTÝ."</string>
<string name="global_action_silent_mode_off_status" msgid="6608006545950920042">"Zvuk je zapnutý"</string>
@@ -460,9 +458,11 @@
<string name="permdesc_acceptHandovers" msgid="7129026180128626870">"Umožňuje aplikácii pokračovať v hovore začatom v inej aplikácii."</string>
<string name="permlab_readPhoneNumbers" msgid="5668704794723365628">"čítanie telefónnych čísel"</string>
<string name="permdesc_readPhoneNumbers" msgid="7368652482818338871">"Umožňuje aplikácii pristupovať k telefónnym číslam zariadenia."</string>
+ <string name="permlab_wakeLock" product="automotive" msgid="1904736682319375676">"zabránenie vypnutiu obrazovky auta"</string>
<string name="permlab_wakeLock" product="tablet" msgid="1527660973931694000">"zabránenie prechodu tabletu do režimu spánku"</string>
<string name="permlab_wakeLock" product="tv" msgid="2856941418123343518">"zabránenie prechodu zariadenia Android TV do režimu spánku"</string>
<string name="permlab_wakeLock" product="default" msgid="569409726861695115">"deaktivovať režim spánku"</string>
+ <string name="permdesc_wakeLock" product="automotive" msgid="5995045369683254571">"Umožňuje aplikácii zabrániť vypnutiu obrazovky auta."</string>
<string name="permdesc_wakeLock" product="tablet" msgid="2441742939101526277">"Umožňuje aplikácii zabrániť prechodu tabletu do režimu spánku."</string>
<string name="permdesc_wakeLock" product="tv" msgid="2329298966735118796">"Umožňuje aplikácii zabrániť prechodu zariadenia Android TV do režimu spánku."</string>
<string name="permdesc_wakeLock" product="default" msgid="3689523792074007163">"Umožňuje aplikácii zabrániť prechodu telefónu do režimu spánku."</string>
@@ -1675,6 +1675,12 @@
<string name="safe_media_volume_warning" product="default" msgid="3751676824423049994">"Zvýšiť hlasitosť nad odporúčanú úroveň?\n\nDlhodobé počúvanie pri vysokej hlasitosti môže poškodiť váš sluch."</string>
<string name="accessibility_shortcut_warning_dialog_title" msgid="4017995837692622933">"Použiť skratku dostupnosti?"</string>
<string name="accessibility_shortcut_toogle_warning" msgid="4161716521310929544">"Keď je skratka zapnutá, stlačením obidvoch tlačidiel hlasitosti na tri sekundy spustíte funkciu dostupnosti."</string>
+ <!-- no translation found for accessibility_select_shortcut_menu_title (7310194076629867377) -->
+ <skip />
+ <!-- no translation found for accessibility_edit_shortcut_menu_button_title (6096484087245145325) -->
+ <skip />
+ <!-- no translation found for accessibility_edit_shortcut_menu_volume_title (4849108668454490699) -->
+ <skip />
<string name="edit_accessibility_shortcut_menu_button" msgid="8885752738733772935">"Upraviť skratky"</string>
<string name="cancel_accessibility_shortcut_menu_button" msgid="1817413122335452474">"Zrušiť"</string>
<string name="disable_accessibility_shortcut" msgid="5806091378745232383">"Vypnúť skratku"</string>
@@ -1917,8 +1923,7 @@
<string name="default_notification_channel_label" msgid="3697928973567217330">"Nekategorizované"</string>
<string name="importance_from_user" msgid="2782756722448800447">"Nastavili ste dôležitosť týchto upozornení."</string>
<string name="importance_from_person" msgid="4235804979664465383">"Táto správa je dôležitá vzhľadom na osoby, ktorých sa to týka."</string>
- <!-- no translation found for notification_history_title_placeholder (7748630986182249599) -->
- <skip />
+ <string name="notification_history_title_placeholder" msgid="7748630986182249599">"Vlastné upozornenie na aplikáciu"</string>
<string name="user_creation_account_exists" msgid="2239146360099708035">"Chcete povoliť aplikácii <xliff:g id="APP">%1$s</xliff:g> vytvoriť nového používateľa pomocou účtu <xliff:g id="ACCOUNT">%2$s</xliff:g> (používateľ s týmto účtom už existuje)?"</string>
<string name="user_creation_adding" msgid="7305185499667958364">"Chcete povoliť aplikácii <xliff:g id="APP">%1$s</xliff:g> vytvoriť nového používateľa pomocou účtu <xliff:g id="ACCOUNT">%2$s</xliff:g>?"</string>
<string name="language_selection_title" msgid="52674936078683285">"Pridať jazyk"</string>
@@ -2096,14 +2101,29 @@
<string name="as_app_forced_to_restricted_bucket" msgid="8233871289353898964">"Balík <xliff:g id="PACKAGE_NAME">%1$s</xliff:g> bol vložený do kontajnera OBMEDZENÉ"</string>
<string name="resolver_personal_tab" msgid="2051260504014442073">"Osobné"</string>
<string name="resolver_work_tab" msgid="2690019516263167035">"Práca"</string>
+ <!-- no translation found for resolver_personal_tab_accessibility (5739524949153091224) -->
+ <skip />
+ <!-- no translation found for resolver_work_tab_accessibility (4753168230363802734) -->
+ <skip />
<string name="resolver_cant_share_with_work_apps" msgid="7539495559434146897">"Nedá sa zdieľa s pracovnými aplikáciami"</string>
<string name="resolver_cant_share_with_personal_apps" msgid="8020581735267157241">"Nedá sa zdieľať s osobnými aplikáciami"</string>
- <string name="resolver_cant_share_cross_profile_explanation" msgid="3536237105241882679">"Váš správca IT zablokoval zdieľanie medzi osobnými a pracovnými aplikáciami"</string>
- <string name="resolver_turn_on_work_apps" msgid="8987359079870455469">"Zapnite pracovné aplikácie"</string>
- <string name="resolver_turn_on_work_apps_explanation" msgid="6322467455509618928">"Ak chcete získať prístup k pracovným aplikáciám a kontaktom, zapnite pracovné aplikácie"</string>
+ <!-- no translation found for resolver_cant_share_cross_profile_explanation (5556640604460901386) -->
+ <skip />
+ <!-- no translation found for resolver_cant_access_work_apps (375634344111233790) -->
+ <skip />
+ <!-- no translation found for resolver_cant_access_work_apps_explanation (3958762224516867388) -->
+ <skip />
+ <!-- no translation found for resolver_cant_access_personal_apps (1953215925406474177) -->
+ <skip />
+ <!-- no translation found for resolver_cant_access_personal_apps_explanation (1725572276741281136) -->
+ <skip />
+ <!-- no translation found for resolver_turn_on_work_apps_share (619263911204978175) -->
+ <skip />
+ <!-- no translation found for resolver_turn_on_work_apps_view (3073389230905543680) -->
+ <skip />
<string name="resolver_no_apps_available" msgid="7710339903040989654">"K dispozícii nie sú žiadne aplikácie"</string>
- <string name="resolver_no_apps_available_explanation" msgid="4662694431121196560">"Neboli nájdené žiadne aplikácie"</string>
- <string name="resolver_switch_on_work" msgid="8294542702883688533">"Zapnúť pracovný profil"</string>
+ <!-- no translation found for resolver_switch_on_work (2873009160846966379) -->
+ <skip />
<string name="permlab_accessCallAudio" msgid="1682957511874097664">"Nahrávanie alebo prehrávanie zvuku počas telefonických hovorov"</string>
<string name="permdesc_accessCallAudio" msgid="8448360894684277823">"Povoľuje tejto aplikácii, keď je priradená ako predvolená aplikácia na vytáčanie, nahrávať alebo prehrávať zvuk počas telefonických hovorov."</string>
</resources>
diff --git a/core/res/res/values-sl/strings.xml b/core/res/res/values-sl/strings.xml
index 71786011f2ce..d5ae02593efe 100644
--- a/core/res/res/values-sl/strings.xml
+++ b/core/res/res/values-sl/strings.xml
@@ -255,10 +255,8 @@
<item quantity="few">Posnetek zaslona za poročilo o napakah bo narejen čez <xliff:g id="NUMBER_1">%d</xliff:g> s.</item>
<item quantity="other">Posnetek zaslona za poročilo o napakah bo narejen čez <xliff:g id="NUMBER_1">%d</xliff:g> s.</item>
</plurals>
- <!-- no translation found for bugreport_screenshot_success_toast (7986095104151473745) -->
- <skip />
- <!-- no translation found for bugreport_screenshot_failure_toast (6736320861311294294) -->
- <skip />
+ <string name="bugreport_screenshot_success_toast" msgid="7986095104151473745">"Posnetek zaslona s poročilom o napakah je izdelan"</string>
+ <string name="bugreport_screenshot_failure_toast" msgid="6736320861311294294">"Izdelava posnetka zaslona s poročilom o napakah ni uspela"</string>
<string name="global_action_toggle_silent_mode" msgid="8464352592860372188">"Tihi način"</string>
<string name="global_action_silent_mode_on_status" msgid="2371892537738632013">"Zvok je IZKLOPLJEN"</string>
<string name="global_action_silent_mode_off_status" msgid="6608006545950920042">"Zvok je VKLOPLJEN"</string>
@@ -460,9 +458,11 @@
<string name="permdesc_acceptHandovers" msgid="7129026180128626870">"Aplikaciji dovoljuje nadaljevanje klica, ki se je začel v drugi aplikaciji."</string>
<string name="permlab_readPhoneNumbers" msgid="5668704794723365628">"branje telefonskih številk"</string>
<string name="permdesc_readPhoneNumbers" msgid="7368652482818338871">"Aplikaciji dovoljuje dostop do telefonskih številk v napravi."</string>
+ <string name="permlab_wakeLock" product="automotive" msgid="1904736682319375676">"Ohranjanje vklopljenega zaslona avtomobila"</string>
<string name="permlab_wakeLock" product="tablet" msgid="1527660973931694000">"preprečitev prehoda tabličnega računalnika v stanje pripravljenosti"</string>
<string name="permlab_wakeLock" product="tv" msgid="2856941418123343518">"preprečevanje preklopa naprave Android TV v stanje pripravljenosti"</string>
<string name="permlab_wakeLock" product="default" msgid="569409726861695115">"preprečevanje prehoda v stanje pripravljenosti telefona"</string>
+ <string name="permdesc_wakeLock" product="automotive" msgid="5995045369683254571">"Aplikaciji omogoča, da zaslon avtomobila ohranja vklopljen."</string>
<string name="permdesc_wakeLock" product="tablet" msgid="2441742939101526277">"Omogoča, da aplikacija prepreči prehod tabličnega računalnika v stanje pripravljenosti."</string>
<string name="permdesc_wakeLock" product="tv" msgid="2329298966735118796">"Aplikaciji dovoljuje, da prepreči preklop naprave Android TV v stanje pripravljenosti."</string>
<string name="permdesc_wakeLock" product="default" msgid="3689523792074007163">"Aplikaciji omogoča, da v telefonu prepreči prehod v stanje pripravljenosti."</string>
@@ -1675,6 +1675,12 @@
<string name="safe_media_volume_warning" product="default" msgid="3751676824423049994">"Ali želite povečati glasnost nad priporočeno raven?\n\nDolgotrajno poslušanje pri veliki glasnosti lahko poškoduje sluh."</string>
<string name="accessibility_shortcut_warning_dialog_title" msgid="4017995837692622933">"Želite uporabljati bližnjico funkcij za ljudi s posebnimi potrebami?"</string>
<string name="accessibility_shortcut_toogle_warning" msgid="4161716521310929544">"Ko je bližnjica vklopljena, pritisnite gumba za glasnost in ju pridržite tri sekunde, če želite zagnati funkcijo za ljudi s posebnimi potrebami."</string>
+ <!-- no translation found for accessibility_select_shortcut_menu_title (7310194076629867377) -->
+ <skip />
+ <!-- no translation found for accessibility_edit_shortcut_menu_button_title (6096484087245145325) -->
+ <skip />
+ <!-- no translation found for accessibility_edit_shortcut_menu_volume_title (4849108668454490699) -->
+ <skip />
<string name="edit_accessibility_shortcut_menu_button" msgid="8885752738733772935">"Uredi bližnjice"</string>
<string name="cancel_accessibility_shortcut_menu_button" msgid="1817413122335452474">"Prekliči"</string>
<string name="disable_accessibility_shortcut" msgid="5806091378745232383">"Izklopi bližnjico"</string>
@@ -1917,8 +1923,7 @@
<string name="default_notification_channel_label" msgid="3697928973567217330">"Nekategorizirano"</string>
<string name="importance_from_user" msgid="2782756722448800447">"Vi določite raven pomembnosti teh obvestil."</string>
<string name="importance_from_person" msgid="4235804979664465383">"Pomembno zaradi udeleženih ljudi."</string>
- <!-- no translation found for notification_history_title_placeholder (7748630986182249599) -->
- <skip />
+ <string name="notification_history_title_placeholder" msgid="7748630986182249599">"Obvestilo po meri iz aplikacije"</string>
<string name="user_creation_account_exists" msgid="2239146360099708035">"Ali aplikaciji <xliff:g id="APP">%1$s</xliff:g> dovolite, da ustvari novega uporabnika za račun <xliff:g id="ACCOUNT">%2$s</xliff:g> (uporabnik s tem računom že obstaja)?"</string>
<string name="user_creation_adding" msgid="7305185499667958364">"Ali aplikaciji <xliff:g id="APP">%1$s</xliff:g> dovolite, da ustvari novega uporabnika za račun <xliff:g id="ACCOUNT">%2$s</xliff:g>?"</string>
<string name="language_selection_title" msgid="52674936078683285">"Dodajanje jezika"</string>
@@ -2096,14 +2101,29 @@
<string name="as_app_forced_to_restricted_bucket" msgid="8233871289353898964">"Paket <xliff:g id="PACKAGE_NAME">%1$s</xliff:g> je bil dodan v segment OMEJENO"</string>
<string name="resolver_personal_tab" msgid="2051260504014442073">"Osebno"</string>
<string name="resolver_work_tab" msgid="2690019516263167035">"Služba"</string>
+ <!-- no translation found for resolver_personal_tab_accessibility (5739524949153091224) -->
+ <skip />
+ <!-- no translation found for resolver_work_tab_accessibility (4753168230363802734) -->
+ <skip />
<string name="resolver_cant_share_with_work_apps" msgid="7539495559434146897">"Deljenje z delovnimi aplikacijami ni mogoče"</string>
<string name="resolver_cant_share_with_personal_apps" msgid="8020581735267157241">"Deljenje z osebnimi aplikacijami ni mogoče"</string>
- <string name="resolver_cant_share_cross_profile_explanation" msgid="3536237105241882679">"Skrbnik za IT je blokiral deljenje med osebnimi in delovnimi aplikacijami"</string>
- <string name="resolver_turn_on_work_apps" msgid="8987359079870455469">"Vklopi delovne aplikacije"</string>
- <string name="resolver_turn_on_work_apps_explanation" msgid="6322467455509618928">"Če želite dostopati do delovnih aplikacij in stikov, vklopite delovne aplikacije"</string>
+ <!-- no translation found for resolver_cant_share_cross_profile_explanation (5556640604460901386) -->
+ <skip />
+ <!-- no translation found for resolver_cant_access_work_apps (375634344111233790) -->
+ <skip />
+ <!-- no translation found for resolver_cant_access_work_apps_explanation (3958762224516867388) -->
+ <skip />
+ <!-- no translation found for resolver_cant_access_personal_apps (1953215925406474177) -->
+ <skip />
+ <!-- no translation found for resolver_cant_access_personal_apps_explanation (1725572276741281136) -->
+ <skip />
+ <!-- no translation found for resolver_turn_on_work_apps_share (619263911204978175) -->
+ <skip />
+ <!-- no translation found for resolver_turn_on_work_apps_view (3073389230905543680) -->
+ <skip />
<string name="resolver_no_apps_available" msgid="7710339903040989654">"Na voljo ni nobena aplikacija"</string>
- <string name="resolver_no_apps_available_explanation" msgid="4662694431121196560">"Aplikacij ni bilo mogoče najti"</string>
- <string name="resolver_switch_on_work" msgid="8294542702883688533">"Vklopi delovni profil"</string>
+ <!-- no translation found for resolver_switch_on_work (2873009160846966379) -->
+ <skip />
<string name="permlab_accessCallAudio" msgid="1682957511874097664">"Snemanje ali predvajanje zvoka med telefonskimi klici"</string>
<string name="permdesc_accessCallAudio" msgid="8448360894684277823">"Tej aplikaciji dovoljuje snemanje ali predvajanje zvoka med telefonskimi klici, ko je nastavljena kot privzeta aplikacija za klicanje."</string>
</resources>
diff --git a/core/res/res/values-sq/strings.xml b/core/res/res/values-sq/strings.xml
index 244852110835..3cb728881d3f 100644
--- a/core/res/res/values-sq/strings.xml
+++ b/core/res/res/values-sq/strings.xml
@@ -249,10 +249,8 @@
<item quantity="other">Marrja e pamjes së ekranit për raportin e defektit në kod në <xliff:g id="NUMBER_1">%d</xliff:g> sekonda.</item>
<item quantity="one">Marrja e pamjes së ekranit për raportin e defektit në kod në <xliff:g id="NUMBER_0">%d</xliff:g> sekondë.</item>
</plurals>
- <!-- no translation found for bugreport_screenshot_success_toast (7986095104151473745) -->
- <skip />
- <!-- no translation found for bugreport_screenshot_failure_toast (6736320861311294294) -->
- <skip />
+ <string name="bugreport_screenshot_success_toast" msgid="7986095104151473745">"U shkrep pamja e ekranit me raportin e defekteve në kod"</string>
+ <string name="bugreport_screenshot_failure_toast" msgid="6736320861311294294">"Nuk u shkrep pamja e ekranit me raportin e defekteve në kod"</string>
<string name="global_action_toggle_silent_mode" msgid="8464352592860372188">"Modaliteti \"në heshtje\""</string>
<string name="global_action_silent_mode_on_status" msgid="2371892537738632013">"Zëri është çaktivizuar"</string>
<string name="global_action_silent_mode_off_status" msgid="6608006545950920042">"Zëri është i aktivizuar"</string>
@@ -454,9 +452,11 @@
<string name="permdesc_acceptHandovers" msgid="7129026180128626870">"Lejon që aplikacioni të vazhdojë një telefonatë që është nisur në një aplikacion tjetër."</string>
<string name="permlab_readPhoneNumbers" msgid="5668704794723365628">"lexo numrat e telefonit"</string>
<string name="permdesc_readPhoneNumbers" msgid="7368652482818338871">"Lejon që aplikacioni të ketë qasje te numrat e telefonit të pajisjes."</string>
+ <string name="permlab_wakeLock" product="automotive" msgid="1904736682319375676">"të mbajë ekranin e makinës të aktivizuar"</string>
<string name="permlab_wakeLock" product="tablet" msgid="1527660973931694000">"parandalo kalimin e tabletit në fjetje"</string>
<string name="permlab_wakeLock" product="tv" msgid="2856941418123343518">"parandalon kalimin në fjetje të pajisjes sate Android TV"</string>
<string name="permlab_wakeLock" product="default" msgid="569409726861695115">"parandalo kalimin e telefonit në fjetje"</string>
+ <string name="permdesc_wakeLock" product="automotive" msgid="5995045369683254571">"Lejon që aplikacioni të mbajë ekranin e makinës të aktivizuar."</string>
<string name="permdesc_wakeLock" product="tablet" msgid="2441742939101526277">"Lejon aplikacionin të parandalojë tabletin nga fjetja."</string>
<string name="permdesc_wakeLock" product="tv" msgid="2329298966735118796">"Lejon aplikacionin të parandalojë kalimin në fjetje të pajisjes sate Android TV."</string>
<string name="permdesc_wakeLock" product="default" msgid="3689523792074007163">"Lejon aplikacionin të parandalojë telefonin nga fjetja."</string>
@@ -1631,6 +1631,12 @@
<string name="safe_media_volume_warning" product="default" msgid="3751676824423049994">"Të ngrihet volumi mbi nivelin e rekomanduar?\n\nDëgjimi me volum të lartë për periudha të gjata mund të dëmtojë dëgjimin."</string>
<string name="accessibility_shortcut_warning_dialog_title" msgid="4017995837692622933">"Të përdoret shkurtorja e qasshmërisë?"</string>
<string name="accessibility_shortcut_toogle_warning" msgid="4161716521310929544">"Kur shkurtorja është e aktivizuar, shtypja e të dy butonave për 3 sekonda do të nisë një funksion qasshmërie."</string>
+ <!-- no translation found for accessibility_select_shortcut_menu_title (7310194076629867377) -->
+ <skip />
+ <!-- no translation found for accessibility_edit_shortcut_menu_button_title (6096484087245145325) -->
+ <skip />
+ <!-- no translation found for accessibility_edit_shortcut_menu_volume_title (4849108668454490699) -->
+ <skip />
<string name="edit_accessibility_shortcut_menu_button" msgid="8885752738733772935">"Redakto shkurtoret"</string>
<string name="cancel_accessibility_shortcut_menu_button" msgid="1817413122335452474">"Anulo"</string>
<string name="disable_accessibility_shortcut" msgid="5806091378745232383">"Çaktivizo shkurtoren"</string>
@@ -1853,8 +1859,7 @@
<string name="default_notification_channel_label" msgid="3697928973567217330">"E pakategorizuara"</string>
<string name="importance_from_user" msgid="2782756722448800447">"Ke caktuar rëndësinë e këtyre njoftimeve."</string>
<string name="importance_from_person" msgid="4235804979664465383">"Është i rëndësishëm për shkak të personave të përfshirë."</string>
- <!-- no translation found for notification_history_title_placeholder (7748630986182249599) -->
- <skip />
+ <string name="notification_history_title_placeholder" msgid="7748630986182249599">"Njoftim i personalizuar për aplikacionin"</string>
<string name="user_creation_account_exists" msgid="2239146360099708035">"Të lejohet <xliff:g id="APP">%1$s</xliff:g> që të krijojë një përdorues të ri me <xliff:g id="ACCOUNT">%2$s</xliff:g> (një përdorues me këtë llogari ekziston tashmë) ?"</string>
<string name="user_creation_adding" msgid="7305185499667958364">"Të lejohet <xliff:g id="APP">%1$s</xliff:g> që të krijojë një përdorues të ri me <xliff:g id="ACCOUNT">%2$s</xliff:g> ?"</string>
<string name="language_selection_title" msgid="52674936078683285">"Shto një gjuhë"</string>
@@ -2028,14 +2033,29 @@
<string name="as_app_forced_to_restricted_bucket" msgid="8233871289353898964">"<xliff:g id="PACKAGE_NAME">%1$s</xliff:g> është vendosur në grupin E KUFIZUAR"</string>
<string name="resolver_personal_tab" msgid="2051260504014442073">"Personal"</string>
<string name="resolver_work_tab" msgid="2690019516263167035">"Puna"</string>
+ <!-- no translation found for resolver_personal_tab_accessibility (5739524949153091224) -->
+ <skip />
+ <!-- no translation found for resolver_work_tab_accessibility (4753168230363802734) -->
+ <skip />
<string name="resolver_cant_share_with_work_apps" msgid="7539495559434146897">"Nuk mund të ndash me aplikacionet e punës"</string>
<string name="resolver_cant_share_with_personal_apps" msgid="8020581735267157241">"Nuk mund të ndash me aplikacionet personale"</string>
- <string name="resolver_cant_share_cross_profile_explanation" msgid="3536237105241882679">"Administratori yt i teknologjisë së informacionit ka bllokuar ndarjen mes aplikacioneve personale dhe atyre të punës"</string>
- <string name="resolver_turn_on_work_apps" msgid="8987359079870455469">"Aktivizo aplikacionet e punës"</string>
- <string name="resolver_turn_on_work_apps_explanation" msgid="6322467455509618928">"Aktivizo aplikacionet e punës për të pasur qasje tek aplikacionet dhe kontaktet e punës"</string>
+ <!-- no translation found for resolver_cant_share_cross_profile_explanation (5556640604460901386) -->
+ <skip />
+ <!-- no translation found for resolver_cant_access_work_apps (375634344111233790) -->
+ <skip />
+ <!-- no translation found for resolver_cant_access_work_apps_explanation (3958762224516867388) -->
+ <skip />
+ <!-- no translation found for resolver_cant_access_personal_apps (1953215925406474177) -->
+ <skip />
+ <!-- no translation found for resolver_cant_access_personal_apps_explanation (1725572276741281136) -->
+ <skip />
+ <!-- no translation found for resolver_turn_on_work_apps_share (619263911204978175) -->
+ <skip />
+ <!-- no translation found for resolver_turn_on_work_apps_view (3073389230905543680) -->
+ <skip />
<string name="resolver_no_apps_available" msgid="7710339903040989654">"Nuk ofrohet asnjë aplikacion"</string>
- <string name="resolver_no_apps_available_explanation" msgid="4662694431121196560">"Nuk mund të gjenim asnjë aplikacion"</string>
- <string name="resolver_switch_on_work" msgid="8294542702883688533">"Kalo në profilin e punës"</string>
+ <!-- no translation found for resolver_switch_on_work (2873009160846966379) -->
+ <skip />
<string name="permlab_accessCallAudio" msgid="1682957511874097664">"Të regjistrojë ose luajë audio në telefonata"</string>
<string name="permdesc_accessCallAudio" msgid="8448360894684277823">"Lejon këtë aplikacion, kur caktohet si aplikacioni i parazgjedhur i formuesit të numrave, të regjistrojë ose luajë audio në telefonata."</string>
</resources>
diff --git a/core/res/res/values-sr/strings.xml b/core/res/res/values-sr/strings.xml
index 3edfdb1c01a7..c84f4a96cc5d 100644
--- a/core/res/res/values-sr/strings.xml
+++ b/core/res/res/values-sr/strings.xml
@@ -252,10 +252,8 @@
<item quantity="few">Направићемо снимак екрана ради извештаја о грешци за <xliff:g id="NUMBER_1">%d</xliff:g> секунде.</item>
<item quantity="other">Направићемо снимак екрана ради извештаја о грешци за <xliff:g id="NUMBER_1">%d</xliff:g> секунди.</item>
</plurals>
- <!-- no translation found for bugreport_screenshot_success_toast (7986095104151473745) -->
- <skip />
- <!-- no translation found for bugreport_screenshot_failure_toast (6736320861311294294) -->
- <skip />
+ <string name="bugreport_screenshot_success_toast" msgid="7986095104151473745">"Екран са извештајем о грешци је снимљен"</string>
+ <string name="bugreport_screenshot_failure_toast" msgid="6736320861311294294">"Снимање екрана са извештајем о грешци није успело"</string>
<string name="global_action_toggle_silent_mode" msgid="8464352592860372188">"Нечујни режим"</string>
<string name="global_action_silent_mode_on_status" msgid="2371892537738632013">"Звук је ИСКЉУЧЕН"</string>
<string name="global_action_silent_mode_off_status" msgid="6608006545950920042">"Звук је УКЉУЧЕН"</string>
@@ -457,9 +455,11 @@
<string name="permdesc_acceptHandovers" msgid="7129026180128626870">"Дозвољава апликацији да настави позив који је започет у другој апликацији."</string>
<string name="permlab_readPhoneNumbers" msgid="5668704794723365628">"читање бројева телефона"</string>
<string name="permdesc_readPhoneNumbers" msgid="7368652482818338871">"Дозвољава апликацији да приступа бројевима телефона на уређају."</string>
+ <string name="permlab_wakeLock" product="automotive" msgid="1904736682319375676">"не искључуј екран у аутомобилу"</string>
<string name="permlab_wakeLock" product="tablet" msgid="1527660973931694000">"спречавање преласка таблета у стање спавања"</string>
<string name="permlab_wakeLock" product="tv" msgid="2856941418123343518">"спречава Android TV уређај да пређе у стање спавања"</string>
<string name="permlab_wakeLock" product="default" msgid="569409726861695115">"спречавање преласка телефона у стање спавања"</string>
+ <string name="permdesc_wakeLock" product="automotive" msgid="5995045369683254571">"Дозвољава апликацији да не искључује екран у аутомобилу."</string>
<string name="permdesc_wakeLock" product="tablet" msgid="2441742939101526277">"Дозвољава апликацији да спречи таблет да пређе у стање спавања."</string>
<string name="permdesc_wakeLock" product="tv" msgid="2329298966735118796">"Дозвољава апликацији да спречи Android TV уређај да пређе у стање спавања."</string>
<string name="permdesc_wakeLock" product="default" msgid="3689523792074007163">"Дозвољава апликацији да спречи телефон да пређе у стање спавања."</string>
@@ -1653,6 +1653,12 @@
<string name="safe_media_volume_warning" product="default" msgid="3751676824423049994">"Желите да појачате звук изнад препорученог нивоа?\n\nСлушање гласне музике дуже време може да вам оштети слух."</string>
<string name="accessibility_shortcut_warning_dialog_title" msgid="4017995837692622933">"Желите ли да користите пречицу за приступачност?"</string>
<string name="accessibility_shortcut_toogle_warning" msgid="4161716521310929544">"Када је пречица укључена, притисните оба дугмета за јачину звука да бисте покренули функцију приступачности."</string>
+ <!-- no translation found for accessibility_select_shortcut_menu_title (7310194076629867377) -->
+ <skip />
+ <!-- no translation found for accessibility_edit_shortcut_menu_button_title (6096484087245145325) -->
+ <skip />
+ <!-- no translation found for accessibility_edit_shortcut_menu_volume_title (4849108668454490699) -->
+ <skip />
<string name="edit_accessibility_shortcut_menu_button" msgid="8885752738733772935">"Измените пречице"</string>
<string name="cancel_accessibility_shortcut_menu_button" msgid="1817413122335452474">"Откажи"</string>
<string name="disable_accessibility_shortcut" msgid="5806091378745232383">"Искључи пречицу"</string>
@@ -1885,8 +1891,7 @@
<string name="default_notification_channel_label" msgid="3697928973567217330">"Некатегоризовано"</string>
<string name="importance_from_user" msgid="2782756722448800447">"Ви подешавате важност ових обавештења."</string>
<string name="importance_from_person" msgid="4235804979664465383">"Ово је важно због људи који учествују."</string>
- <!-- no translation found for notification_history_title_placeholder (7748630986182249599) -->
- <skip />
+ <string name="notification_history_title_placeholder" msgid="7748630986182249599">"Прилагођено обавештење о апликацији"</string>
<string name="user_creation_account_exists" msgid="2239146360099708035">"Желите ли да дозволите да <xliff:g id="APP">%1$s</xliff:g> направи новог корисника са налогом <xliff:g id="ACCOUNT">%2$s</xliff:g> (корисник са тим налогом већ постоји)?"</string>
<string name="user_creation_adding" msgid="7305185499667958364">"Желите ли да дозволите да <xliff:g id="APP">%1$s</xliff:g> направи новог корисника са налогом <xliff:g id="ACCOUNT">%2$s</xliff:g>?"</string>
<string name="language_selection_title" msgid="52674936078683285">"Додајте језик"</string>
@@ -2062,14 +2067,29 @@
<string name="as_app_forced_to_restricted_bucket" msgid="8233871289353898964">"Пакет <xliff:g id="PACKAGE_NAME">%1$s</xliff:g> је додат у сегмент ОГРАНИЧЕНО"</string>
<string name="resolver_personal_tab" msgid="2051260504014442073">"Лични"</string>
<string name="resolver_work_tab" msgid="2690019516263167035">"Пословни"</string>
+ <!-- no translation found for resolver_personal_tab_accessibility (5739524949153091224) -->
+ <skip />
+ <!-- no translation found for resolver_work_tab_accessibility (4753168230363802734) -->
+ <skip />
<string name="resolver_cant_share_with_work_apps" msgid="7539495559434146897">"Не можете да делите садржај са апликацијама за посао"</string>
<string name="resolver_cant_share_with_personal_apps" msgid="8020581735267157241">"Не можете да делите садржај са личним апликацијама"</string>
- <string name="resolver_cant_share_cross_profile_explanation" msgid="3536237105241882679">"ИТ администратор је блокирао дељење између личних апликација и апликација за посао"</string>
- <string name="resolver_turn_on_work_apps" msgid="8987359079870455469">"Укључите апликације за посао"</string>
- <string name="resolver_turn_on_work_apps_explanation" msgid="6322467455509618928">"Укључите апликације за посао да бисте приступили апликацијама и контактима за посао"</string>
+ <!-- no translation found for resolver_cant_share_cross_profile_explanation (5556640604460901386) -->
+ <skip />
+ <!-- no translation found for resolver_cant_access_work_apps (375634344111233790) -->
+ <skip />
+ <!-- no translation found for resolver_cant_access_work_apps_explanation (3958762224516867388) -->
+ <skip />
+ <!-- no translation found for resolver_cant_access_personal_apps (1953215925406474177) -->
+ <skip />
+ <!-- no translation found for resolver_cant_access_personal_apps_explanation (1725572276741281136) -->
+ <skip />
+ <!-- no translation found for resolver_turn_on_work_apps_share (619263911204978175) -->
+ <skip />
+ <!-- no translation found for resolver_turn_on_work_apps_view (3073389230905543680) -->
+ <skip />
<string name="resolver_no_apps_available" msgid="7710339903040989654">"Нема доступних апликација"</string>
- <string name="resolver_no_apps_available_explanation" msgid="4662694431121196560">"Нисмо пронашли ниједну апликацију"</string>
- <string name="resolver_switch_on_work" msgid="8294542702883688533">"Укључи профил за Work"</string>
+ <!-- no translation found for resolver_switch_on_work (2873009160846966379) -->
+ <skip />
<string name="permlab_accessCallAudio" msgid="1682957511874097664">"Снимање или пуштање звука у телефонским позивима"</string>
<string name="permdesc_accessCallAudio" msgid="8448360894684277823">"Омогућава овој апликацији, када је додељена као подразумевана апликација за позивање, да снима или пушта звук у телефонским позивима."</string>
</resources>
diff --git a/core/res/res/values-sv/strings.xml b/core/res/res/values-sv/strings.xml
index 73e7efc4ab8d..4c07f22f6ad2 100644
--- a/core/res/res/values-sv/strings.xml
+++ b/core/res/res/values-sv/strings.xml
@@ -249,10 +249,8 @@
<item quantity="other">Tar en skärmdump till felrapporten om <xliff:g id="NUMBER_1">%d</xliff:g> sekunder.</item>
<item quantity="one">Tar en skärmdump till felrapporten om <xliff:g id="NUMBER_0">%d</xliff:g> sekund.</item>
</plurals>
- <!-- no translation found for bugreport_screenshot_success_toast (7986095104151473745) -->
- <skip />
- <!-- no translation found for bugreport_screenshot_failure_toast (6736320861311294294) -->
- <skip />
+ <string name="bugreport_screenshot_success_toast" msgid="7986095104151473745">"Skärmdump med felrapport har tagits"</string>
+ <string name="bugreport_screenshot_failure_toast" msgid="6736320861311294294">"Det gick inte att ta en skärmdump med felrapport"</string>
<string name="global_action_toggle_silent_mode" msgid="8464352592860372188">"Tyst läge"</string>
<string name="global_action_silent_mode_on_status" msgid="2371892537738632013">"Ljudet är AV"</string>
<string name="global_action_silent_mode_off_status" msgid="6608006545950920042">"Ljudet är PÅ"</string>
@@ -454,9 +452,11 @@
<string name="permdesc_acceptHandovers" msgid="7129026180128626870">"Tillåter att appen fortsätter ett samtal som har startats i en annan app."</string>
<string name="permlab_readPhoneNumbers" msgid="5668704794723365628">"läsa telefonnummer"</string>
<string name="permdesc_readPhoneNumbers" msgid="7368652482818338871">"Appen beviljas åtkomst till enhetens telefonnummer."</string>
+ <string name="permlab_wakeLock" product="automotive" msgid="1904736682319375676">"låta bilens skärm vara på"</string>
<string name="permlab_wakeLock" product="tablet" msgid="1527660973931694000">"förhindra att surfplattan går in i viloläge"</string>
<string name="permlab_wakeLock" product="tv" msgid="2856941418123343518">"förhindra att Android TV-enheten försätts i viloläge"</string>
<string name="permlab_wakeLock" product="default" msgid="569409726861695115">"förhindra att telefonen sätts i viloläge"</string>
+ <string name="permdesc_wakeLock" product="automotive" msgid="5995045369683254571">"Tillåter appen att låta bilens skärm vara på."</string>
<string name="permdesc_wakeLock" product="tablet" msgid="2441742939101526277">"Tillåter att appen förhindrar att surfplattan går in i viloläge."</string>
<string name="permdesc_wakeLock" product="tv" msgid="2329298966735118796">"Tillåter att appen förhindrar att Android TV-enheten försätts i viloläge."</string>
<string name="permdesc_wakeLock" product="default" msgid="3689523792074007163">"Tillåter att appen förhindrar att mobilen går in i viloläge."</string>
@@ -1631,6 +1631,12 @@
<string name="safe_media_volume_warning" product="default" msgid="3751676824423049994">"Vill du höja volymen över den rekommenderade nivån?\n\nAtt lyssna med stark volym långa stunder åt gången kan skada hörseln."</string>
<string name="accessibility_shortcut_warning_dialog_title" msgid="4017995837692622933">"Vill du använda Aktivera tillgänglighet snabbt?"</string>
<string name="accessibility_shortcut_toogle_warning" msgid="4161716521310929544">"När kortkommandot har aktiverats startar du en tillgänglighetsfunktion genom att trycka ned båda volymknapparna i tre sekunder."</string>
+ <!-- no translation found for accessibility_select_shortcut_menu_title (7310194076629867377) -->
+ <skip />
+ <!-- no translation found for accessibility_edit_shortcut_menu_button_title (6096484087245145325) -->
+ <skip />
+ <!-- no translation found for accessibility_edit_shortcut_menu_volume_title (4849108668454490699) -->
+ <skip />
<string name="edit_accessibility_shortcut_menu_button" msgid="8885752738733772935">"Redigera genvägar"</string>
<string name="cancel_accessibility_shortcut_menu_button" msgid="1817413122335452474">"Avbryt"</string>
<string name="disable_accessibility_shortcut" msgid="5806091378745232383">"Inaktivera kortkommandot"</string>
@@ -1853,8 +1859,7 @@
<string name="default_notification_channel_label" msgid="3697928973567217330">"Okategoriserad"</string>
<string name="importance_from_user" msgid="2782756722448800447">"Du anger hur viktiga aviseringarna är."</string>
<string name="importance_from_person" msgid="4235804979664465383">"Detta är viktigt på grund av personerna som deltar."</string>
- <!-- no translation found for notification_history_title_placeholder (7748630986182249599) -->
- <skip />
+ <string name="notification_history_title_placeholder" msgid="7748630986182249599">"Anpassad appavisering"</string>
<string name="user_creation_account_exists" msgid="2239146360099708035">"Tillåter du att <xliff:g id="APP">%1$s</xliff:g> skapar en ny användare för <xliff:g id="ACCOUNT">%2$s</xliff:g> (det finns redan en användare med det här kontot)?"</string>
<string name="user_creation_adding" msgid="7305185499667958364">"Tillåter du att <xliff:g id="APP">%1$s</xliff:g> skapar en ny användare för <xliff:g id="ACCOUNT">%2$s</xliff:g>?"</string>
<string name="language_selection_title" msgid="52674936078683285">"Lägg till ett språk"</string>
@@ -2028,14 +2033,29 @@
<string name="as_app_forced_to_restricted_bucket" msgid="8233871289353898964">"<xliff:g id="PACKAGE_NAME">%1$s</xliff:g> har placerats i hinken RESTRICTED"</string>
<string name="resolver_personal_tab" msgid="2051260504014442073">"Privat"</string>
<string name="resolver_work_tab" msgid="2690019516263167035">"Jobb"</string>
+ <!-- no translation found for resolver_personal_tab_accessibility (5739524949153091224) -->
+ <skip />
+ <!-- no translation found for resolver_work_tab_accessibility (4753168230363802734) -->
+ <skip />
<string name="resolver_cant_share_with_work_apps" msgid="7539495559434146897">"Det går inte att dela med jobbappar"</string>
<string name="resolver_cant_share_with_personal_apps" msgid="8020581735267157241">"Det går inte att dela med personliga appar"</string>
- <string name="resolver_cant_share_cross_profile_explanation" msgid="3536237105241882679">"IT-administratören har blockerat delning mellan personliga och jobbappar"</string>
- <string name="resolver_turn_on_work_apps" msgid="8987359079870455469">"Aktivera jobbappar"</string>
- <string name="resolver_turn_on_work_apps_explanation" msgid="6322467455509618928">"Aktivera jobbappar om du vill få åtkomst till jobbrelaterade appar och kontakter"</string>
+ <!-- no translation found for resolver_cant_share_cross_profile_explanation (5556640604460901386) -->
+ <skip />
+ <!-- no translation found for resolver_cant_access_work_apps (375634344111233790) -->
+ <skip />
+ <!-- no translation found for resolver_cant_access_work_apps_explanation (3958762224516867388) -->
+ <skip />
+ <!-- no translation found for resolver_cant_access_personal_apps (1953215925406474177) -->
+ <skip />
+ <!-- no translation found for resolver_cant_access_personal_apps_explanation (1725572276741281136) -->
+ <skip />
+ <!-- no translation found for resolver_turn_on_work_apps_share (619263911204978175) -->
+ <skip />
+ <!-- no translation found for resolver_turn_on_work_apps_view (3073389230905543680) -->
+ <skip />
<string name="resolver_no_apps_available" msgid="7710339903040989654">"Det finns inga tillgängliga appar"</string>
- <string name="resolver_no_apps_available_explanation" msgid="4662694431121196560">"Vi hittade inga appar"</string>
- <string name="resolver_switch_on_work" msgid="8294542702883688533">"Aktivera jobbprofil"</string>
+ <!-- no translation found for resolver_switch_on_work (2873009160846966379) -->
+ <skip />
<string name="permlab_accessCallAudio" msgid="1682957511874097664">"Spela in och spela upp ljud i telefonsamtal"</string>
<string name="permdesc_accessCallAudio" msgid="8448360894684277823">"Tillåter appen att spela in och spela upp ljud i telefonsamtal när den har angetts som standardapp för uppringningsfunktionen."</string>
</resources>
diff --git a/core/res/res/values-sw/strings.xml b/core/res/res/values-sw/strings.xml
index 5ef601fba163..b5c07b332151 100644
--- a/core/res/res/values-sw/strings.xml
+++ b/core/res/res/values-sw/strings.xml
@@ -249,10 +249,8 @@
<item quantity="other">Inapiga picha ya skrini ili iripoti hitilafu baada ya sekunde <xliff:g id="NUMBER_1">%d</xliff:g>.</item>
<item quantity="one">Inapiga picha ya skrini ili iripoti hitilafu baada ya sekunde <xliff:g id="NUMBER_0">%d</xliff:g>.</item>
</plurals>
- <!-- no translation found for bugreport_screenshot_success_toast (7986095104151473745) -->
- <skip />
- <!-- no translation found for bugreport_screenshot_failure_toast (6736320861311294294) -->
- <skip />
+ <string name="bugreport_screenshot_success_toast" msgid="7986095104151473745">"Umepiga picha ya skrini ya ripoti ya hitilafu"</string>
+ <string name="bugreport_screenshot_failure_toast" msgid="6736320861311294294">"Imeshindwa kupiga picha ya skrini ya ripoti ya hitilafu"</string>
<string name="global_action_toggle_silent_mode" msgid="8464352592860372188">"Mtindo wa kimya"</string>
<string name="global_action_silent_mode_on_status" msgid="2371892537738632013">"Sauti Imezimwa"</string>
<string name="global_action_silent_mode_off_status" msgid="6608006545950920042">"Sauti imewashwa"</string>
@@ -454,9 +452,11 @@
<string name="permdesc_acceptHandovers" msgid="7129026180128626870">"Huruhusu programu kuendelea na simu ambayo ilianzishwa katika programu nyingine."</string>
<string name="permlab_readPhoneNumbers" msgid="5668704794723365628">"kusoma nambari za simu"</string>
<string name="permdesc_readPhoneNumbers" msgid="7368652482818338871">"Inaruhusu programu kufikia nambari za simu zilizo kwenye kifaa."</string>
+ <string name="permlab_wakeLock" product="automotive" msgid="1904736682319375676">"kuweka skrini ya gari isijizime"</string>
<string name="permlab_wakeLock" product="tablet" msgid="1527660973931694000">"zuia kompyuta ndogo dhidi ya kulala"</string>
<string name="permlab_wakeLock" product="tv" msgid="2856941418123343518">"zuia kifaa chako cha Android TV kisiingie katika hali tuli"</string>
<string name="permlab_wakeLock" product="default" msgid="569409726861695115">"kuzuia simu isilale"</string>
+ <string name="permdesc_wakeLock" product="automotive" msgid="5995045369683254571">"Huruhusu programu kuweka skrini ya gari isijizime."</string>
<string name="permdesc_wakeLock" product="tablet" msgid="2441742939101526277">"Inaruhusu programu kuzuia kompyuta kibao kwenda kulala."</string>
<string name="permdesc_wakeLock" product="tv" msgid="2329298966735118796">"Huruhusu programu izuie kifaa chako cha Android TV kisiingie katika hali tuli."</string>
<string name="permdesc_wakeLock" product="default" msgid="3689523792074007163">"Inaruhusu programu kuzuia simu isiende kulala."</string>
@@ -1631,6 +1631,12 @@
<string name="safe_media_volume_warning" product="default" msgid="3751676824423049994">"Ungependa kupandisha sauti zaidi ya kiwango kinachopendekezwa?\n\nKusikiliza kwa sauti ya juu kwa muda mrefu kunaweza kuharibu uwezo wako wa kusikia."</string>
<string name="accessibility_shortcut_warning_dialog_title" msgid="4017995837692622933">"Ungependa kutumia njia ya mkato ya ufikivu?"</string>
<string name="accessibility_shortcut_toogle_warning" msgid="4161716521310929544">"Unapowasha kipengele cha njia ya mkato, hatua ya kubonyeza vitufe vyote viwili vya sauti kwa sekunde tatu itafungua kipengele cha ufikivu."</string>
+ <!-- no translation found for accessibility_select_shortcut_menu_title (7310194076629867377) -->
+ <skip />
+ <!-- no translation found for accessibility_edit_shortcut_menu_button_title (6096484087245145325) -->
+ <skip />
+ <!-- no translation found for accessibility_edit_shortcut_menu_volume_title (4849108668454490699) -->
+ <skip />
<string name="edit_accessibility_shortcut_menu_button" msgid="8885752738733772935">"Kubadilisha njia za mkato"</string>
<string name="cancel_accessibility_shortcut_menu_button" msgid="1817413122335452474">"Ghairi"</string>
<string name="disable_accessibility_shortcut" msgid="5806091378745232383">"Zima kipengele cha Njia ya Mkato"</string>
@@ -1853,8 +1859,7 @@
<string name="default_notification_channel_label" msgid="3697928973567217330">"Ambazo aina haijabainishwa"</string>
<string name="importance_from_user" msgid="2782756722448800447">"Uliweka mipangilio ya umuhimu wa arifa hizi."</string>
<string name="importance_from_person" msgid="4235804979664465383">"Hii ni muhimu kwa sababu ya watu waliohusika."</string>
- <!-- no translation found for notification_history_title_placeholder (7748630986182249599) -->
- <skip />
+ <string name="notification_history_title_placeholder" msgid="7748630986182249599">"Arifa ya programu maalum"</string>
<string name="user_creation_account_exists" msgid="2239146360099708035">"Ruhusu <xliff:g id="APP">%1$s</xliff:g> iweke Mtumiaji mpya ikitumia <xliff:g id="ACCOUNT">%2$s</xliff:g> (Je, tayari kuna mtumiaji anayetumia akaunti hii)?"</string>
<string name="user_creation_adding" msgid="7305185499667958364">"Ungependa kuruhusu <xliff:g id="APP">%1$s</xliff:g> iweke Mtumiaji mpya ikitumia <xliff:g id="ACCOUNT">%2$s</xliff:g>?"</string>
<string name="language_selection_title" msgid="52674936078683285">"Ongeza lugha"</string>
@@ -2028,14 +2033,29 @@
<string name="as_app_forced_to_restricted_bucket" msgid="8233871289353898964">"<xliff:g id="PACKAGE_NAME">%1$s</xliff:g> kimewekwa katika kikundi KILICHODHIBITIWA"</string>
<string name="resolver_personal_tab" msgid="2051260504014442073">"Binafsi"</string>
<string name="resolver_work_tab" msgid="2690019516263167035">"Kazini"</string>
+ <!-- no translation found for resolver_personal_tab_accessibility (5739524949153091224) -->
+ <skip />
+ <!-- no translation found for resolver_work_tab_accessibility (4753168230363802734) -->
+ <skip />
<string name="resolver_cant_share_with_work_apps" msgid="7539495559434146897">"Imeshindwa kushiriki na programu za kazini"</string>
<string name="resolver_cant_share_with_personal_apps" msgid="8020581735267157241">"Imeshindwa kushiriki na programu za binafsi"</string>
- <string name="resolver_cant_share_cross_profile_explanation" msgid="3536237105241882679">"Msimamizi wako wa TEHAMA amezuia kushiriki kati ya programu za binafsi na za kazini"</string>
- <string name="resolver_turn_on_work_apps" msgid="8987359079870455469">"Washa programu za kazini"</string>
- <string name="resolver_turn_on_work_apps_explanation" msgid="6322467455509618928">"Washa programu za kazini ili ufikie programu na anwani za kazini"</string>
+ <!-- no translation found for resolver_cant_share_cross_profile_explanation (5556640604460901386) -->
+ <skip />
+ <!-- no translation found for resolver_cant_access_work_apps (375634344111233790) -->
+ <skip />
+ <!-- no translation found for resolver_cant_access_work_apps_explanation (3958762224516867388) -->
+ <skip />
+ <!-- no translation found for resolver_cant_access_personal_apps (1953215925406474177) -->
+ <skip />
+ <!-- no translation found for resolver_cant_access_personal_apps_explanation (1725572276741281136) -->
+ <skip />
+ <!-- no translation found for resolver_turn_on_work_apps_share (619263911204978175) -->
+ <skip />
+ <!-- no translation found for resolver_turn_on_work_apps_view (3073389230905543680) -->
+ <skip />
<string name="resolver_no_apps_available" msgid="7710339903040989654">"Hakuna programu zinazopatikana"</string>
- <string name="resolver_no_apps_available_explanation" msgid="4662694431121196560">"Hatujapata programu zozote"</string>
- <string name="resolver_switch_on_work" msgid="8294542702883688533">"Washa wasifu wa kazini"</string>
+ <!-- no translation found for resolver_switch_on_work (2873009160846966379) -->
+ <skip />
<string name="permlab_accessCallAudio" msgid="1682957511874097664">"Kurekodi au kucheza sauti katika simu"</string>
<string name="permdesc_accessCallAudio" msgid="8448360894684277823">"Huruhusu programu hii, wakati imekabidhiwa kuwa programu chaguomsingi ya kipiga simu, kurekodi au kucheza sauti katika simu."</string>
</resources>
diff --git a/core/res/res/values-sw600dp/config.xml b/core/res/res/values-sw600dp/config.xml
index e2c8d8a57e85..c891268a04da 100644
--- a/core/res/res/values-sw600dp/config.xml
+++ b/core/res/res/values-sw600dp/config.xml
@@ -42,16 +42,6 @@
<integer name="config_dockedStackDividerSnapMode">1</integer>
- <!-- The snap mode to use for picture-in-picture. These values correspond to constants defined
- in PipSnapAlgorithm and should not be changed independently.
- 0 - Snap to the four corners
- 1 - Snap to the four corners and the mid-points on the long edge in each orientation
- 2 - Snap anywhere along the edge of the screen
- 3 - Snap anywhere along the edge of the screen and magnet to corners
- 4 - Snap to the long edges in each orientation and magnet to corners
- -->
- <integer name="config_pictureInPictureSnapMode">3</integer>
-
<!-- Controls whether the nav bar can move from the bottom to the side in landscape.
Only applies if the device display is not square. -->
<bool name="config_navBarCanMove">false</bool>
diff --git a/core/res/res/values-ta/strings.xml b/core/res/res/values-ta/strings.xml
index da6cf4b643f3..8a8a327b1b3e 100644
--- a/core/res/res/values-ta/strings.xml
+++ b/core/res/res/values-ta/strings.xml
@@ -193,14 +193,10 @@
<string name="network_logging_notification_text" msgid="1327373071132562512">"உங்கள் நிறுவனம் இந்தச் சாதனத்தை நிர்வகிக்கும், அத்துடன் அது நெட்வொர்க் ட்ராஃபிக்கைக் கண்காணிக்கலாம். விவரங்களுக்கு, தட்டவும்."</string>
<string name="location_changed_notification_title" msgid="4119726617105166830">"உங்கள் நிர்வாகியால் இருப்பிட அமைப்புகள் மாற்றப்பட்டன"</string>
<string name="location_changed_notification_text" msgid="198907268219396399">"உங்கள் இருப்பிட அமைப்புகளைப் பார்க்க தட்டவும்."</string>
- <!-- no translation found for country_detector (7023275114706088854) -->
- <skip />
- <!-- no translation found for location_service (2439187616018455546) -->
- <skip />
- <!-- no translation found for sensor_notification_service (7474531979178682676) -->
- <skip />
- <!-- no translation found for twilight_service (8964898045693187224) -->
- <skip />
+ <string name="country_detector" msgid="7023275114706088854">"நாட்டைக் கண்டறியும் அம்சம்"</string>
+ <string name="location_service" msgid="2439187616018455546">"இருப்பிடச் சேவை"</string>
+ <string name="sensor_notification_service" msgid="7474531979178682676">"சென்சார் அறிவிப்புச் சேவை"</string>
+ <string name="twilight_service" msgid="8964898045693187224">"Twilight சேவை"</string>
<string name="factory_reset_warning" msgid="6858705527798047809">"சாதனத் தரவு அழிக்கப்படும்"</string>
<string name="factory_reset_message" msgid="2657049595153992213">"நிர்வாகி ஆப்ஸை உபயோகிக்க முடியாது. இப்போது, உங்கள் சாதனம் ஆரம்ப நிலைக்கு மீட்டமைக்கப்படும்.\n\nஏதேனும் கேள்விகள் இருப்பின், உங்கள் நிறுவனத்தின் நிர்வாகியைத் தொடர்புகொள்ளவும்."</string>
<string name="printing_disabled_by" msgid="3517499806528864633">"பிரிண்ட் செய்வதை <xliff:g id="OWNER_APP">%s</xliff:g> தடுத்துள்ளது."</string>
@@ -458,9 +454,11 @@
<string name="permdesc_acceptHandovers" msgid="7129026180128626870">"மற்றொரு பயன்பாட்டில் தொடங்கப்பட்ட அழைப்பைத் தொடருவதற்கு, ஆப்ஸை அனுமதிக்கிறது."</string>
<string name="permlab_readPhoneNumbers" msgid="5668704794723365628">"ஃபோன் எண்களைப் படித்தல்"</string>
<string name="permdesc_readPhoneNumbers" msgid="7368652482818338871">"சாதனத்தின் ஃபோன் எண்களை அணுக, ஆப்ஸை அனுமதிக்கும்."</string>
+ <string name="permlab_wakeLock" product="automotive" msgid="1904736682319375676">"கார் திரையை ஆன் செய்து வைத்திருத்தல்"</string>
<string name="permlab_wakeLock" product="tablet" msgid="1527660973931694000">"டேப்லெட் உறக்க நிலைக்குச் செல்வதைத் தடுத்தல்"</string>
<string name="permlab_wakeLock" product="tv" msgid="2856941418123343518">"உங்கள் Android TV உறக்க நிலைக்குச் செல்வதைத் தடுத்தல்"</string>
<string name="permlab_wakeLock" product="default" msgid="569409726861695115">"தொலைபேசி உறக்கநிலைக்குச் செல்வதைத் தடுத்தல்"</string>
+ <string name="permdesc_wakeLock" product="automotive" msgid="5995045369683254571">"கார் திரையை ஆன் செய்து வைத்திருப்பதற்கு இந்த ஆப்ஸை அனுமதிக்கும்."</string>
<string name="permdesc_wakeLock" product="tablet" msgid="2441742939101526277">"உறக்கநிலைக்குச் செல்லாமல் டேப்லெட்டைத் தடுக்க ஆப்ஸை அனுமதிக்கிறது."</string>
<string name="permdesc_wakeLock" product="tv" msgid="2329298966735118796">"Android TV உறக்க நிலைக்குச் செல்வதைத் தடுக்க ஆப்ஸை அனுமதிக்கும்."</string>
<string name="permdesc_wakeLock" product="default" msgid="3689523792074007163">"உறக்கநிலைக்குச் செல்லாமல் மொபைலைத் தடுக்க ஆப்ஸை அனுமதிக்கிறது."</string>
@@ -558,8 +556,7 @@
<string name="fingerprint_error_unable_to_process" msgid="1148553603490048742">"மீண்டும் முயற்சிக்கவும்."</string>
<string name="fingerprint_error_no_fingerprints" msgid="8671811719699072411">"கைரேகைப் பதிவுகள் எதுவும் இல்லை."</string>
<string name="fingerprint_error_hw_not_present" msgid="578914350967423382">"இந்தச் சாதனத்தில் கைரேகை சென்சார் இல்லை."</string>
- <!-- no translation found for fingerprint_error_security_update_required (7750187320640856433) -->
- <skip />
+ <string name="fingerprint_error_security_update_required" msgid="7750187320640856433">"சென்சார் தற்காலிகமாக முடக்கப்பட்டுள்ளது."</string>
<string name="fingerprint_name_template" msgid="8941662088160289778">"கைரேகை <xliff:g id="FINGERID">%d</xliff:g>"</string>
<string-array name="fingerprint_error_vendor">
</string-array>
@@ -603,8 +600,7 @@
<string name="face_error_unable_to_process" msgid="5723292697366130070">"முகத்தைச் சரிபார்க்க இயலவில்லை. மீண்டும் முயலவும்."</string>
<string name="face_error_not_enrolled" msgid="7369928733504691611">"’முகம் காட்டித் திறத்தலை’ நீங்கள் அமைக்கவில்லை."</string>
<string name="face_error_hw_not_present" msgid="1070600921591729944">"இந்த சாதனத்தில் ’முகம் காட்டித் திறத்தல்’ ஆதரிக்கப்படவில்லை."</string>
- <!-- no translation found for face_error_security_update_required (5076017208528750161) -->
- <skip />
+ <string name="face_error_security_update_required" msgid="5076017208528750161">"சென்சார் தற்காலிகமாக முடக்கப்பட்டுள்ளது."</string>
<string name="face_name_template" msgid="3877037340223318119">"முகம் <xliff:g id="FACEID">%d</xliff:g>"</string>
<string-array name="face_error_vendor">
</string-array>
@@ -1330,12 +1326,9 @@
<string name="adb_active_notification_title" msgid="408390247354560331">"USB பிழைதிருத்தம் இணைக்கப்பட்டது"</string>
<string name="adb_active_notification_message" msgid="5617264033476778211">"USB பிழைதிருத்தத்தை ஆஃப் செய்ய தட்டவும்"</string>
<string name="adb_active_notification_message" product="tv" msgid="6624498401272780855">"USB பிழைதிருத்தத்தை முடக்க, தேர்ந்தெடுக்கவும்."</string>
- <!-- no translation found for adbwifi_active_notification_title (6147343659168302473) -->
- <skip />
- <!-- no translation found for adbwifi_active_notification_message (930987922852867972) -->
- <skip />
- <!-- no translation found for adbwifi_active_notification_message (8633421848366915478) -->
- <skip />
+ <string name="adbwifi_active_notification_title" msgid="6147343659168302473">"வயர்லெஸ் பிழைதிருத்தம் இணைக்கப்பட்டது"</string>
+ <string name="adbwifi_active_notification_message" msgid="930987922852867972">"வயர்லெஸ் பிழைதிருத்தத்தை ஆஃப் செய்ய தட்டவும்"</string>
+ <string name="adbwifi_active_notification_message" product="tv" msgid="8633421848366915478">"வயர்லெஸ் பிழைதிருத்தத்தை முடக்க தேர்ந்தெடுக்கவும்."</string>
<string name="test_harness_mode_notification_title" msgid="2282785860014142511">"\'தன்னியக்க சோதனைப்\' பயன்முறை இயக்கப்பட்டது"</string>
<string name="test_harness_mode_notification_message" msgid="3039123743127958420">"’தன்னியக்க சோதனைப்\' பயன்முறையை முடக்க ஆரம்பநிலைக்கு மீட்டமைக்கவும்."</string>
<string name="console_running_notification_title" msgid="6087888939261635904">"சீரியல் கன்சோல் இயக்கப்பட்டது"</string>
@@ -1639,7 +1632,12 @@
<string name="allow_while_in_use_permission_in_fgs" msgid="4101339676785053656">"<xliff:g id="PACKAGENAME">%1$s</xliff:g> இல் இருந்து பின்னணியில் தொடங்கப்பட்ட முன்புலச் சேவைக்கு, வரவுள்ள R பதிப்புகளில் உபயோகத்தின்போது மட்டுமான அனுமதி இருக்காது. go/r-bg-fgs-restriction என்பதைப் பார்த்து பிழை அறிக்கை ஒன்றைச் சமர்ப்பிக்கவும்."</string>
<string name="safe_media_volume_warning" product="default" msgid="3751676824423049994">"பரிந்துரைத்த அளவை விட ஒலியை அதிகரிக்கவா?\n\nநீண்ட நேரத்திற்கு அதிகளவில் ஒலி கேட்பது கேட்கும் திறனைப் பாதிக்கலாம்."</string>
<string name="accessibility_shortcut_warning_dialog_title" msgid="4017995837692622933">"அணுகல்தன்மை ஷார்ட்கட்டைப் பயன்படுத்தவா?"</string>
- <!-- no translation found for accessibility_shortcut_toogle_warning (4161716521310929544) -->
+ <string name="accessibility_shortcut_toogle_warning" msgid="4161716521310929544">"ஷார்ட்கட் இயக்கத்தில் இருக்கும்போது ஒலியளவு பட்டன்கள் இரண்டையும் 3 வினாடிகளுக்கு அழுத்தினால் அணுகல்தன்மை அம்சம் இயக்கப்படும்."</string>
+ <!-- no translation found for accessibility_select_shortcut_menu_title (7310194076629867377) -->
+ <skip />
+ <!-- no translation found for accessibility_edit_shortcut_menu_button_title (6096484087245145325) -->
+ <skip />
+ <!-- no translation found for accessibility_edit_shortcut_menu_volume_title (4849108668454490699) -->
<skip />
<string name="edit_accessibility_shortcut_menu_button" msgid="8885752738733772935">"ஷார்ட்கட்களை மாற்று"</string>
<string name="cancel_accessibility_shortcut_menu_button" msgid="1817413122335452474">"ரத்துசெய்"</string>
@@ -2038,24 +2036,29 @@
<string name="as_app_forced_to_restricted_bucket" msgid="8233871289353898964">"<xliff:g id="PACKAGE_NAME">%1$s</xliff:g> என்பதை வரம்பிடப்பட்ட பக்கெட்திற்குள் சேர்க்கப்பட்டது"</string>
<string name="resolver_personal_tab" msgid="2051260504014442073">"தனிப்பட்ட சுயவிவரம்"</string>
<string name="resolver_work_tab" msgid="2690019516263167035">"பணிச் சுயவிவரம்"</string>
- <!-- no translation found for resolver_cant_share_with_work_apps (7539495559434146897) -->
+ <!-- no translation found for resolver_personal_tab_accessibility (5739524949153091224) -->
<skip />
- <!-- no translation found for resolver_cant_share_with_personal_apps (8020581735267157241) -->
+ <!-- no translation found for resolver_work_tab_accessibility (4753168230363802734) -->
<skip />
- <!-- no translation found for resolver_cant_share_cross_profile_explanation (3536237105241882679) -->
+ <string name="resolver_cant_share_with_work_apps" msgid="7539495559434146897">"பணி ஆப்ஸுக்குப் பகிர முடியாது"</string>
+ <string name="resolver_cant_share_with_personal_apps" msgid="8020581735267157241">"தனிப்பட்ட ஆப்ஸுக்குப் பகிர முடியாது"</string>
+ <!-- no translation found for resolver_cant_share_cross_profile_explanation (5556640604460901386) -->
<skip />
- <!-- no translation found for resolver_turn_on_work_apps (8987359079870455469) -->
+ <!-- no translation found for resolver_cant_access_work_apps (375634344111233790) -->
<skip />
- <!-- no translation found for resolver_turn_on_work_apps_explanation (6322467455509618928) -->
+ <!-- no translation found for resolver_cant_access_work_apps_explanation (3958762224516867388) -->
<skip />
- <!-- no translation found for resolver_no_apps_available (7710339903040989654) -->
+ <!-- no translation found for resolver_cant_access_personal_apps (1953215925406474177) -->
<skip />
- <!-- no translation found for resolver_no_apps_available_explanation (4662694431121196560) -->
+ <!-- no translation found for resolver_cant_access_personal_apps_explanation (1725572276741281136) -->
<skip />
- <!-- no translation found for resolver_switch_on_work (8294542702883688533) -->
+ <!-- no translation found for resolver_turn_on_work_apps_share (619263911204978175) -->
<skip />
- <!-- no translation found for permlab_accessCallAudio (1682957511874097664) -->
+ <!-- no translation found for resolver_turn_on_work_apps_view (3073389230905543680) -->
<skip />
- <!-- no translation found for permdesc_accessCallAudio (8448360894684277823) -->
+ <string name="resolver_no_apps_available" msgid="7710339903040989654">"ஆப்ஸ் இல்லை"</string>
+ <!-- no translation found for resolver_switch_on_work (2873009160846966379) -->
<skip />
+ <string name="permlab_accessCallAudio" msgid="1682957511874097664">"அழைப்புகளின்போது ரெக்கார்டு செய்தல் அல்லது ஆடியோவைப் பிளே செய்தல்"</string>
+ <string name="permdesc_accessCallAudio" msgid="8448360894684277823">"இயல்பான டயலர் ஆப்ஸாக இதை அமைக்கும்போது, அழைப்புகளை ரெக்கார்டு செய்ய அல்லது ஆடியோவைப் பிளே செய்ய இதை அனுமதிக்கும்."</string>
</resources>
diff --git a/core/res/res/values-te/strings.xml b/core/res/res/values-te/strings.xml
index f6cc17e314f2..130efbdf52a6 100644
--- a/core/res/res/values-te/strings.xml
+++ b/core/res/res/values-te/strings.xml
@@ -249,10 +249,8 @@
<item quantity="other">బగ్ నివేదిక కోసం <xliff:g id="NUMBER_1">%d</xliff:g> సెకన్లలో స్క్రీన్‌షాట్ తీయబోతోంది.</item>
<item quantity="one">బగ్ నివేదిక కోసం <xliff:g id="NUMBER_0">%d</xliff:g> సెకనులో స్క్రీన్‌షాట్ తీయబోతోంది.</item>
</plurals>
- <!-- no translation found for bugreport_screenshot_success_toast (7986095104151473745) -->
- <skip />
- <!-- no translation found for bugreport_screenshot_failure_toast (6736320861311294294) -->
- <skip />
+ <string name="bugreport_screenshot_success_toast" msgid="7986095104151473745">"బగ్ నివేదికతో ఉన్న స్క్రీన్‌షాట్ తీయబడింది"</string>
+ <string name="bugreport_screenshot_failure_toast" msgid="6736320861311294294">"బగ్ నివేదికతో ఉన్న స్క్రీన్‌షాట్‌ను తీయడం విఫలమైంది"</string>
<string name="global_action_toggle_silent_mode" msgid="8464352592860372188">"నిశ్శబ్ద మోడ్"</string>
<string name="global_action_silent_mode_on_status" msgid="2371892537738632013">"ధ్వని ఆఫ్‌లో ఉంది"</string>
<string name="global_action_silent_mode_off_status" msgid="6608006545950920042">"ధ్వని ఆన్‌లో ఉంది"</string>
@@ -454,9 +452,11 @@
<string name="permdesc_acceptHandovers" msgid="7129026180128626870">"మరో యాప్‌లో ప్రారంభించిన కాల్‌ని కొనసాగించడానికి యాప్‌ని అనుమతిస్తుంది."</string>
<string name="permlab_readPhoneNumbers" msgid="5668704794723365628">"ఫోన్ నంబర్‌లను చదువు"</string>
<string name="permdesc_readPhoneNumbers" msgid="7368652482818338871">"పరికరం యొక్క ఫోన్ నంబర్‌లను యాక్సెస్ చేయడానికి యాప్‌ను అనుమతిస్తుంది."</string>
+ <string name="permlab_wakeLock" product="automotive" msgid="1904736682319375676">"కార్ స్క్రీన్‌ను ఆన్ చేసి ఉంచండి"</string>
<string name="permlab_wakeLock" product="tablet" msgid="1527660973931694000">"టాబ్లెట్‌ను నిద్రావస్థకు వెళ్లనీయకుండా నిరోధించడం"</string>
<string name="permlab_wakeLock" product="tv" msgid="2856941418123343518">"స్లీప్ మోడ్‌కి వెళ్లకుండా మీ Android TV పరికరాన్ని నివారించండి"</string>
<string name="permlab_wakeLock" product="default" msgid="569409726861695115">"ఫోన్‌ను స్లీప్ మోడ్‌లోకి వెళ్లనీయకుండా నిరోధించగలగడం"</string>
+ <string name="permdesc_wakeLock" product="automotive" msgid="5995045369683254571">"కార్ స్క్రీన్ ఆన్ చేసి ఉంచడానికి ఈ యాప్‌ను అనుమతిస్తుంది."</string>
<string name="permdesc_wakeLock" product="tablet" msgid="2441742939101526277">"నిద్రావస్థకి వెళ్లకుండా టాబ్లెట్‌ను నిరోధించడానికి యాప్‌ను అనుమతిస్తుంది."</string>
<string name="permdesc_wakeLock" product="tv" msgid="2329298966735118796">"మీ Android TV పరికరం స్లీప్ మోడ్‌లోకి వెళ్లకుండా నివారించడానికి యాప్‌ని అనుమతిస్తుంది."</string>
<string name="permdesc_wakeLock" product="default" msgid="3689523792074007163">"నిద్రావస్థకి వెళ్లకుండా ఫోన్‌ను నిరోధించడానికి యాప్‌ను అనుమతిస్తుంది."</string>
@@ -1631,6 +1631,12 @@
<string name="safe_media_volume_warning" product="default" msgid="3751676824423049994">"వాల్యూమ్‌ను సిఫార్సు చేయబడిన స్థాయి కంటే ఎక్కువగా పెంచాలా?\n\nసుదీర్ఘ వ్యవధుల పాటు అధిక వాల్యూమ్‌లో వినడం వలన మీ వినికిడి శక్తి దెబ్బ తినవచ్చు."</string>
<string name="accessibility_shortcut_warning_dialog_title" msgid="4017995837692622933">"యాక్సెస్ సామర్థ్యం షార్ట్‌కట్‌ను ఉపయోగించాలా?"</string>
<string name="accessibility_shortcut_toogle_warning" msgid="4161716521310929544">"షార్ట్‌కట్ ఆన్ చేసి ఉన్నప్పుడు, రెండు వాల్యూమ్ బటన్‌లను 3 సెకన్ల పాటు నొక్కి ఉంచితే యాక్సెస్ సౌలభ్య ఫీచర్ ప్రారంభం అవుతుంది."</string>
+ <!-- no translation found for accessibility_select_shortcut_menu_title (7310194076629867377) -->
+ <skip />
+ <!-- no translation found for accessibility_edit_shortcut_menu_button_title (6096484087245145325) -->
+ <skip />
+ <!-- no translation found for accessibility_edit_shortcut_menu_volume_title (4849108668454490699) -->
+ <skip />
<string name="edit_accessibility_shortcut_menu_button" msgid="8885752738733772935">"షార్ట్‌కట్‌లను ఎడిట్ చేయి"</string>
<string name="cancel_accessibility_shortcut_menu_button" msgid="1817413122335452474">"రద్దు చేయి"</string>
<string name="disable_accessibility_shortcut" msgid="5806091378745232383">"సత్వరమార్గాన్ని ఆఫ్ చేయి"</string>
@@ -2028,14 +2034,29 @@
<string name="as_app_forced_to_restricted_bucket" msgid="8233871289353898964">"<xliff:g id="PACKAGE_NAME">%1$s</xliff:g> పరిమితం చేయబడిన బకెట్‌లో ఉంచబడింది"</string>
<string name="resolver_personal_tab" msgid="2051260504014442073">"వ్యక్తిగతం"</string>
<string name="resolver_work_tab" msgid="2690019516263167035">"కార్యాలయం"</string>
+ <!-- no translation found for resolver_personal_tab_accessibility (5739524949153091224) -->
+ <skip />
+ <!-- no translation found for resolver_work_tab_accessibility (4753168230363802734) -->
+ <skip />
<string name="resolver_cant_share_with_work_apps" msgid="7539495559434146897">"వర్క్ యాప్‌లతో షేర్ చేయడం సాధ్యపడదు"</string>
<string name="resolver_cant_share_with_personal_apps" msgid="8020581735267157241">"వ్యక్తిగత యాప్‌లతో షేర్ చేయడం సాధ్యపడదు"</string>
- <string name="resolver_cant_share_cross_profile_explanation" msgid="3536237105241882679">"వ్యక్తిగత, వర్క్ యాప్‌ల మధ్య షేర్ చేయడాన్ని మీ IT అడ్మిన్ బ్లాక్ చేశారు"</string>
- <string name="resolver_turn_on_work_apps" msgid="8987359079870455469">"వర్క్ యాప్‌లను ఆన్ చేయండి"</string>
- <string name="resolver_turn_on_work_apps_explanation" msgid="6322467455509618928">"వర్క్ యాప్‌లు &amp; కాంటాక్ట్‌లను యాక్సెస్ చేయడానికి వర్క్ యాప్‌లను ఆన్ చేయండి"</string>
+ <!-- no translation found for resolver_cant_share_cross_profile_explanation (5556640604460901386) -->
+ <skip />
+ <!-- no translation found for resolver_cant_access_work_apps (375634344111233790) -->
+ <skip />
+ <!-- no translation found for resolver_cant_access_work_apps_explanation (3958762224516867388) -->
+ <skip />
+ <!-- no translation found for resolver_cant_access_personal_apps (1953215925406474177) -->
+ <skip />
+ <!-- no translation found for resolver_cant_access_personal_apps_explanation (1725572276741281136) -->
+ <skip />
+ <!-- no translation found for resolver_turn_on_work_apps_share (619263911204978175) -->
+ <skip />
+ <!-- no translation found for resolver_turn_on_work_apps_view (3073389230905543680) -->
+ <skip />
<string name="resolver_no_apps_available" msgid="7710339903040989654">"యాప్‌లు ఏవీ అందుబాటులో లేవు"</string>
- <string name="resolver_no_apps_available_explanation" msgid="4662694431121196560">"మేము యాప్‌లు వేటినీ కనుగొనలేకపోయాము"</string>
- <string name="resolver_switch_on_work" msgid="8294542702883688533">"కార్యాలయ ప్రొఫైల్‌ను ఆన్ చేయి"</string>
+ <!-- no translation found for resolver_switch_on_work (2873009160846966379) -->
+ <skip />
<string name="permlab_accessCallAudio" msgid="1682957511874097664">"టెలిఫోనీ కాల్స్‌లో రికార్డ్ చేయండి లేదా ఆడియో ప్లే చేయండి"</string>
<string name="permdesc_accessCallAudio" msgid="8448360894684277823">"డిఫాల్ట్ డయలర్ యాప్‌గా కేటాయించినప్పుడు, టెలిఫోనీ కాల్స్‌లో రికార్డ్ చేయడానికి లేదా ఆడియో ప్లే చేయడానికి ఈ యాప్‌ను అనుమతిస్తుంది."</string>
</resources>
diff --git a/core/res/res/values-th/strings.xml b/core/res/res/values-th/strings.xml
index 90831d71f1d1..3ab4170a4dec 100644
--- a/core/res/res/values-th/strings.xml
+++ b/core/res/res/values-th/strings.xml
@@ -249,10 +249,8 @@
<item quantity="other">จะจับภาพหน้าจอสำหรับรายงานข้อบกพร่องใน <xliff:g id="NUMBER_1">%d</xliff:g> วินาที</item>
<item quantity="one">จะจับภาพหน้าจอสำหรับรายงานข้อบกพร่องใน <xliff:g id="NUMBER_0">%d</xliff:g> วินาที</item>
</plurals>
- <!-- no translation found for bugreport_screenshot_success_toast (7986095104151473745) -->
- <skip />
- <!-- no translation found for bugreport_screenshot_failure_toast (6736320861311294294) -->
- <skip />
+ <string name="bugreport_screenshot_success_toast" msgid="7986095104151473745">"ถ่ายภาพหน้าจอด้วยรายงานข้อบกพร่องแล้ว"</string>
+ <string name="bugreport_screenshot_failure_toast" msgid="6736320861311294294">"ถ่ายภาพหน้าจอด้วยรายงานข้อบกพร่องไม่สำเร็จ"</string>
<string name="global_action_toggle_silent_mode" msgid="8464352592860372188">"โหมดปิดเสียง"</string>
<string name="global_action_silent_mode_on_status" msgid="2371892537738632013">"ปิดเสียงไว้"</string>
<string name="global_action_silent_mode_off_status" msgid="6608006545950920042">"เปิดเสียงแล้ว"</string>
@@ -454,9 +452,11 @@
<string name="permdesc_acceptHandovers" msgid="7129026180128626870">"อนุญาตให้แอปต่อสายที่เริ่มจากแอปอื่น"</string>
<string name="permlab_readPhoneNumbers" msgid="5668704794723365628">"อ่านหมายเลขโทรศัพท์"</string>
<string name="permdesc_readPhoneNumbers" msgid="7368652482818338871">"อนุญาตให้แอปเข้าถึงหมายเลขโทรศัพท์ของอุปกรณ์นี้"</string>
+ <string name="permlab_wakeLock" product="automotive" msgid="1904736682319375676">"เปิดหน้าจอในรถไว้"</string>
<string name="permlab_wakeLock" product="tablet" msgid="1527660973931694000">"ป้องกันไม่ให้แท็บเล็ตเข้าสู่โหมดสลีป"</string>
<string name="permlab_wakeLock" product="tv" msgid="2856941418123343518">"ป้องกันไม่ให้อุปกรณ์ Android TV เข้าสู่โหมดสลีป"</string>
<string name="permlab_wakeLock" product="default" msgid="569409726861695115">"ป้องกันไม่ให้โทรศัพท์เข้าโหมดสลีป"</string>
+ <string name="permdesc_wakeLock" product="automotive" msgid="5995045369683254571">"อนุญาตให้แอปเปิดหน้าจอในรถไว้"</string>
<string name="permdesc_wakeLock" product="tablet" msgid="2441742939101526277">"อนุญาตให้แอปพลิเคชันป้องกันไม่ให้แท็บเล็ตเข้าสู่โหมดสลีป"</string>
<string name="permdesc_wakeLock" product="tv" msgid="2329298966735118796">"อนุญาตให้แอปป้องกันไม่ให้อุปกรณ์ Android TV เข้าสู่โหมดสลีป"</string>
<string name="permdesc_wakeLock" product="default" msgid="3689523792074007163">"อนุญาตให้แอปพลิเคชันป้องกันไม่ให้โทรศัพท์เข้าสู่โหมดสลีป"</string>
@@ -1631,6 +1631,12 @@
<string name="safe_media_volume_warning" product="default" msgid="3751676824423049994">"นี่เป็นการเพิ่มระดับเสียงเกินระดับที่แนะนำ\n\nการฟังเสียงดังเป็นเวลานานอาจทำให้การได้ยินของคุณบกพร่องได้"</string>
<string name="accessibility_shortcut_warning_dialog_title" msgid="4017995837692622933">"ใช้ทางลัดการช่วยเหลือพิเศษไหม"</string>
<string name="accessibility_shortcut_toogle_warning" msgid="4161716521310929544">"เมื่อทางลัดเปิดอยู่ การกดปุ่มปรับระดับเสียงทั้ง 2 ปุ่มนาน 3 วินาทีจะเริ่มฟีเจอร์การช่วยเหลือพิเศษ"</string>
+ <!-- no translation found for accessibility_select_shortcut_menu_title (7310194076629867377) -->
+ <skip />
+ <!-- no translation found for accessibility_edit_shortcut_menu_button_title (6096484087245145325) -->
+ <skip />
+ <!-- no translation found for accessibility_edit_shortcut_menu_volume_title (4849108668454490699) -->
+ <skip />
<string name="edit_accessibility_shortcut_menu_button" msgid="8885752738733772935">"แก้ไขทางลัด"</string>
<string name="cancel_accessibility_shortcut_menu_button" msgid="1817413122335452474">"ยกเลิก"</string>
<string name="disable_accessibility_shortcut" msgid="5806091378745232383">"ปิดทางลัด"</string>
@@ -1853,8 +1859,7 @@
<string name="default_notification_channel_label" msgid="3697928973567217330">"ไม่จัดอยู่ในหมวดหมู่ใดๆ"</string>
<string name="importance_from_user" msgid="2782756722448800447">"คุณตั้งค่าความสำคัญของการแจ้งเตือนเหล่านี้"</string>
<string name="importance_from_person" msgid="4235804979664465383">"ข้อความนี้สำคัญเนื่องจากบุคคลที่เกี่ยวข้อง"</string>
- <!-- no translation found for notification_history_title_placeholder (7748630986182249599) -->
- <skip />
+ <string name="notification_history_title_placeholder" msgid="7748630986182249599">"การแจ้งเตือนที่กำหนดเองของแอป"</string>
<string name="user_creation_account_exists" msgid="2239146360099708035">"อนุญาตให้ <xliff:g id="APP">%1$s</xliff:g> สร้างผู้ใช้ใหม่ด้วย <xliff:g id="ACCOUNT">%2$s</xliff:g> ไหม (มีผู้ใช้ที่มีบัญชีนี้อยู่แล้ว)"</string>
<string name="user_creation_adding" msgid="7305185499667958364">"อนุญาตให้ <xliff:g id="APP">%1$s</xliff:g> สร้างผู้ใช้ใหม่ด้วย <xliff:g id="ACCOUNT">%2$s</xliff:g> ไหม"</string>
<string name="language_selection_title" msgid="52674936078683285">"เพิ่มภาษา"</string>
@@ -2028,14 +2033,29 @@
<string name="as_app_forced_to_restricted_bucket" msgid="8233871289353898964">"ใส่ <xliff:g id="PACKAGE_NAME">%1$s</xliff:g> ในที่เก็บข้อมูลที่ถูกจำกัดแล้ว"</string>
<string name="resolver_personal_tab" msgid="2051260504014442073">"ส่วนตัว"</string>
<string name="resolver_work_tab" msgid="2690019516263167035">"งาน"</string>
+ <!-- no translation found for resolver_personal_tab_accessibility (5739524949153091224) -->
+ <skip />
+ <!-- no translation found for resolver_work_tab_accessibility (4753168230363802734) -->
+ <skip />
<string name="resolver_cant_share_with_work_apps" msgid="7539495559434146897">"แชร์ด้วยแอปงานไม่ได้"</string>
<string name="resolver_cant_share_with_personal_apps" msgid="8020581735267157241">"แชร์ด้วยแอปส่วนตัวไม่ได้"</string>
- <string name="resolver_cant_share_cross_profile_explanation" msgid="3536237105241882679">"ผู้ดูแลระบบไอทีบล็อกการแชร์ระหว่างแอปส่วนตัวและแอปงาน"</string>
- <string name="resolver_turn_on_work_apps" msgid="8987359079870455469">"เปิดแอปงาน"</string>
- <string name="resolver_turn_on_work_apps_explanation" msgid="6322467455509618928">"เปิดแอปงานเพื่อเข้าถึงแอปงานและรายชื่อติดต่อ"</string>
+ <!-- no translation found for resolver_cant_share_cross_profile_explanation (5556640604460901386) -->
+ <skip />
+ <!-- no translation found for resolver_cant_access_work_apps (375634344111233790) -->
+ <skip />
+ <!-- no translation found for resolver_cant_access_work_apps_explanation (3958762224516867388) -->
+ <skip />
+ <!-- no translation found for resolver_cant_access_personal_apps (1953215925406474177) -->
+ <skip />
+ <!-- no translation found for resolver_cant_access_personal_apps_explanation (1725572276741281136) -->
+ <skip />
+ <!-- no translation found for resolver_turn_on_work_apps_share (619263911204978175) -->
+ <skip />
+ <!-- no translation found for resolver_turn_on_work_apps_view (3073389230905543680) -->
+ <skip />
<string name="resolver_no_apps_available" msgid="7710339903040989654">"ไม่มีแอป"</string>
- <string name="resolver_no_apps_available_explanation" msgid="4662694431121196560">"เราไม่พบแอปใดเลย"</string>
- <string name="resolver_switch_on_work" msgid="8294542702883688533">"เปิดโปรไฟล์งาน"</string>
+ <!-- no translation found for resolver_switch_on_work (2873009160846966379) -->
+ <skip />
<string name="permlab_accessCallAudio" msgid="1682957511874097664">"บันทึกหรือเปิดเสียงในสายโทรศัพท์"</string>
<string name="permdesc_accessCallAudio" msgid="8448360894684277823">"อนุญาตให้แอปนี้ (เมื่อกำหนดให้เป็นแอปโทรออกเริ่มต้น) บันทึกหรือเปิดเสียงในสายโทรศัพท์ได้"</string>
</resources>
diff --git a/core/res/res/values-tl/strings.xml b/core/res/res/values-tl/strings.xml
index d65c2147251f..25021372bffb 100644
--- a/core/res/res/values-tl/strings.xml
+++ b/core/res/res/values-tl/strings.xml
@@ -249,10 +249,8 @@
<item quantity="one">Kukuha ng screenshot para sa ulat ng bug sa loob ng <xliff:g id="NUMBER_1">%d</xliff:g> segundo.</item>
<item quantity="other">Kukuha ng screenshot para sa ulat ng bug sa loob ng <xliff:g id="NUMBER_1">%d</xliff:g> na segundo.</item>
</plurals>
- <!-- no translation found for bugreport_screenshot_success_toast (7986095104151473745) -->
- <skip />
- <!-- no translation found for bugreport_screenshot_failure_toast (6736320861311294294) -->
- <skip />
+ <string name="bugreport_screenshot_success_toast" msgid="7986095104151473745">"Nakakuha ng screenshot kasama ng ulat ng bug"</string>
+ <string name="bugreport_screenshot_failure_toast" msgid="6736320861311294294">"Hindi nakakuha ng screenshot kasama ng ulat ng bug"</string>
<string name="global_action_toggle_silent_mode" msgid="8464352592860372188">"Silent mode"</string>
<string name="global_action_silent_mode_on_status" msgid="2371892537738632013">"Naka-OFF ang tunog"</string>
<string name="global_action_silent_mode_off_status" msgid="6608006545950920042">"Naka-ON ang sound"</string>
@@ -454,9 +452,11 @@
<string name="permdesc_acceptHandovers" msgid="7129026180128626870">"Pinapayagan ang app na ipagpatuloy ang isang tawag na sinimulan sa ibang app."</string>
<string name="permlab_readPhoneNumbers" msgid="5668704794723365628">"basahin ang mga numero ng telepono"</string>
<string name="permdesc_readPhoneNumbers" msgid="7368652482818338871">"Pinapayagan ang app na i-access ang mga numero ng telepono ng device."</string>
+ <string name="permlab_wakeLock" product="automotive" msgid="1904736682319375676">"panatilihing naka-on ang screen ng sasakyan"</string>
<string name="permlab_wakeLock" product="tablet" msgid="1527660973931694000">"pigilan ang tablet mula sa pag-sleep"</string>
<string name="permlab_wakeLock" product="tv" msgid="2856941418123343518">"pigilang mag-sleep ang iyong Android TV device"</string>
<string name="permlab_wakeLock" product="default" msgid="569409726861695115">"pigilan ang telepono mula sa paghinto"</string>
+ <string name="permdesc_wakeLock" product="automotive" msgid="5995045369683254571">"Pinapayagan ang app na panatilihing naka-on ang screen ng sasakyan."</string>
<string name="permdesc_wakeLock" product="tablet" msgid="2441742939101526277">"Pinapayagan ang app na pigilan ang tablet mula sa pag-sleep."</string>
<string name="permdesc_wakeLock" product="tv" msgid="2329298966735118796">"Nagbibigay-daan sa app na pigilang mag-sleep ang iyong Android TV device."</string>
<string name="permdesc_wakeLock" product="default" msgid="3689523792074007163">"Pinapayagan ang app na pigilan ang telepono mula sa pag-sleep."</string>
@@ -1631,6 +1631,12 @@
<string name="safe_media_volume_warning" product="default" msgid="3751676824423049994">"Lakasan ang volume nang lagpas sa inirerekomendang antas?\n\nMaaaring mapinsala ng pakikinig sa malakas na volume sa loob ng mahahabang panahon ang iyong pandinig."</string>
<string name="accessibility_shortcut_warning_dialog_title" msgid="4017995837692622933">"Gagamitin ang Shortcut sa Pagiging Accessible?"</string>
<string name="accessibility_shortcut_toogle_warning" msgid="4161716521310929544">"Kapag naka-on ang shortcut, magsisimula ang isang feature ng pagiging naa-access kapag pinindot ang parehong button ng volume."</string>
+ <!-- no translation found for accessibility_select_shortcut_menu_title (7310194076629867377) -->
+ <skip />
+ <!-- no translation found for accessibility_edit_shortcut_menu_button_title (6096484087245145325) -->
+ <skip />
+ <!-- no translation found for accessibility_edit_shortcut_menu_volume_title (4849108668454490699) -->
+ <skip />
<string name="edit_accessibility_shortcut_menu_button" msgid="8885752738733772935">"I-edit ang mga shortcut"</string>
<string name="cancel_accessibility_shortcut_menu_button" msgid="1817413122335452474">"Kanselahin"</string>
<string name="disable_accessibility_shortcut" msgid="5806091378745232383">"I-off ang Shortcut"</string>
@@ -1853,8 +1859,7 @@
<string name="default_notification_channel_label" msgid="3697928973567217330">"Di-nakategorya"</string>
<string name="importance_from_user" msgid="2782756722448800447">"Ikaw ang magtatakda sa kahalagahan ng mga notification na ito."</string>
<string name="importance_from_person" msgid="4235804979664465383">"Mahalaga ito dahil sa mga taong kasangkot."</string>
- <!-- no translation found for notification_history_title_placeholder (7748630986182249599) -->
- <skip />
+ <string name="notification_history_title_placeholder" msgid="7748630986182249599">"Custom na notification ng app"</string>
<string name="user_creation_account_exists" msgid="2239146360099708035">"Payagan ang <xliff:g id="APP">%1$s</xliff:g> na gumawa ng bagong User sa <xliff:g id="ACCOUNT">%2$s</xliff:g> (mayroon nang User sa account na ito) ?"</string>
<string name="user_creation_adding" msgid="7305185499667958364">"Payagan ang <xliff:g id="APP">%1$s</xliff:g> na gumawa ng bagong User sa <xliff:g id="ACCOUNT">%2$s</xliff:g> ?"</string>
<string name="language_selection_title" msgid="52674936078683285">"Magdagdag ng wika"</string>
@@ -2028,14 +2033,29 @@
<string name="as_app_forced_to_restricted_bucket" msgid="8233871289353898964">"Inilagay ang <xliff:g id="PACKAGE_NAME">%1$s</xliff:g> sa PINAGHIHIGPITANG bucket"</string>
<string name="resolver_personal_tab" msgid="2051260504014442073">"Personal"</string>
<string name="resolver_work_tab" msgid="2690019516263167035">"Trabaho"</string>
+ <!-- no translation found for resolver_personal_tab_accessibility (5739524949153091224) -->
+ <skip />
+ <!-- no translation found for resolver_work_tab_accessibility (4753168230363802734) -->
+ <skip />
<string name="resolver_cant_share_with_work_apps" msgid="7539495559434146897">"Hindi puwedeng magbahagi sa mga app para sa trabaho"</string>
<string name="resolver_cant_share_with_personal_apps" msgid="8020581735267157241">"Hindi puwedeng magbahagi sa mga personal na app"</string>
- <string name="resolver_cant_share_cross_profile_explanation" msgid="3536237105241882679">"Na-block ng iyong IT admin ang pagbabahagi sa pagitan ng mga personal na app at app para sa trabaho"</string>
- <string name="resolver_turn_on_work_apps" msgid="8987359079870455469">"I-on ang mga app para sa trabaho"</string>
- <string name="resolver_turn_on_work_apps_explanation" msgid="6322467455509618928">"I-on ang mga app para sa trabaho para ma-access ang mga app at contact para sa trabaho"</string>
+ <!-- no translation found for resolver_cant_share_cross_profile_explanation (5556640604460901386) -->
+ <skip />
+ <!-- no translation found for resolver_cant_access_work_apps (375634344111233790) -->
+ <skip />
+ <!-- no translation found for resolver_cant_access_work_apps_explanation (3958762224516867388) -->
+ <skip />
+ <!-- no translation found for resolver_cant_access_personal_apps (1953215925406474177) -->
+ <skip />
+ <!-- no translation found for resolver_cant_access_personal_apps_explanation (1725572276741281136) -->
+ <skip />
+ <!-- no translation found for resolver_turn_on_work_apps_share (619263911204978175) -->
+ <skip />
+ <!-- no translation found for resolver_turn_on_work_apps_view (3073389230905543680) -->
+ <skip />
<string name="resolver_no_apps_available" msgid="7710339903040989654">"Walang available na app"</string>
- <string name="resolver_no_apps_available_explanation" msgid="4662694431121196560">"Wala kaming makitang anumang app"</string>
- <string name="resolver_switch_on_work" msgid="8294542702883688533">"I-on ang pantrabahong profile"</string>
+ <!-- no translation found for resolver_switch_on_work (2873009160846966379) -->
+ <skip />
<string name="permlab_accessCallAudio" msgid="1682957511874097664">"Mag-record o mag-play ng audio sa mga tawag sa telephony"</string>
<string name="permdesc_accessCallAudio" msgid="8448360894684277823">"Papayagan ang app na ito na mag-record o mag-play ng audio sa mga tawag sa telephony kapag naitalaga bilang default na dialer application."</string>
</resources>
diff --git a/core/res/res/values-tr/strings.xml b/core/res/res/values-tr/strings.xml
index 718df3d72f8e..245b4a1318eb 100644
--- a/core/res/res/values-tr/strings.xml
+++ b/core/res/res/values-tr/strings.xml
@@ -249,10 +249,8 @@
<item quantity="other"><xliff:g id="NUMBER_1">%d</xliff:g> saniye içinde hata raporu ekran görüntüsü alınıyor.</item>
<item quantity="one">Hata raporu ekran görüntüsü <xliff:g id="NUMBER_0">%d</xliff:g> saniye içinde alınacak.</item>
</plurals>
- <!-- no translation found for bugreport_screenshot_success_toast (7986095104151473745) -->
- <skip />
- <!-- no translation found for bugreport_screenshot_failure_toast (6736320861311294294) -->
- <skip />
+ <string name="bugreport_screenshot_success_toast" msgid="7986095104151473745">"Hata raporunun ekran görüntüsü alındı"</string>
+ <string name="bugreport_screenshot_failure_toast" msgid="6736320861311294294">"Hata raporunun ekran görüntüsü alınamadı"</string>
<string name="global_action_toggle_silent_mode" msgid="8464352592860372188">"Sessiz mod"</string>
<string name="global_action_silent_mode_on_status" msgid="2371892537738632013">"Ses KAPALI"</string>
<string name="global_action_silent_mode_off_status" msgid="6608006545950920042">"Ses AÇIK"</string>
@@ -454,9 +452,11 @@
<string name="permdesc_acceptHandovers" msgid="7129026180128626870">"Uygulamanın, başka bir uygulamada başlatılan çağrıya devam etmesine izin verir."</string>
<string name="permlab_readPhoneNumbers" msgid="5668704794723365628">"telefon numaralarını oku"</string>
<string name="permdesc_readPhoneNumbers" msgid="7368652482818338871">"Uygulamaya, cihazınızın telefon numaralarına erişme izni verir."</string>
+ <string name="permlab_wakeLock" product="automotive" msgid="1904736682319375676">"arabanın ekranını açık tutma"</string>
<string name="permlab_wakeLock" product="tablet" msgid="1527660973931694000">"tabletin uykuya geçmesini önle"</string>
<string name="permlab_wakeLock" product="tv" msgid="2856941418123343518">"Android TV cihazınızın uyku moduna geçmesini önleme"</string>
<string name="permlab_wakeLock" product="default" msgid="569409726861695115">"telefonun uykuya geçmesini önleme"</string>
+ <string name="permdesc_wakeLock" product="automotive" msgid="5995045369683254571">"Uygulamaya, arabanın ekranını açık tutmaya izin verir."</string>
<string name="permdesc_wakeLock" product="tablet" msgid="2441742939101526277">"Uygulamaya, tabletin uykuya geçmesini önleme izni verir."</string>
<string name="permdesc_wakeLock" product="tv" msgid="2329298966735118796">"Uygulamaya, Android TV cihazınızın uyku moduna geçmesini önleme izni verir."</string>
<string name="permdesc_wakeLock" product="default" msgid="3689523792074007163">"Uygulamaya, telefonun uykuya geçmesini önleme izni verir."</string>
@@ -1631,6 +1631,12 @@
<string name="safe_media_volume_warning" product="default" msgid="3751676824423049994">"Ses seviyesi önerilen düzeyin üzerine yükseltilsin mi?\n\nUzun süre yüksek ses seviyesinde dinlemek işitme duyunuza zarar verebilir."</string>
<string name="accessibility_shortcut_warning_dialog_title" msgid="4017995837692622933">"Erişilebilirlik Kısayolu Kullanılsın mı?"</string>
<string name="accessibility_shortcut_toogle_warning" msgid="4161716521310929544">"Kısayol açıkken ses düğmelerinin ikisini birden 3 saniyeliğine basılı tutmanız bir erişilebilirlik özelliğini başlatır."</string>
+ <!-- no translation found for accessibility_select_shortcut_menu_title (7310194076629867377) -->
+ <skip />
+ <!-- no translation found for accessibility_edit_shortcut_menu_button_title (6096484087245145325) -->
+ <skip />
+ <!-- no translation found for accessibility_edit_shortcut_menu_volume_title (4849108668454490699) -->
+ <skip />
<string name="edit_accessibility_shortcut_menu_button" msgid="8885752738733772935">"Kısayolları düzenle"</string>
<string name="cancel_accessibility_shortcut_menu_button" msgid="1817413122335452474">"İptal"</string>
<string name="disable_accessibility_shortcut" msgid="5806091378745232383">"Kısayolu Kapat"</string>
@@ -1853,8 +1859,7 @@
<string name="default_notification_channel_label" msgid="3697928973567217330">"Kategorize edilmemiş"</string>
<string name="importance_from_user" msgid="2782756722448800447">"Bu bildirimlerin önem derecesini ayarladınız."</string>
<string name="importance_from_person" msgid="4235804979664465383">"Bu, dahil olan kişiler nedeniyle önemlidir."</string>
- <!-- no translation found for notification_history_title_placeholder (7748630986182249599) -->
- <skip />
+ <string name="notification_history_title_placeholder" msgid="7748630986182249599">"Özel uygulama bildirimi"</string>
<string name="user_creation_account_exists" msgid="2239146360099708035">"<xliff:g id="APP">%1$s</xliff:g> uygulamasının <xliff:g id="ACCOUNT">%2$s</xliff:g> hesabına sahip yeni bir Kullanıcı eklemesine izin verilsin mi (bu hesaba sahip bir kullanıcı zaten var)?"</string>
<string name="user_creation_adding" msgid="7305185499667958364">"<xliff:g id="APP">%1$s</xliff:g> uygulamasının <xliff:g id="ACCOUNT">%2$s</xliff:g> hesabına sahip yeni bir Kullanıcı eklemesine izin verilsin mi?"</string>
<string name="language_selection_title" msgid="52674936078683285">"Dil ekleyin"</string>
@@ -2028,14 +2033,29 @@
<string name="as_app_forced_to_restricted_bucket" msgid="8233871289353898964">"<xliff:g id="PACKAGE_NAME">%1$s</xliff:g> KISITLANMIŞ gruba yerleştirildi"</string>
<string name="resolver_personal_tab" msgid="2051260504014442073">"Kişisel"</string>
<string name="resolver_work_tab" msgid="2690019516263167035">"İş"</string>
+ <!-- no translation found for resolver_personal_tab_accessibility (5739524949153091224) -->
+ <skip />
+ <!-- no translation found for resolver_work_tab_accessibility (4753168230363802734) -->
+ <skip />
<string name="resolver_cant_share_with_work_apps" msgid="7539495559434146897">"İş uygulamalarıyla paylaşılamıyor"</string>
<string name="resolver_cant_share_with_personal_apps" msgid="8020581735267157241">"Kişisel uygulamalarla paylaşılamıyor"</string>
- <string name="resolver_cant_share_cross_profile_explanation" msgid="3536237105241882679">"BT yöneticiniz kişisel uygulamalar ile iş uygulamaları arasında paylaşımı engelledi"</string>
- <string name="resolver_turn_on_work_apps" msgid="8987359079870455469">"İş uygulamalarını açın"</string>
- <string name="resolver_turn_on_work_apps_explanation" msgid="6322467455509618928">"İş uygulamalarına ve kişilere erişmek için iş uygulamalarını açın"</string>
+ <!-- no translation found for resolver_cant_share_cross_profile_explanation (5556640604460901386) -->
+ <skip />
+ <!-- no translation found for resolver_cant_access_work_apps (375634344111233790) -->
+ <skip />
+ <!-- no translation found for resolver_cant_access_work_apps_explanation (3958762224516867388) -->
+ <skip />
+ <!-- no translation found for resolver_cant_access_personal_apps (1953215925406474177) -->
+ <skip />
+ <!-- no translation found for resolver_cant_access_personal_apps_explanation (1725572276741281136) -->
+ <skip />
+ <!-- no translation found for resolver_turn_on_work_apps_share (619263911204978175) -->
+ <skip />
+ <!-- no translation found for resolver_turn_on_work_apps_view (3073389230905543680) -->
+ <skip />
<string name="resolver_no_apps_available" msgid="7710339903040989654">"Kullanılabilir uygulama yok"</string>
- <string name="resolver_no_apps_available_explanation" msgid="4662694431121196560">"Herhangi bir uygulama bulamadık"</string>
- <string name="resolver_switch_on_work" msgid="8294542702883688533">"İş profilini aç"</string>
+ <!-- no translation found for resolver_switch_on_work (2873009160846966379) -->
+ <skip />
<string name="permlab_accessCallAudio" msgid="1682957511874097664">"Telefon aramalarında sesi kaydet veya çal"</string>
<string name="permdesc_accessCallAudio" msgid="8448360894684277823">"Varsayılan çevirici uygulaması olarak atandığında bu uygulamanın telefon aramalarında sesi kaydetmesine veya çalmasına izin verir."</string>
</resources>
diff --git a/core/res/res/values-uk/strings.xml b/core/res/res/values-uk/strings.xml
index e36c900fe4e8..b1a954ac2427 100644
--- a/core/res/res/values-uk/strings.xml
+++ b/core/res/res/values-uk/strings.xml
@@ -255,10 +255,8 @@
<item quantity="many">Знімок екрана для звіту про помилки буде зроблено через <xliff:g id="NUMBER_1">%d</xliff:g> секунд.</item>
<item quantity="other">Знімок екрана для звіту про помилки буде зроблено через <xliff:g id="NUMBER_1">%d</xliff:g> секунди.</item>
</plurals>
- <!-- no translation found for bugreport_screenshot_success_toast (7986095104151473745) -->
- <skip />
- <!-- no translation found for bugreport_screenshot_failure_toast (6736320861311294294) -->
- <skip />
+ <string name="bugreport_screenshot_success_toast" msgid="7986095104151473745">"Знімок екрана зі звітом про помилку зроблено"</string>
+ <string name="bugreport_screenshot_failure_toast" msgid="6736320861311294294">"Не вдалося зробити знімок екрана зі звітом про помилку"</string>
<string name="global_action_toggle_silent_mode" msgid="8464352592860372188">"Беззвуч. режим"</string>
<string name="global_action_silent_mode_on_status" msgid="2371892537738632013">"Звук ВИМК."</string>
<string name="global_action_silent_mode_off_status" msgid="6608006545950920042">"Звук УВІМК."</string>
@@ -460,9 +458,11 @@
<string name="permdesc_acceptHandovers" msgid="7129026180128626870">"Додаток може продовжувати виклик, початий в іншому додатку."</string>
<string name="permlab_readPhoneNumbers" msgid="5668704794723365628">"переглядати номери телефону"</string>
<string name="permdesc_readPhoneNumbers" msgid="7368652482818338871">"Надає додаткам доступ до номерів телефону на пристрої."</string>
+ <string name="permlab_wakeLock" product="automotive" msgid="1904736682319375676">"залишати екран автомобіля ввімкненим"</string>
<string name="permlab_wakeLock" product="tablet" msgid="1527660973931694000">"не доп.перехід пристр.в реж.сну"</string>
<string name="permlab_wakeLock" product="tv" msgid="2856941418123343518">"не допускати перехід пристрою Android TV в режим сну"</string>
<string name="permlab_wakeLock" product="default" msgid="569409726861695115">"Вимкнення режиму сну"</string>
+ <string name="permdesc_wakeLock" product="automotive" msgid="5995045369683254571">"Дозволяє додатку залишати екран автомобіля ввімкненим."</string>
<string name="permdesc_wakeLock" product="tablet" msgid="2441742939101526277">"Дозволяє програмі не допускати перехід планшетного ПК у режим сну."</string>
<string name="permdesc_wakeLock" product="tv" msgid="2329298966735118796">"Дозволяє додатку не допускати перехід пристрою Android TV в режим сну."</string>
<string name="permdesc_wakeLock" product="default" msgid="3689523792074007163">"Дозволяє програмі не допускати перехід телефону в режим сну."</string>
@@ -1675,6 +1675,12 @@
<string name="safe_media_volume_warning" product="default" msgid="3751676824423049994">"Збільшити гучність понад рекомендований рівень?\n\nЯкщо слухати надто гучну музику тривалий час, можна пошкодити слух."</string>
<string name="accessibility_shortcut_warning_dialog_title" msgid="4017995837692622933">"Використовувати швидке ввімкнення?"</string>
<string name="accessibility_shortcut_toogle_warning" msgid="4161716521310929544">"Якщо цей засіб увімкнено, ви можете активувати спеціальні можливості, утримуючи обидві кнопки гучності протягом трьох секунд."</string>
+ <!-- no translation found for accessibility_select_shortcut_menu_title (7310194076629867377) -->
+ <skip />
+ <!-- no translation found for accessibility_edit_shortcut_menu_button_title (6096484087245145325) -->
+ <skip />
+ <!-- no translation found for accessibility_edit_shortcut_menu_volume_title (4849108668454490699) -->
+ <skip />
<string name="edit_accessibility_shortcut_menu_button" msgid="8885752738733772935">"Редагувати засоби"</string>
<string name="cancel_accessibility_shortcut_menu_button" msgid="1817413122335452474">"Скасувати"</string>
<string name="disable_accessibility_shortcut" msgid="5806091378745232383">"Вимкнути ярлик"</string>
@@ -1917,8 +1923,7 @@
<string name="default_notification_channel_label" msgid="3697928973567217330">"Без категорії"</string>
<string name="importance_from_user" msgid="2782756722448800447">"Ви вказуєте пріоритет цих сповіщень."</string>
<string name="importance_from_person" msgid="4235804979664465383">"Важливе з огляду на учасників."</string>
- <!-- no translation found for notification_history_title_placeholder (7748630986182249599) -->
- <skip />
+ <string name="notification_history_title_placeholder" msgid="7748630986182249599">"Користувацьке сповіщення додатка"</string>
<string name="user_creation_account_exists" msgid="2239146360099708035">"Дозволити додатку <xliff:g id="APP">%1$s</xliff:g> створити нового користувача з обліковим записом <xliff:g id="ACCOUNT">%2$s</xliff:g> (користувач із таким обліковим записом уже існує)?"</string>
<string name="user_creation_adding" msgid="7305185499667958364">"Дозволити додатку <xliff:g id="APP">%1$s</xliff:g> створити нового користувача з обліковим записом <xliff:g id="ACCOUNT">%2$s</xliff:g>?"</string>
<string name="language_selection_title" msgid="52674936078683285">"Додати мову"</string>
@@ -2096,14 +2101,29 @@
<string name="as_app_forced_to_restricted_bucket" msgid="8233871289353898964">"Пакет \"<xliff:g id="PACKAGE_NAME">%1$s</xliff:g>\" додано в сегмент з обмеженнями"</string>
<string name="resolver_personal_tab" msgid="2051260504014442073">"Особисте"</string>
<string name="resolver_work_tab" msgid="2690019516263167035">"Робоче"</string>
+ <!-- no translation found for resolver_personal_tab_accessibility (5739524949153091224) -->
+ <skip />
+ <!-- no translation found for resolver_work_tab_accessibility (4753168230363802734) -->
+ <skip />
<string name="resolver_cant_share_with_work_apps" msgid="7539495559434146897">"Не можна надсилати дані робочим додаткам"</string>
<string name="resolver_cant_share_with_personal_apps" msgid="8020581735267157241">"Не можна надсилати дані особистим додаткам"</string>
- <string name="resolver_cant_share_cross_profile_explanation" msgid="3536237105241882679">"Ваш ІТ-адміністратор заблокував обмін даними між особистими й робочими додатками"</string>
- <string name="resolver_turn_on_work_apps" msgid="8987359079870455469">"Увімкніть робочі додатки"</string>
- <string name="resolver_turn_on_work_apps_explanation" msgid="6322467455509618928">"Щоб отримати доступ до робочих додатків і контактів, увімкніть ці додатки"</string>
+ <!-- no translation found for resolver_cant_share_cross_profile_explanation (5556640604460901386) -->
+ <skip />
+ <!-- no translation found for resolver_cant_access_work_apps (375634344111233790) -->
+ <skip />
+ <!-- no translation found for resolver_cant_access_work_apps_explanation (3958762224516867388) -->
+ <skip />
+ <!-- no translation found for resolver_cant_access_personal_apps (1953215925406474177) -->
+ <skip />
+ <!-- no translation found for resolver_cant_access_personal_apps_explanation (1725572276741281136) -->
+ <skip />
+ <!-- no translation found for resolver_turn_on_work_apps_share (619263911204978175) -->
+ <skip />
+ <!-- no translation found for resolver_turn_on_work_apps_view (3073389230905543680) -->
+ <skip />
<string name="resolver_no_apps_available" msgid="7710339903040989654">"Немає доступних додатків"</string>
- <string name="resolver_no_apps_available_explanation" msgid="4662694431121196560">"Немає додатків"</string>
- <string name="resolver_switch_on_work" msgid="8294542702883688533">"Увімкнути робочий профіль"</string>
+ <!-- no translation found for resolver_switch_on_work (2873009160846966379) -->
+ <skip />
<string name="permlab_accessCallAudio" msgid="1682957511874097664">"Записувати й відтворювати звук під час викликів"</string>
<string name="permdesc_accessCallAudio" msgid="8448360894684277823">"Дозволяє цьому додатку записувати й відтворювати звук під час викликів, коли його вибрано додатком для дзвінків за умовчанням."</string>
</resources>
diff --git a/core/res/res/values-ur/strings.xml b/core/res/res/values-ur/strings.xml
index 10eb4ce81b24..31ff6cfb9fbf 100644
--- a/core/res/res/values-ur/strings.xml
+++ b/core/res/res/values-ur/strings.xml
@@ -249,10 +249,8 @@
<item quantity="other">بگ رپورٹ کیلئے <xliff:g id="NUMBER_1">%d</xliff:g> سیکنڈز میں اسکرین شاٹ لیا جائے گا۔</item>
<item quantity="one">بگ رپورٹ کیلئے <xliff:g id="NUMBER_0">%d</xliff:g> سیکنڈ میں اسکرین شاٹ لیا جائے گا۔</item>
</plurals>
- <!-- no translation found for bugreport_screenshot_success_toast (7986095104151473745) -->
- <skip />
- <!-- no translation found for bugreport_screenshot_failure_toast (6736320861311294294) -->
- <skip />
+ <string name="bugreport_screenshot_success_toast" msgid="7986095104151473745">"بگ رپورٹ کے ساتھ لیا گیا اسکرین شاٹ"</string>
+ <string name="bugreport_screenshot_failure_toast" msgid="6736320861311294294">"بگ رپورٹ کے ساتھ اسکرین شاٹ لینے میں ناکام"</string>
<string name="global_action_toggle_silent_mode" msgid="8464352592860372188">"خاموش وضع"</string>
<string name="global_action_silent_mode_on_status" msgid="2371892537738632013">"آواز آف ہے"</string>
<string name="global_action_silent_mode_off_status" msgid="6608006545950920042">"آواز آن ہے"</string>
@@ -454,9 +452,11 @@
<string name="permdesc_acceptHandovers" msgid="7129026180128626870">"ایپ کو دوسری ایپ میں شروع کردہ کال کو جاری رکھنے کی اجازت ملتی ہے۔"</string>
<string name="permlab_readPhoneNumbers" msgid="5668704794723365628">"فون نمبرز پڑھیں"</string>
<string name="permdesc_readPhoneNumbers" msgid="7368652482818338871">"ایپ کو آلہ کے فون نمبرز تک رسائی کرنے دیتا ہے۔"</string>
+ <string name="permlab_wakeLock" product="automotive" msgid="1904736682319375676">"کار کی اسکرین آن رکھیں"</string>
<string name="permlab_wakeLock" product="tablet" msgid="1527660973931694000">"ٹیبلیٹ کو سلیپ وضع میں جانے سے روکیں"</string>
<string name="permlab_wakeLock" product="tv" msgid="2856941418123343518">"‏اپنے Android TV کو سلیپ وضع میں جانے سے روکیں"</string>
<string name="permlab_wakeLock" product="default" msgid="569409726861695115">"فون کو سلیپ وضع میں جانے سے روکیں"</string>
+ <string name="permdesc_wakeLock" product="automotive" msgid="5995045369683254571">"ایپ کو کار کی اسکرین آن رکھنے کی اجازت دیتا ہے۔"</string>
<string name="permdesc_wakeLock" product="tablet" msgid="2441742939101526277">"ایپ کو ٹیبلیٹ کو سلیپ وضع میں جانے سے روکنے کی اجازت دیتا ہے"</string>
<string name="permdesc_wakeLock" product="tv" msgid="2329298966735118796">"‏ایپ کو آپ کے Android TV آلہ کو سلیپ وضع میں جانے سے روکنے کی اجازت دیتا ہے۔"</string>
<string name="permdesc_wakeLock" product="default" msgid="3689523792074007163">"ایپ کو فون کو سلیپ وضع میں جانے سے روکنے کی اجازت دیتا ہے"</string>
@@ -1631,6 +1631,12 @@
<string name="safe_media_volume_warning" product="default" msgid="3751676824423049994">"والیوم کو تجویز کردہ سطح سے زیادہ کریں؟\n\nزیادہ وقت تک اونچی آواز میں سننے سے آپ کی سماعت کو نقصان پہنچ سکتا ہے۔"</string>
<string name="accessibility_shortcut_warning_dialog_title" msgid="4017995837692622933">"ایکسیسبیلٹی شارٹ کٹ استعمال کریں؟"</string>
<string name="accessibility_shortcut_toogle_warning" msgid="4161716521310929544">"شارٹ کٹ آن ہونے پر، 3 سیکنڈ تک دونوں والیوم بٹنز کو دبانے سے ایک ایکسیسبیلٹی خصوصیت شروع ہو جائے گی۔"</string>
+ <!-- no translation found for accessibility_select_shortcut_menu_title (7310194076629867377) -->
+ <skip />
+ <!-- no translation found for accessibility_edit_shortcut_menu_button_title (6096484087245145325) -->
+ <skip />
+ <!-- no translation found for accessibility_edit_shortcut_menu_volume_title (4849108668454490699) -->
+ <skip />
<string name="edit_accessibility_shortcut_menu_button" msgid="8885752738733772935">"شارٹ کٹس میں ترمیم کریں"</string>
<string name="cancel_accessibility_shortcut_menu_button" msgid="1817413122335452474">"منسوخ کریں"</string>
<string name="disable_accessibility_shortcut" msgid="5806091378745232383">"شارٹ کٹ آف کریں"</string>
@@ -2028,14 +2034,29 @@
<string name="as_app_forced_to_restricted_bucket" msgid="8233871289353898964">"<xliff:g id="PACKAGE_NAME">%1$s</xliff:g> کو پابند کردہ بکٹ میں رکھ دیا گیا ہے"</string>
<string name="resolver_personal_tab" msgid="2051260504014442073">"ذاتی"</string>
<string name="resolver_work_tab" msgid="2690019516263167035">"دفتر"</string>
+ <!-- no translation found for resolver_personal_tab_accessibility (5739524949153091224) -->
+ <skip />
+ <!-- no translation found for resolver_work_tab_accessibility (4753168230363802734) -->
+ <skip />
<string name="resolver_cant_share_with_work_apps" msgid="7539495559434146897">"ورک ایپس کے ساتھ اشتراک نہیں کر سکتے"</string>
<string name="resolver_cant_share_with_personal_apps" msgid="8020581735267157241">"ذاتی ایپس کے ساتھ اشتراک نہیں کر سکتے"</string>
- <string name="resolver_cant_share_cross_profile_explanation" msgid="3536237105241882679">"‏آپ کے IT منتظم نے ذاتی اور ورک ایپس کے درمیان اشتراک کرنے کو مسدود کر دیا"</string>
- <string name="resolver_turn_on_work_apps" msgid="8987359079870455469">"ورک ایپس آن کریں"</string>
- <string name="resolver_turn_on_work_apps_explanation" msgid="6322467455509618928">"ورک ایپس اور رابطوں تک رسائی حاصل کرنے کے لیے ورک ایپس آن کریں"</string>
+ <!-- no translation found for resolver_cant_share_cross_profile_explanation (5556640604460901386) -->
+ <skip />
+ <!-- no translation found for resolver_cant_access_work_apps (375634344111233790) -->
+ <skip />
+ <!-- no translation found for resolver_cant_access_work_apps_explanation (3958762224516867388) -->
+ <skip />
+ <!-- no translation found for resolver_cant_access_personal_apps (1953215925406474177) -->
+ <skip />
+ <!-- no translation found for resolver_cant_access_personal_apps_explanation (1725572276741281136) -->
+ <skip />
+ <!-- no translation found for resolver_turn_on_work_apps_share (619263911204978175) -->
+ <skip />
+ <!-- no translation found for resolver_turn_on_work_apps_view (3073389230905543680) -->
+ <skip />
<string name="resolver_no_apps_available" msgid="7710339903040989654">"کوئی ایپ دستیاب نہیں"</string>
- <string name="resolver_no_apps_available_explanation" msgid="4662694431121196560">"ہمیں کوئی ایپ نہیں مل سکی"</string>
- <string name="resolver_switch_on_work" msgid="8294542702883688533">"ورک کا سوئچ آن کریں"</string>
+ <!-- no translation found for resolver_switch_on_work (2873009160846966379) -->
+ <skip />
<string name="permlab_accessCallAudio" msgid="1682957511874097664">"ٹیلیفون کالز میں آڈیو ریکارڈ کریں یا چلائیں"</string>
<string name="permdesc_accessCallAudio" msgid="8448360894684277823">"اس ایپ کو، جب ڈیفالٹ ڈائلر ایپلیکیشن کے بطور تفویض کیا جاتا ہے، تو ٹیلیفون کالز میں آڈیو ریکارڈ کرنے یا چلانے کی اجازت دیتا ہے۔"</string>
</resources>
diff --git a/core/res/res/values-uz/strings.xml b/core/res/res/values-uz/strings.xml
index 526d88b87590..7365dfdccc04 100644
--- a/core/res/res/values-uz/strings.xml
+++ b/core/res/res/values-uz/strings.xml
@@ -249,10 +249,8 @@
<item quantity="other">Xatoliklar hisoboti uchun skrinshot <xliff:g id="NUMBER_1">%d</xliff:g> soniyadan so‘ng olinadi.</item>
<item quantity="one">Xatoliklar hisoboti uchun skrinshot <xliff:g id="NUMBER_0">%d</xliff:g> soniyadan so‘ng olinadi.</item>
</plurals>
- <!-- no translation found for bugreport_screenshot_success_toast (7986095104151473745) -->
- <skip />
- <!-- no translation found for bugreport_screenshot_failure_toast (6736320861311294294) -->
- <skip />
+ <string name="bugreport_screenshot_success_toast" msgid="7986095104151473745">"Xatoliklar hisoboti bilan skrinshot olindi"</string>
+ <string name="bugreport_screenshot_failure_toast" msgid="6736320861311294294">"Xatoliklar hisoboti bilan skrinshot olinmadi"</string>
<string name="global_action_toggle_silent_mode" msgid="8464352592860372188">"Ovozsiz rejim"</string>
<string name="global_action_silent_mode_on_status" msgid="2371892537738632013">"Tovush o‘chirilgan"</string>
<string name="global_action_silent_mode_off_status" msgid="6608006545950920042">"YONIQ"</string>
@@ -454,9 +452,11 @@
<string name="permdesc_acceptHandovers" msgid="7129026180128626870">"Ilovaga boshqa ilovada boshlangan chaqiruvni davom ettirish imkon beradi"</string>
<string name="permlab_readPhoneNumbers" msgid="5668704794723365628">"telefon raqamlarini o‘qish"</string>
<string name="permdesc_readPhoneNumbers" msgid="7368652482818338871">"Ilovaga qurilmaning telefon raqamlaridan foydalanishiga ruxsat beradi."</string>
+ <string name="permlab_wakeLock" product="automotive" msgid="1904736682319375676">"avtomobil ekranini yoniq holatda saqlab turish"</string>
<string name="permlab_wakeLock" product="tablet" msgid="1527660973931694000">"planshetni uyquga ketishiga yo‘l qo‘ymaslik"</string>
<string name="permlab_wakeLock" product="tv" msgid="2856941418123343518">"Android TV qurilmasining uyqu rejimiga kirishining oldini olish"</string>
<string name="permlab_wakeLock" product="default" msgid="569409726861695115">"telefonni uxlashiga yo‘l qo‘ymaslik"</string>
+ <string name="permdesc_wakeLock" product="automotive" msgid="5995045369683254571">"Ilova avtomobil ekranini yoniq holatda saqlaydi."</string>
<string name="permdesc_wakeLock" product="tablet" msgid="2441742939101526277">"Ilova planshetning uyqu rejimiga o‘tib qolishining oldini olishi mumkin."</string>
<string name="permdesc_wakeLock" product="tv" msgid="2329298966735118796">"Ilovaga Android TV qurilmangizning uyqu rejimiga oʻtishining oldini olish huquqini beradi."</string>
<string name="permdesc_wakeLock" product="default" msgid="3689523792074007163">"Ilova telefonning uyqu rejimiga o‘tib qolishining oldini olishi mumkin."</string>
@@ -1631,6 +1631,12 @@
<string name="safe_media_volume_warning" product="default" msgid="3751676824423049994">"Tovush balandligi tavsiya etilgan darajadan ham yuqori qilinsinmi?\n\nUzoq vaqt davomida baland ovozda tinglash eshitish qobiliyatingizga salbiy ta’sir ko‘rsatishi mumkin."</string>
<string name="accessibility_shortcut_warning_dialog_title" msgid="4017995837692622933">"Tezkor ishga tushirishdan foydalanilsinmi?"</string>
<string name="accessibility_shortcut_toogle_warning" msgid="4161716521310929544">"Maxsus imkoniyatlar funksiyasidan foydalanish uchun u yoniqligida ikkala tovush tugmasini 3 soniya bosib turing."</string>
+ <!-- no translation found for accessibility_select_shortcut_menu_title (7310194076629867377) -->
+ <skip />
+ <!-- no translation found for accessibility_edit_shortcut_menu_button_title (6096484087245145325) -->
+ <skip />
+ <!-- no translation found for accessibility_edit_shortcut_menu_volume_title (4849108668454490699) -->
+ <skip />
<string name="edit_accessibility_shortcut_menu_button" msgid="8885752738733772935">"Tezkor tugmalarni tahrirlash"</string>
<string name="cancel_accessibility_shortcut_menu_button" msgid="1817413122335452474">"Bekor qilish"</string>
<string name="disable_accessibility_shortcut" msgid="5806091378745232383">"Tezkor ishga tushirishni o‘chirib qo‘yish"</string>
@@ -1853,8 +1859,7 @@
<string name="default_notification_channel_label" msgid="3697928973567217330">"Turkumlanmagan"</string>
<string name="importance_from_user" msgid="2782756722448800447">"Siz ushbu bildirishnomalarning muhimligini belgilagansiz."</string>
<string name="importance_from_person" msgid="4235804979664465383">"Bu odamlar siz uchun muhim."</string>
- <!-- no translation found for notification_history_title_placeholder (7748630986182249599) -->
- <skip />
+ <string name="notification_history_title_placeholder" msgid="7748630986182249599">"Maxsus ilova bildirishnomasi"</string>
<string name="user_creation_account_exists" msgid="2239146360099708035">"<xliff:g id="APP">%1$s</xliff:g> ilovasiga <xliff:g id="ACCOUNT">%2$s</xliff:g> hisobi bilan yangi foydalanuvchi yaratishiga ruxsat berilsinmi (bunday hisobdagi foydalanuvchi allaqachon mavjud) ?"</string>
<string name="user_creation_adding" msgid="7305185499667958364">"<xliff:g id="APP">%1$s</xliff:g> ilovasiga <xliff:g id="ACCOUNT">%2$s</xliff:g> hisobi bilan yangi foydalanuvchi yaratishiga ruxsat berilsinmi ?"</string>
<string name="language_selection_title" msgid="52674936078683285">"Til qoʻshish"</string>
@@ -2028,14 +2033,29 @@
<string name="as_app_forced_to_restricted_bucket" msgid="8233871289353898964">"<xliff:g id="PACKAGE_NAME">%1$s</xliff:g> cheklangan turkumga joylandi"</string>
<string name="resolver_personal_tab" msgid="2051260504014442073">"Shaxsiy"</string>
<string name="resolver_work_tab" msgid="2690019516263167035">"Ish"</string>
+ <!-- no translation found for resolver_personal_tab_accessibility (5739524949153091224) -->
+ <skip />
+ <!-- no translation found for resolver_work_tab_accessibility (4753168230363802734) -->
+ <skip />
<string name="resolver_cant_share_with_work_apps" msgid="7539495559434146897">"Ishga oid ilovalarga ulashilmaydi"</string>
<string name="resolver_cant_share_with_personal_apps" msgid="8020581735267157241">"Shaxsiy ilovalarga ulashilmaydi"</string>
- <string name="resolver_cant_share_cross_profile_explanation" msgid="3536237105241882679">"Shaxsiy va ishga oid ilovalararo axborot ulashish AT administratori tomonidan taqiqlangan"</string>
- <string name="resolver_turn_on_work_apps" msgid="8987359079870455469">"Ishga oid ilovalarni yoqish"</string>
- <string name="resolver_turn_on_work_apps_explanation" msgid="6322467455509618928">"Ishga oid ilova va kontaktlarni ochish uchun ishga oid ilovalarni yoqing"</string>
+ <!-- no translation found for resolver_cant_share_cross_profile_explanation (5556640604460901386) -->
+ <skip />
+ <!-- no translation found for resolver_cant_access_work_apps (375634344111233790) -->
+ <skip />
+ <!-- no translation found for resolver_cant_access_work_apps_explanation (3958762224516867388) -->
+ <skip />
+ <!-- no translation found for resolver_cant_access_personal_apps (1953215925406474177) -->
+ <skip />
+ <!-- no translation found for resolver_cant_access_personal_apps_explanation (1725572276741281136) -->
+ <skip />
+ <!-- no translation found for resolver_turn_on_work_apps_share (619263911204978175) -->
+ <skip />
+ <!-- no translation found for resolver_turn_on_work_apps_view (3073389230905543680) -->
+ <skip />
<string name="resolver_no_apps_available" msgid="7710339903040989654">"Mos ilova topilmadi"</string>
- <string name="resolver_no_apps_available_explanation" msgid="4662694431121196560">"Hech qanday ilova topilmadi"</string>
- <string name="resolver_switch_on_work" msgid="8294542702883688533">"Ish rejimini yoqish"</string>
+ <!-- no translation found for resolver_switch_on_work (2873009160846966379) -->
+ <skip />
<string name="permlab_accessCallAudio" msgid="1682957511874097664">"Telefondagi suhbatlarni yozib olish va ularni ijro qilish"</string>
<string name="permdesc_accessCallAudio" msgid="8448360894684277823">"Bu ilova chaqiruvlar uchun asosiy ilova sifatida tayinlanganda u telefon chaqiruvlarida suhbatlarni yozib olish va shu audiolarni ijro etish imkonini beradi."</string>
</resources>
diff --git a/core/res/res/values-vi/strings.xml b/core/res/res/values-vi/strings.xml
index 4f67627b9904..bce8e37fbc9f 100644
--- a/core/res/res/values-vi/strings.xml
+++ b/core/res/res/values-vi/strings.xml
@@ -249,10 +249,8 @@
<item quantity="other">Sẽ chụp ảnh màn hình để báo cáo lỗi sau <xliff:g id="NUMBER_1">%d</xliff:g> giây.</item>
<item quantity="one">Sẽ chụp ảnh màn hình để báo cáo lỗi sau <xliff:g id="NUMBER_0">%d</xliff:g> giây.</item>
</plurals>
- <!-- no translation found for bugreport_screenshot_success_toast (7986095104151473745) -->
- <skip />
- <!-- no translation found for bugreport_screenshot_failure_toast (6736320861311294294) -->
- <skip />
+ <string name="bugreport_screenshot_success_toast" msgid="7986095104151473745">"Đã chụp được ảnh màn hình báo cáo lỗi"</string>
+ <string name="bugreport_screenshot_failure_toast" msgid="6736320861311294294">"Không chụp được ảnh màn hình báo cáo lỗi"</string>
<string name="global_action_toggle_silent_mode" msgid="8464352592860372188">"Chế độ im lặng"</string>
<string name="global_action_silent_mode_on_status" msgid="2371892537738632013">"Âm thanh TẮT"</string>
<string name="global_action_silent_mode_off_status" msgid="6608006545950920042">"Âm thanh BẬT"</string>
@@ -454,9 +452,11 @@
<string name="permdesc_acceptHandovers" msgid="7129026180128626870">"Cho phép ứng dụng tiếp tục cuộc gọi được bắt đầu trong một ứng dụng khác."</string>
<string name="permlab_readPhoneNumbers" msgid="5668704794723365628">"đọc số điện thoại"</string>
<string name="permdesc_readPhoneNumbers" msgid="7368652482818338871">"Cho phép ứng dụng truy cập số điện thoại của thiết bị."</string>
+ <string name="permlab_wakeLock" product="automotive" msgid="1904736682319375676">"duy trì trạng thái bật của màn hình ô tô"</string>
<string name="permlab_wakeLock" product="tablet" msgid="1527660973931694000">"ngăn máy tính bảng chuyển sang chế độ ngủ"</string>
<string name="permlab_wakeLock" product="tv" msgid="2856941418123343518">"ngăn thiết bị Android TV chuyển sang chế độ ngủ"</string>
<string name="permlab_wakeLock" product="default" msgid="569409726861695115">"ngăn điện thoại chuyển sang chế độ ngủ"</string>
+ <string name="permdesc_wakeLock" product="automotive" msgid="5995045369683254571">"Cho phép ứng dụng này duy trì trạng thái bật của màn hình ô tô."</string>
<string name="permdesc_wakeLock" product="tablet" msgid="2441742939101526277">"Cho phép ứng dụng ngăn máy tính bảng chuyển sang chế độ ngủ."</string>
<string name="permdesc_wakeLock" product="tv" msgid="2329298966735118796">"Cho phép ứng dụng ngăn thiết bị Android TV chuyển sang chế độ ngủ."</string>
<string name="permdesc_wakeLock" product="default" msgid="3689523792074007163">"Cho phép ứng dụng ngăn điện thoại chuyển sang chế độ ngủ."</string>
@@ -1631,6 +1631,12 @@
<string name="safe_media_volume_warning" product="default" msgid="3751676824423049994">"Bạn tăng âm lượng lên quá mức khuyên dùng?\n\nViệc nghe ở mức âm lượng cao trong thời gian dài có thể gây tổn thương thính giác của bạn."</string>
<string name="accessibility_shortcut_warning_dialog_title" msgid="4017995837692622933">"Sử dụng phím tắt Hỗ trợ tiếp cận?"</string>
<string name="accessibility_shortcut_toogle_warning" msgid="4161716521310929544">"Khi phím tắt này đang bật, thao tác nhấn cả hai nút âm lượng trong 3 giây sẽ mở tính năng hỗ trợ tiếp cận."</string>
+ <!-- no translation found for accessibility_select_shortcut_menu_title (7310194076629867377) -->
+ <skip />
+ <!-- no translation found for accessibility_edit_shortcut_menu_button_title (6096484087245145325) -->
+ <skip />
+ <!-- no translation found for accessibility_edit_shortcut_menu_volume_title (4849108668454490699) -->
+ <skip />
<string name="edit_accessibility_shortcut_menu_button" msgid="8885752738733772935">"Chỉnh sửa phím tắt"</string>
<string name="cancel_accessibility_shortcut_menu_button" msgid="1817413122335452474">"Hủy"</string>
<string name="disable_accessibility_shortcut" msgid="5806091378745232383">"Tắt phím tắt"</string>
@@ -1853,8 +1859,7 @@
<string name="default_notification_channel_label" msgid="3697928973567217330">"Chưa được phân loại"</string>
<string name="importance_from_user" msgid="2782756722448800447">"Bạn đặt tầm quan trọng của các thông báo này."</string>
<string name="importance_from_person" msgid="4235804979664465383">"Thông báo này quan trọng vì những người có liên quan."</string>
- <!-- no translation found for notification_history_title_placeholder (7748630986182249599) -->
- <skip />
+ <string name="notification_history_title_placeholder" msgid="7748630986182249599">"Thông báo tùy chỉnh cho ứng dụng"</string>
<string name="user_creation_account_exists" msgid="2239146360099708035">"Cho phép <xliff:g id="APP">%1$s</xliff:g> tạo người dùng mới bằng <xliff:g id="ACCOUNT">%2$s</xliff:g> (đã tồn tại người dùng có tài khoản này)?"</string>
<string name="user_creation_adding" msgid="7305185499667958364">"Cho phép <xliff:g id="APP">%1$s</xliff:g> tạo người dùng mới bằng <xliff:g id="ACCOUNT">%2$s</xliff:g>?"</string>
<string name="language_selection_title" msgid="52674936078683285">"Thêm ngôn ngữ"</string>
@@ -2028,14 +2033,29 @@
<string name="as_app_forced_to_restricted_bucket" msgid="8233871289353898964">"Đã đưa <xliff:g id="PACKAGE_NAME">%1$s</xliff:g> vào bộ chứa BỊ HẠN CHẾ"</string>
<string name="resolver_personal_tab" msgid="2051260504014442073">"Cá nhân"</string>
<string name="resolver_work_tab" msgid="2690019516263167035">"Cơ quan"</string>
+ <!-- no translation found for resolver_personal_tab_accessibility (5739524949153091224) -->
+ <skip />
+ <!-- no translation found for resolver_work_tab_accessibility (4753168230363802734) -->
+ <skip />
<string name="resolver_cant_share_with_work_apps" msgid="7539495559434146897">"Không thể chia sẻ với các ứng dụng công việc"</string>
<string name="resolver_cant_share_with_personal_apps" msgid="8020581735267157241">"Không thể chia sẻ với các ứng dụng cá nhân"</string>
- <string name="resolver_cant_share_cross_profile_explanation" msgid="3536237105241882679">"Quản trị viên CNTT của bạn đã chặn hoạt động chia sẻ giữa các ứng dụng cá nhân và công việc"</string>
- <string name="resolver_turn_on_work_apps" msgid="8987359079870455469">"Bật các ứng dụng công việc"</string>
- <string name="resolver_turn_on_work_apps_explanation" msgid="6322467455509618928">"Bật ứng dụng công việc để truy cập vào phần những người liên hệ và ứng dụng công việc"</string>
+ <!-- no translation found for resolver_cant_share_cross_profile_explanation (5556640604460901386) -->
+ <skip />
+ <!-- no translation found for resolver_cant_access_work_apps (375634344111233790) -->
+ <skip />
+ <!-- no translation found for resolver_cant_access_work_apps_explanation (3958762224516867388) -->
+ <skip />
+ <!-- no translation found for resolver_cant_access_personal_apps (1953215925406474177) -->
+ <skip />
+ <!-- no translation found for resolver_cant_access_personal_apps_explanation (1725572276741281136) -->
+ <skip />
+ <!-- no translation found for resolver_turn_on_work_apps_share (619263911204978175) -->
+ <skip />
+ <!-- no translation found for resolver_turn_on_work_apps_view (3073389230905543680) -->
+ <skip />
<string name="resolver_no_apps_available" msgid="7710339903040989654">"Không có ứng dụng nào"</string>
- <string name="resolver_no_apps_available_explanation" msgid="4662694431121196560">"Chúng tôi không tìm thấy bất kỳ ứng dụng nào"</string>
- <string name="resolver_switch_on_work" msgid="8294542702883688533">"Bật hồ sơ công việc"</string>
+ <!-- no translation found for resolver_switch_on_work (2873009160846966379) -->
+ <skip />
<string name="permlab_accessCallAudio" msgid="1682957511874097664">"Ghi âm hoặc phát âm thanh trong cuộc gọi điện thoại"</string>
<string name="permdesc_accessCallAudio" msgid="8448360894684277823">"Cho phép ứng dụng này ghi âm hoặc phát âm thanh trong cuộc gọi điện thoại khi được chỉ định làm ứng dụng trình quay số mặc định."</string>
</resources>
diff --git a/core/res/res/values-zh-rCN/strings.xml b/core/res/res/values-zh-rCN/strings.xml
index 5ac1f0a0f52e..b24a89e077ed 100644
--- a/core/res/res/values-zh-rCN/strings.xml
+++ b/core/res/res/values-zh-rCN/strings.xml
@@ -249,10 +249,8 @@
<item quantity="other">系统将在 <xliff:g id="NUMBER_1">%d</xliff:g> 秒后对错误报告进行截屏。</item>
<item quantity="one">系统将在 <xliff:g id="NUMBER_0">%d</xliff:g> 秒后对错误报告进行截屏。</item>
</plurals>
- <!-- no translation found for bugreport_screenshot_success_toast (7986095104151473745) -->
- <skip />
- <!-- no translation found for bugreport_screenshot_failure_toast (6736320861311294294) -->
- <skip />
+ <string name="bugreport_screenshot_success_toast" msgid="7986095104151473745">"已截取错误报告的屏幕截图"</string>
+ <string name="bugreport_screenshot_failure_toast" msgid="6736320861311294294">"无法截取错误报告的屏幕截图"</string>
<string name="global_action_toggle_silent_mode" msgid="8464352592860372188">"静音模式"</string>
<string name="global_action_silent_mode_on_status" msgid="2371892537738632013">"声音已关闭"</string>
<string name="global_action_silent_mode_off_status" msgid="6608006545950920042">"声音已开启"</string>
@@ -454,9 +452,11 @@
<string name="permdesc_acceptHandovers" msgid="7129026180128626870">"允许该应用继续进行在其他应用中发起的通话。"</string>
<string name="permlab_readPhoneNumbers" msgid="5668704794723365628">"读取电话号码"</string>
<string name="permdesc_readPhoneNumbers" msgid="7368652482818338871">"允许该应用访问设备上的电话号码。"</string>
+ <string name="permlab_wakeLock" product="automotive" msgid="1904736682319375676">"使车载显示屏保持开启状态"</string>
<string name="permlab_wakeLock" product="tablet" msgid="1527660973931694000">"阻止平板电脑进入休眠状态"</string>
<string name="permlab_wakeLock" product="tv" msgid="2856941418123343518">"阻止 Android TV 设备进入休眠状态"</string>
<string name="permlab_wakeLock" product="default" msgid="569409726861695115">"防止手机休眠"</string>
+ <string name="permdesc_wakeLock" product="automotive" msgid="5995045369683254571">"允许该应用使车载显示屏保持开启状态。"</string>
<string name="permdesc_wakeLock" product="tablet" msgid="2441742939101526277">"允许应用阻止平板电脑进入休眠状态。"</string>
<string name="permdesc_wakeLock" product="tv" msgid="2329298966735118796">"允许应用阻止 Android TV 设备进入休眠状态。"</string>
<string name="permdesc_wakeLock" product="default" msgid="3689523792074007163">"允许应用阻止手机进入休眠状态。"</string>
@@ -1631,6 +1631,12 @@
<string name="safe_media_volume_warning" product="default" msgid="3751676824423049994">"要将音量调高到建议的音量以上吗?\n\n长时间保持高音量可能会损伤听力。"</string>
<string name="accessibility_shortcut_warning_dialog_title" msgid="4017995837692622933">"要使用无障碍快捷方式吗?"</string>
<string name="accessibility_shortcut_toogle_warning" msgid="4161716521310929544">"启用这项快捷方式后,同时按下两个音量按钮 3 秒钟即可启动无障碍功能。"</string>
+ <!-- no translation found for accessibility_select_shortcut_menu_title (7310194076629867377) -->
+ <skip />
+ <!-- no translation found for accessibility_edit_shortcut_menu_button_title (6096484087245145325) -->
+ <skip />
+ <!-- no translation found for accessibility_edit_shortcut_menu_volume_title (4849108668454490699) -->
+ <skip />
<string name="edit_accessibility_shortcut_menu_button" msgid="8885752738733772935">"修改快捷方式"</string>
<string name="cancel_accessibility_shortcut_menu_button" msgid="1817413122335452474">"取消"</string>
<string name="disable_accessibility_shortcut" msgid="5806091378745232383">"关闭快捷方式"</string>
@@ -1853,8 +1859,7 @@
<string name="default_notification_channel_label" msgid="3697928973567217330">"未分类"</string>
<string name="importance_from_user" msgid="2782756722448800447">"这些通知的重要程度由您来设置。"</string>
<string name="importance_from_person" msgid="4235804979664465383">"这条通知涉及特定的人,因此被归为重要通知。"</string>
- <!-- no translation found for notification_history_title_placeholder (7748630986182249599) -->
- <skip />
+ <string name="notification_history_title_placeholder" msgid="7748630986182249599">"自定义应用通知"</string>
<string name="user_creation_account_exists" msgid="2239146360099708035">"允许<xliff:g id="APP">%1$s</xliff:g>使用 <xliff:g id="ACCOUNT">%2$s</xliff:g>(目前已有用户使用此帐号)创建新用户吗?"</string>
<string name="user_creation_adding" msgid="7305185499667958364">"允许<xliff:g id="APP">%1$s</xliff:g>使用 <xliff:g id="ACCOUNT">%2$s</xliff:g> 创建新用户吗?"</string>
<string name="language_selection_title" msgid="52674936078683285">"添加语言"</string>
@@ -2028,14 +2033,29 @@
<string name="as_app_forced_to_restricted_bucket" msgid="8233871289353898964">"<xliff:g id="PACKAGE_NAME">%1$s</xliff:g> 已被放入受限存储分区"</string>
<string name="resolver_personal_tab" msgid="2051260504014442073">"个人"</string>
<string name="resolver_work_tab" msgid="2690019516263167035">"工作"</string>
+ <!-- no translation found for resolver_personal_tab_accessibility (5739524949153091224) -->
+ <skip />
+ <!-- no translation found for resolver_work_tab_accessibility (4753168230363802734) -->
+ <skip />
<string name="resolver_cant_share_with_work_apps" msgid="7539495559434146897">"无法与工作应用共享数据"</string>
<string name="resolver_cant_share_with_personal_apps" msgid="8020581735267157241">"无法与个人应用共享数据"</string>
- <string name="resolver_cant_share_cross_profile_explanation" msgid="3536237105241882679">"您的 IT 管理员已禁止在个人应用和工作应用之间共享数据"</string>
- <string name="resolver_turn_on_work_apps" msgid="8987359079870455469">"打开工作应用"</string>
- <string name="resolver_turn_on_work_apps_explanation" msgid="6322467455509618928">"打开工作应用以访问工作应用和联系人"</string>
+ <!-- no translation found for resolver_cant_share_cross_profile_explanation (5556640604460901386) -->
+ <skip />
+ <!-- no translation found for resolver_cant_access_work_apps (375634344111233790) -->
+ <skip />
+ <!-- no translation found for resolver_cant_access_work_apps_explanation (3958762224516867388) -->
+ <skip />
+ <!-- no translation found for resolver_cant_access_personal_apps (1953215925406474177) -->
+ <skip />
+ <!-- no translation found for resolver_cant_access_personal_apps_explanation (1725572276741281136) -->
+ <skip />
+ <!-- no translation found for resolver_turn_on_work_apps_share (619263911204978175) -->
+ <skip />
+ <!-- no translation found for resolver_turn_on_work_apps_view (3073389230905543680) -->
+ <skip />
<string name="resolver_no_apps_available" msgid="7710339903040989654">"没有可用的应用"</string>
- <string name="resolver_no_apps_available_explanation" msgid="4662694431121196560">"系统找不到任何应用"</string>
- <string name="resolver_switch_on_work" msgid="8294542702883688533">"打开工作资料"</string>
+ <!-- no translation found for resolver_switch_on_work (2873009160846966379) -->
+ <skip />
<string name="permlab_accessCallAudio" msgid="1682957511874097664">"录制或播放电话通话音频"</string>
<string name="permdesc_accessCallAudio" msgid="8448360894684277823">"允许此应用在被指定为默认拨号器应用时录制或播放电话通话音频。"</string>
</resources>
diff --git a/core/res/res/values-zh-rHK/strings.xml b/core/res/res/values-zh-rHK/strings.xml
index 44de6bf1bf3d..b0331bf6efad 100644
--- a/core/res/res/values-zh-rHK/strings.xml
+++ b/core/res/res/values-zh-rHK/strings.xml
@@ -249,10 +249,8 @@
<item quantity="other">系統將在 <xliff:g id="NUMBER_1">%d</xliff:g> 秒後擷取錯誤報告的螢幕畫面。</item>
<item quantity="one">系統將在 <xliff:g id="NUMBER_0">%d</xliff:g> 秒後擷取錯誤報告的螢幕畫面。</item>
</plurals>
- <!-- no translation found for bugreport_screenshot_success_toast (7986095104151473745) -->
- <skip />
- <!-- no translation found for bugreport_screenshot_failure_toast (6736320861311294294) -->
- <skip />
+ <string name="bugreport_screenshot_success_toast" msgid="7986095104151473745">"已為錯誤報告擷取螢幕截圖"</string>
+ <string name="bugreport_screenshot_failure_toast" msgid="6736320861311294294">"無法為錯誤報告擷取螢幕截圖"</string>
<string name="global_action_toggle_silent_mode" msgid="8464352592860372188">"靜音模式"</string>
<string name="global_action_silent_mode_on_status" msgid="2371892537738632013">"關閉音效"</string>
<string name="global_action_silent_mode_off_status" msgid="6608006545950920042">"音效已開啟"</string>
@@ -454,9 +452,11 @@
<string name="permdesc_acceptHandovers" msgid="7129026180128626870">"允許應用程式繼續進行在其他應用程式中開始的通話。"</string>
<string name="permlab_readPhoneNumbers" msgid="5668704794723365628">"讀取電話號碼"</string>
<string name="permdesc_readPhoneNumbers" msgid="7368652482818338871">"允許應用程式存取裝置上的電話號碼。"</string>
+ <string name="permlab_wakeLock" product="automotive" msgid="1904736682319375676">"保持汽車螢幕開啟"</string>
<string name="permlab_wakeLock" product="tablet" msgid="1527660973931694000">"防止平板電腦進入休眠狀態"</string>
<string name="permlab_wakeLock" product="tv" msgid="2856941418123343518">"防止 Android TV 裝置進入休眠狀態"</string>
<string name="permlab_wakeLock" product="default" msgid="569409726861695115">"防止手機進入休眠狀態"</string>
+ <string name="permdesc_wakeLock" product="automotive" msgid="5995045369683254571">"允許應用程式保持汽車螢幕開啟。"</string>
<string name="permdesc_wakeLock" product="tablet" msgid="2441742939101526277">"允許應用程式防止平板電腦進入休眠狀態。"</string>
<string name="permdesc_wakeLock" product="tv" msgid="2329298966735118796">"允許應用程式防止 Android TV 裝置進入休眠狀態。"</string>
<string name="permdesc_wakeLock" product="default" msgid="3689523792074007163">"允許應用程式防止手機進入休眠狀態。"</string>
@@ -1631,6 +1631,12 @@
<string name="safe_media_volume_warning" product="default" msgid="3751676824423049994">"要調高音量 (比建議的音量更大聲) 嗎?\n\n長時間聆聽高分貝音量可能會導致您的聽力受損。"</string>
<string name="accessibility_shortcut_warning_dialog_title" msgid="4017995837692622933">"要使用無障礙功能快速鍵嗎?"</string>
<string name="accessibility_shortcut_toogle_warning" msgid="4161716521310929544">"啟用快速鍵後,同時按住音量按鈕 3 秒便可啟用無障礙功能。"</string>
+ <!-- no translation found for accessibility_select_shortcut_menu_title (7310194076629867377) -->
+ <skip />
+ <!-- no translation found for accessibility_edit_shortcut_menu_button_title (6096484087245145325) -->
+ <skip />
+ <!-- no translation found for accessibility_edit_shortcut_menu_volume_title (4849108668454490699) -->
+ <skip />
<string name="edit_accessibility_shortcut_menu_button" msgid="8885752738733772935">"編輯捷徑"</string>
<string name="cancel_accessibility_shortcut_menu_button" msgid="1817413122335452474">"取消"</string>
<string name="disable_accessibility_shortcut" msgid="5806091378745232383">"關閉快速鍵"</string>
@@ -1853,8 +1859,7 @@
<string name="default_notification_channel_label" msgid="3697928973567217330">"未分類"</string>
<string name="importance_from_user" msgid="2782756722448800447">"您可以設定這些通知的重要性。"</string>
<string name="importance_from_person" msgid="4235804979664465383">"列為重要的原因:涉及的人。"</string>
- <!-- no translation found for notification_history_title_placeholder (7748630986182249599) -->
- <skip />
+ <string name="notification_history_title_placeholder" msgid="7748630986182249599">"自訂應用程式通知"</string>
<string name="user_creation_account_exists" msgid="2239146360099708035">"要允許 <xliff:g id="APP">%1$s</xliff:g> 使用 <xliff:g id="ACCOUNT">%2$s</xliff:g> 建立新使用者 (此帳戶目前已有此使用者) 嗎?"</string>
<string name="user_creation_adding" msgid="7305185499667958364">"要允許 <xliff:g id="APP">%1$s</xliff:g> 使用 <xliff:g id="ACCOUNT">%2$s</xliff:g> 建立新使用者嗎?"</string>
<string name="language_selection_title" msgid="52674936078683285">"新增語言"</string>
@@ -2028,14 +2033,29 @@
<string name="as_app_forced_to_restricted_bucket" msgid="8233871289353898964">"<xliff:g id="PACKAGE_NAME">%1$s</xliff:g> 已納入受限制的儲存區"</string>
<string name="resolver_personal_tab" msgid="2051260504014442073">"個人"</string>
<string name="resolver_work_tab" msgid="2690019516263167035">"公司"</string>
+ <!-- no translation found for resolver_personal_tab_accessibility (5739524949153091224) -->
+ <skip />
+ <!-- no translation found for resolver_work_tab_accessibility (4753168230363802734) -->
+ <skip />
<string name="resolver_cant_share_with_work_apps" msgid="7539495559434146897">"無法與工作應用程式分享"</string>
<string name="resolver_cant_share_with_personal_apps" msgid="8020581735267157241">"無法與個人應用程式分享"</string>
- <string name="resolver_cant_share_cross_profile_explanation" msgid="3536237105241882679">"您的 IT 管理員已封鎖個人和工作應用程式之間的分享功能"</string>
- <string name="resolver_turn_on_work_apps" msgid="8987359079870455469">"開啟工作應用程式"</string>
- <string name="resolver_turn_on_work_apps_explanation" msgid="6322467455509618928">"開啟工作應用程式以存取工作應用程式和聯絡人"</string>
+ <!-- no translation found for resolver_cant_share_cross_profile_explanation (5556640604460901386) -->
+ <skip />
+ <!-- no translation found for resolver_cant_access_work_apps (375634344111233790) -->
+ <skip />
+ <!-- no translation found for resolver_cant_access_work_apps_explanation (3958762224516867388) -->
+ <skip />
+ <!-- no translation found for resolver_cant_access_personal_apps (1953215925406474177) -->
+ <skip />
+ <!-- no translation found for resolver_cant_access_personal_apps_explanation (1725572276741281136) -->
+ <skip />
+ <!-- no translation found for resolver_turn_on_work_apps_share (619263911204978175) -->
+ <skip />
+ <!-- no translation found for resolver_turn_on_work_apps_view (3073389230905543680) -->
+ <skip />
<string name="resolver_no_apps_available" msgid="7710339903040989654">"沒有可用的應用程式"</string>
- <string name="resolver_no_apps_available_explanation" msgid="4662694431121196560">"系統找不到任何應用程式"</string>
- <string name="resolver_switch_on_work" msgid="8294542702883688533">"開啟工作設定檔"</string>
+ <!-- no translation found for resolver_switch_on_work (2873009160846966379) -->
+ <skip />
<string name="permlab_accessCallAudio" msgid="1682957511874097664">"在電話通話中錄音或播放音訊"</string>
<string name="permdesc_accessCallAudio" msgid="8448360894684277823">"如將此應用程式指定為預設撥號器應用程式,則允許應用程式在電話通話中錄音或播放音訊。"</string>
</resources>
diff --git a/core/res/res/values-zh-rTW/strings.xml b/core/res/res/values-zh-rTW/strings.xml
index 9e1b0d42a8f2..fe5fe1a80b54 100644
--- a/core/res/res/values-zh-rTW/strings.xml
+++ b/core/res/res/values-zh-rTW/strings.xml
@@ -249,10 +249,8 @@
<item quantity="other">系統將在 <xliff:g id="NUMBER_1">%d</xliff:g> 秒後擷取錯誤報告的螢幕畫面。</item>
<item quantity="one">系統將在 <xliff:g id="NUMBER_0">%d</xliff:g> 秒後擷取錯誤報告的螢幕畫面。</item>
</plurals>
- <!-- no translation found for bugreport_screenshot_success_toast (7986095104151473745) -->
- <skip />
- <!-- no translation found for bugreport_screenshot_failure_toast (6736320861311294294) -->
- <skip />
+ <string name="bugreport_screenshot_success_toast" msgid="7986095104151473745">"已拍攝錯誤報告的螢幕截圖"</string>
+ <string name="bugreport_screenshot_failure_toast" msgid="6736320861311294294">"無法拍攝錯誤報告的螢幕截圖"</string>
<string name="global_action_toggle_silent_mode" msgid="8464352592860372188">"靜音模式"</string>
<string name="global_action_silent_mode_on_status" msgid="2371892537738632013">"音效已關閉"</string>
<string name="global_action_silent_mode_off_status" msgid="6608006545950920042">"音效已開啟"</string>
@@ -454,9 +452,11 @@
<string name="permdesc_acceptHandovers" msgid="7129026180128626870">"允許應用程式繼續進行在其他應用程式中發起的通話。"</string>
<string name="permlab_readPhoneNumbers" msgid="5668704794723365628">"讀取電話號碼"</string>
<string name="permdesc_readPhoneNumbers" msgid="7368652482818338871">"允許應用程式存取裝置上的電話號碼資料。"</string>
+ <string name="permlab_wakeLock" product="automotive" msgid="1904736682319375676">"讓車輛螢幕保持開啟"</string>
<string name="permlab_wakeLock" product="tablet" msgid="1527660973931694000">"防止平板電腦進入休眠狀態"</string>
<string name="permlab_wakeLock" product="tv" msgid="2856941418123343518">"防止 Android TV 裝置進入休眠狀態"</string>
<string name="permlab_wakeLock" product="default" msgid="569409726861695115">"防止手機進入待命狀態"</string>
+ <string name="permdesc_wakeLock" product="automotive" msgid="5995045369683254571">"允許應用程式讓車輛螢幕保持開啟。"</string>
<string name="permdesc_wakeLock" product="tablet" msgid="2441742939101526277">"允許應用程式防止平板電腦進入休眠狀態。"</string>
<string name="permdesc_wakeLock" product="tv" msgid="2329298966735118796">"允許應用程式防止 Android TV 裝置進入休眠狀態。"</string>
<string name="permdesc_wakeLock" product="default" msgid="3689523792074007163">"允許應用程式防止手機進入休眠狀態。"</string>
@@ -1631,6 +1631,12 @@
<string name="safe_media_volume_warning" product="default" msgid="3751676824423049994">"要調高音量,比建議的音量更大聲嗎?\n\n長時間聆聽高分貝音量可能會使你的聽力受損。"</string>
<string name="accessibility_shortcut_warning_dialog_title" msgid="4017995837692622933">"要使用無障礙捷徑嗎?"</string>
<string name="accessibility_shortcut_toogle_warning" msgid="4161716521310929544">"啟用捷徑功能,只要同時按下兩個音量按鈕 3 秒,就能啟動無障礙功能。"</string>
+ <!-- no translation found for accessibility_select_shortcut_menu_title (7310194076629867377) -->
+ <skip />
+ <!-- no translation found for accessibility_edit_shortcut_menu_button_title (6096484087245145325) -->
+ <skip />
+ <!-- no translation found for accessibility_edit_shortcut_menu_volume_title (4849108668454490699) -->
+ <skip />
<string name="edit_accessibility_shortcut_menu_button" msgid="8885752738733772935">"編輯捷徑"</string>
<string name="cancel_accessibility_shortcut_menu_button" msgid="1817413122335452474">"取消"</string>
<string name="disable_accessibility_shortcut" msgid="5806091378745232383">"停用捷徑"</string>
@@ -1853,8 +1859,7 @@
<string name="default_notification_channel_label" msgid="3697928973567217330">"未分類"</string>
<string name="importance_from_user" msgid="2782756722448800447">"這些通知的重要性由你決定。"</string>
<string name="importance_from_person" msgid="4235804979664465383">"這則通知涉及特定人士,因此被歸為重要通知。"</string>
- <!-- no translation found for notification_history_title_placeholder (7748630986182249599) -->
- <skip />
+ <string name="notification_history_title_placeholder" msgid="7748630986182249599">"自訂應用程式通知"</string>
<string name="user_creation_account_exists" msgid="2239146360099708035">"要允許「<xliff:g id="APP">%1$s</xliff:g>」替 <xliff:g id="ACCOUNT">%2$s</xliff:g> (這個帳戶目前已有使用者) 建立新使用者嗎?"</string>
<string name="user_creation_adding" msgid="7305185499667958364">"要允許「<xliff:g id="APP">%1$s</xliff:g>」替 <xliff:g id="ACCOUNT">%2$s</xliff:g> 建立新使用者嗎?"</string>
<string name="language_selection_title" msgid="52674936078683285">"新增語言"</string>
@@ -2028,14 +2033,29 @@
<string name="as_app_forced_to_restricted_bucket" msgid="8233871289353898964">"已將「<xliff:g id="PACKAGE_NAME">%1$s</xliff:g>」移入受限制的值區"</string>
<string name="resolver_personal_tab" msgid="2051260504014442073">"個人"</string>
<string name="resolver_work_tab" msgid="2690019516263167035">"工作"</string>
+ <!-- no translation found for resolver_personal_tab_accessibility (5739524949153091224) -->
+ <skip />
+ <!-- no translation found for resolver_work_tab_accessibility (4753168230363802734) -->
+ <skip />
<string name="resolver_cant_share_with_work_apps" msgid="7539495559434146897">"無法與工作應用程式分享"</string>
<string name="resolver_cant_share_with_personal_apps" msgid="8020581735267157241">"無法與個人應用程式分享"</string>
- <string name="resolver_cant_share_cross_profile_explanation" msgid="3536237105241882679">"你的 IT 管理員已封鎖個人和工作應用程式之間的分享功能"</string>
- <string name="resolver_turn_on_work_apps" msgid="8987359079870455469">"開啟工作應用程式"</string>
- <string name="resolver_turn_on_work_apps_explanation" msgid="6322467455509618928">"開啟工作應用程式即可存取工作應用程式和聯絡人"</string>
+ <!-- no translation found for resolver_cant_share_cross_profile_explanation (5556640604460901386) -->
+ <skip />
+ <!-- no translation found for resolver_cant_access_work_apps (375634344111233790) -->
+ <skip />
+ <!-- no translation found for resolver_cant_access_work_apps_explanation (3958762224516867388) -->
+ <skip />
+ <!-- no translation found for resolver_cant_access_personal_apps (1953215925406474177) -->
+ <skip />
+ <!-- no translation found for resolver_cant_access_personal_apps_explanation (1725572276741281136) -->
+ <skip />
+ <!-- no translation found for resolver_turn_on_work_apps_share (619263911204978175) -->
+ <skip />
+ <!-- no translation found for resolver_turn_on_work_apps_view (3073389230905543680) -->
+ <skip />
<string name="resolver_no_apps_available" msgid="7710339903040989654">"沒有可用的應用程式"</string>
- <string name="resolver_no_apps_available_explanation" msgid="4662694431121196560">"系統找不到任何應用程式"</string>
- <string name="resolver_switch_on_work" msgid="8294542702883688533">"啟用工作資料夾"</string>
+ <!-- no translation found for resolver_switch_on_work (2873009160846966379) -->
+ <skip />
<string name="permlab_accessCallAudio" msgid="1682957511874097664">"在通話期間錄製或播放音訊"</string>
<string name="permdesc_accessCallAudio" msgid="8448360894684277823">"將這個應用程式指派為預設撥號應用程式時,允許應用程式在通話期間錄製或播放音訊。"</string>
</resources>
diff --git a/core/res/res/values-zu/strings.xml b/core/res/res/values-zu/strings.xml
index f29ac2fd8a75..148272defa78 100644
--- a/core/res/res/values-zu/strings.xml
+++ b/core/res/res/values-zu/strings.xml
@@ -249,10 +249,8 @@
<item quantity="one">Ithathela umbiko wesiphazamisi isithombe-skrini kumasekhondi angu-<xliff:g id="NUMBER_1">%d</xliff:g>.</item>
<item quantity="other">Ithathela umbiko wesiphazamisi isithombe-skrini kumasekhondi angu-<xliff:g id="NUMBER_1">%d</xliff:g>.</item>
</plurals>
- <!-- no translation found for bugreport_screenshot_success_toast (7986095104151473745) -->
- <skip />
- <!-- no translation found for bugreport_screenshot_failure_toast (6736320861311294294) -->
- <skip />
+ <string name="bugreport_screenshot_success_toast" msgid="7986095104151473745">"Isithombe-skrini sithathwe nombiko wesiphazamisi"</string>
+ <string name="bugreport_screenshot_failure_toast" msgid="6736320861311294294">"Yehlulekile ukuthatha isithombe-skrini nombiko wesiphazamisi"</string>
<string name="global_action_toggle_silent_mode" msgid="8464352592860372188">"Imodi ethulile"</string>
<string name="global_action_silent_mode_on_status" msgid="2371892537738632013">"Umsindo UVALIWE"</string>
<string name="global_action_silent_mode_off_status" msgid="6608006545950920042">"Umsindo UVULIWE"</string>
@@ -454,9 +452,11 @@
<string name="permdesc_acceptHandovers" msgid="7129026180128626870">"Ivumela uhlelo lokusebenza ukuze luqhube ikholi eqalwe kolunye uhlelo lokusebenza."</string>
<string name="permlab_readPhoneNumbers" msgid="5668704794723365628">"funda izinombolo zefoni"</string>
<string name="permdesc_readPhoneNumbers" msgid="7368652482818338871">"Ivumela uhlelo lokusebenza ukufinyelela izinombolo zefoni zedivayisi."</string>
+ <string name="permlab_wakeLock" product="automotive" msgid="1904736682319375676">"gcina isikrini semoto sivuliwe"</string>
<string name="permlab_wakeLock" product="tablet" msgid="1527660973931694000">"gwema ithebhulethi ukuba ingalali"</string>
<string name="permlab_wakeLock" product="tv" msgid="2856941418123343518">"gwema idivayisi yakho ye-Android TV ukuthi ingalali"</string>
<string name="permlab_wakeLock" product="default" msgid="569409726861695115">"gwema ifoni ukuba ingalali"</string>
+ <string name="permdesc_wakeLock" product="automotive" msgid="5995045369683254571">"Ivumela uhlelo lokusebenza ukuthi lugcine isikrini semoto sivuliwe."</string>
<string name="permdesc_wakeLock" product="tablet" msgid="2441742939101526277">"Ivumela uhlelo lokusebenza ukuthi linqande ithebulethi yakho ukuthi ilale."</string>
<string name="permdesc_wakeLock" product="tv" msgid="2329298966735118796">"Ivumela uhlelo lokusebenza ukugwema idivayisi yakho ye-Android TV ukuthi ingalali."</string>
<string name="permdesc_wakeLock" product="default" msgid="3689523792074007163">"Ivumela uhlelo lokusebenza ukuthi inqande ucingo ukuthi lulale."</string>
@@ -1631,6 +1631,12 @@
<string name="safe_media_volume_warning" product="default" msgid="3751676824423049994">"Khuphukisa ivolumu ngaphezu kweleveli enconyiwe?\n\nUkulalela ngevolumu ephezulu izikhathi ezide kungahle kulimaze ukuzwa kwakho."</string>
<string name="accessibility_shortcut_warning_dialog_title" msgid="4017995837692622933">"Sebenzisa isinqamuleli sokufinyelela?"</string>
<string name="accessibility_shortcut_toogle_warning" msgid="4161716521310929544">"Uma isinqamuleli sivuliwe, ukucindezela zombili izinkinobho zevolumu amasekhondi angu-3 kuzoqalisa isici sokufinyelela."</string>
+ <!-- no translation found for accessibility_select_shortcut_menu_title (7310194076629867377) -->
+ <skip />
+ <!-- no translation found for accessibility_edit_shortcut_menu_button_title (6096484087245145325) -->
+ <skip />
+ <!-- no translation found for accessibility_edit_shortcut_menu_volume_title (4849108668454490699) -->
+ <skip />
<string name="edit_accessibility_shortcut_menu_button" msgid="8885752738733772935">"Hlela izinqamuleli"</string>
<string name="cancel_accessibility_shortcut_menu_button" msgid="1817413122335452474">"Khansela"</string>
<string name="disable_accessibility_shortcut" msgid="5806091378745232383">"Vala isinqamuleli"</string>
@@ -1853,8 +1859,7 @@
<string name="default_notification_channel_label" msgid="3697928973567217330">"Akufakwanga esigabeni"</string>
<string name="importance_from_user" msgid="2782756722448800447">"Usethe ukubaluleka kwalezi zaziso."</string>
<string name="importance_from_person" msgid="4235804979664465383">"Lokhu kubalulekile ngenxa yabantu ababandakanyekayo."</string>
- <!-- no translation found for notification_history_title_placeholder (7748630986182249599) -->
- <skip />
+ <string name="notification_history_title_placeholder" msgid="7748630986182249599">"Isaziso sohlelo lokusebenza olungokwezifiso"</string>
<string name="user_creation_account_exists" msgid="2239146360099708035">"Vumela i-<xliff:g id="APP">%1$s</xliff:g> ukuthi idale umsebenzisi omusha nge-<xliff:g id="ACCOUNT">%2$s</xliff:g> (Umsebenzisi onale akhawunti usevele ukhona) ?"</string>
<string name="user_creation_adding" msgid="7305185499667958364">"Vumela i-<xliff:g id="APP">%1$s</xliff:g> ukuthi idale umsebenzisi omusha nge-<xliff:g id="ACCOUNT">%2$s</xliff:g> ?"</string>
<string name="language_selection_title" msgid="52674936078683285">"Engeza ulwimi"</string>
@@ -2028,14 +2033,29 @@
<string name="as_app_forced_to_restricted_bucket" msgid="8233871289353898964">"I-<xliff:g id="PACKAGE_NAME">%1$s</xliff:g> ifakwe kubhakede LOKUKHAWULELWE"</string>
<string name="resolver_personal_tab" msgid="2051260504014442073">"Okomuntu siqu"</string>
<string name="resolver_work_tab" msgid="2690019516263167035">"Umsebenzi"</string>
+ <!-- no translation found for resolver_personal_tab_accessibility (5739524949153091224) -->
+ <skip />
+ <!-- no translation found for resolver_work_tab_accessibility (4753168230363802734) -->
+ <skip />
<string name="resolver_cant_share_with_work_apps" msgid="7539495559434146897">"Ayikwazi ukwabelana ngezinhlelo zokusebenza zomsebenzi"</string>
<string name="resolver_cant_share_with_personal_apps" msgid="8020581735267157241">"Ayikwazi ukwabelana ngezinhlelo zokusebenza zomuntu siqu"</string>
- <string name="resolver_cant_share_cross_profile_explanation" msgid="3536237105241882679">"Umphathi wakho we-IT uvimbe ukwabelana phakathi kwezinhlelo zokusebenza zomuntu siqu nezomsebenzi"</string>
- <string name="resolver_turn_on_work_apps" msgid="8987359079870455469">"Vula izinhlelo zokusebenza zomsebenzi"</string>
- <string name="resolver_turn_on_work_apps_explanation" msgid="6322467455509618928">"Vula izinhlelo zokusebenza zomsebenzi ukuze ufinyelele kuzinhlelo zokusebenza zomsebenzi noxhumana nabo"</string>
+ <!-- no translation found for resolver_cant_share_cross_profile_explanation (5556640604460901386) -->
+ <skip />
+ <!-- no translation found for resolver_cant_access_work_apps (375634344111233790) -->
+ <skip />
+ <!-- no translation found for resolver_cant_access_work_apps_explanation (3958762224516867388) -->
+ <skip />
+ <!-- no translation found for resolver_cant_access_personal_apps (1953215925406474177) -->
+ <skip />
+ <!-- no translation found for resolver_cant_access_personal_apps_explanation (1725572276741281136) -->
+ <skip />
+ <!-- no translation found for resolver_turn_on_work_apps_share (619263911204978175) -->
+ <skip />
+ <!-- no translation found for resolver_turn_on_work_apps_view (3073389230905543680) -->
+ <skip />
<string name="resolver_no_apps_available" msgid="7710339903040989654">"Azikho izinhlelo zokusebenza ezitholakalayo"</string>
- <string name="resolver_no_apps_available_explanation" msgid="4662694431121196560">"Asikwazanga ukuthola izinhlelo zokusebenza"</string>
- <string name="resolver_switch_on_work" msgid="8294542702883688533">"Shintshela emsebenzini"</string>
+ <!-- no translation found for resolver_switch_on_work (2873009160846966379) -->
+ <skip />
<string name="permlab_accessCallAudio" msgid="1682957511874097664">"Rekhoda noma dlala umsindo kumakholi ocingo"</string>
<string name="permdesc_accessCallAudio" msgid="8448360894684277823">"Ivumela lolu hlelo lokusebenza, uma lunikezwe njengohlelo lokusebenza oluzenzakalelayo lokudayela, ukuze kurekhodwe noma kudlalwe umsindo kumakholi ocingo."</string>
</resources>
diff --git a/core/res/res/values/attrs.xml b/core/res/res/values/attrs.xml
index cb24c70a7d21..ecf46962f352 100644
--- a/core/res/res/values/attrs.xml
+++ b/core/res/res/values/attrs.xml
@@ -360,7 +360,7 @@
<attr name="windowFullscreen" format="boolean" />
<!-- Flag indicating whether this window should extend into overscan region. Corresponds
to {@link android.view.WindowManager.LayoutParams#FLAG_LAYOUT_IN_OVERSCAN}.
- @deprecated Overscan areas aren't set by any Android product anymore.
+ @deprecated Overscan areas aren't set by any Android product anymore as of Android 11.
-->
<attr name="windowOverscan" format="boolean" />
<!-- Flag indicating whether this is a floating window. -->
diff --git a/core/res/res/values/attrs_manifest.xml b/core/res/res/values/attrs_manifest.xml
index 950f163e0469..c2451319bdc8 100644
--- a/core/res/res/values/attrs_manifest.xml
+++ b/core/res/res/values/attrs_manifest.xml
@@ -2266,9 +2266,9 @@
a newer platform that supports more screens. -->
<attr name="resizeable" format="boolean" />
<!-- Indicates whether the application can accommodate any screen
- density. Older applications are assumed to not be able to,
- new ones able to. You can explicitly supply your abilities
- here. -->
+ density. This is assumed true if targetSdkVersion is 4 or higher.
+ @deprecated Should always be true by default and not overridden.
+ -->
<attr name="anyDensity" format="boolean" />
</declare-styleable>
@@ -2656,7 +2656,7 @@
this field is ignored and the display will remain in its current
mode.
- <p> See {@link android.content.pm.ActivityInfo #preferMinimalPostProcessing} -->
+ <p> See {@link android.content.pm.ActivityInfo#FLAG_PREFER_MINIMAL_POST_PROCESSING} -->
<attr name="preferMinimalPostProcessing" format="boolean"/>
</declare-styleable>
diff --git a/core/res/res/values/config.xml b/core/res/res/values/config.xml
index fdfe82313076..0b6e65fe9407 100644
--- a/core/res/res/values/config.xml
+++ b/core/res/res/values/config.xml
@@ -3363,16 +3363,6 @@
ratio larger than this is considered to wide and short to be usable. Currently 2.39:1. -->
<item name="config_pictureInPictureMaxAspectRatio" format="float" type="dimen">2.39</item>
- <!-- The snap mode to use for picture-in-picture. These values correspond to constants defined
- in PipSnapAlgorithm and should not be changed independently.
- 0 - Snap to the four corners
- 1 - Snap to the four corners and the mid-points on the long edge in each orientation
- 2 - Snap anywhere along the edge of the screen
- 3 - Snap anywhere along the edge of the screen and magnet to corners
- 4 - Snap to the long edges in each orientation and magnet to corners
- -->
- <integer name="config_pictureInPictureSnapMode">4</integer>
-
<!-- Controls the snap mode for the docked stack divider
0 - 3 snap targets: left/top has 16:9 ratio, 1:1, and right/bottom has 16:9 ratio
1 - 3 snap targets: fixed ratio, 1:1, (1 - fixed ratio)
@@ -4419,4 +4409,10 @@
<item>android</item>
<item>com.android.systemui</item>
</string-array>
+
+ <!-- Package name of custom media key dispatcher class used by MediaSessionService. -->
+ <string name="config_customMediaKeyDispatcher"></string>
+
+ <!-- Package name of custom session policy provider class used by MediaSessionService. -->
+ <string name="config_customSessionPolicyProvider"></string>
</resources>
diff --git a/core/res/res/values/dimens.xml b/core/res/res/values/dimens.xml
index dec079eeba44..91186179c6d8 100644
--- a/core/res/res/values/dimens.xml
+++ b/core/res/res/values/dimens.xml
@@ -126,9 +126,6 @@
<!-- The amount to leave on-screen when the PIP is minimized. -->
<dimen name="pip_minimized_visible_size">48dp</dimen>
- <!-- The the PIP decelerates at while moving from a fling. -->
- <dimen name="pip_fling_deceleration">-3000dp</dimen>
-
<!-- Min width for a tablet device -->
<dimen name="min_xlarge_screen_width">800dp</dimen>
@@ -779,6 +776,7 @@
<dimen name="resolver_empty_state_height_with_tabs">268dp</dimen>
<dimen name="resolver_max_collapsed_height">192dp</dimen>
<dimen name="resolver_max_collapsed_height_with_tabs">248dp</dimen>
+ <dimen name="resolver_tab_divider_bottom_padding">8dp</dimen>
<dimen name="chooser_action_button_icon_size">18dp</dimen>
diff --git a/core/res/res/values/public.xml b/core/res/res/values/public.xml
index 7f7bbe93ea28..39e81975fce6 100644
--- a/core/res/res/values/public.xml
+++ b/core/res/res/values/public.xml
@@ -3077,6 +3077,12 @@
<public name="config_sms_enabled_locking_shift_tables" />
</public-group>
+ <public-group type="string" first-id="0x0104002c">
+ <!-- @hide -->
+ <public name="config_customMediaKeyDispatcher" />
+ <!-- @hide -->
+ <public name="config_customSessionPolicyProvider" />
+ </public-group>
<!-- ===============================================================
DO NOT ADD UN-GROUPED ITEMS HERE
diff --git a/core/res/res/values/strings.xml b/core/res/res/values/strings.xml
index d83236c46f36..d30fdced3e38 100644
--- a/core/res/res/values/strings.xml
+++ b/core/res/res/values/strings.xml
@@ -3402,8 +3402,6 @@
<!-- A notification is shown when connected network without internet due to private dns validation failed. This is the notification's message. [CHAR LIMIT=NONE] -->
<string name="private_dns_broken_detailed">Private DNS server cannot be accessed</string>
- <!-- A notification is shown after the user logs in to a captive portal network, to indicate that the network should now have internet connectivity. This is the message of notification. [CHAR LIMIT=50] -->
- <string name="captive_portal_logged_in_detailed">Connected</string>
<!-- A notification is shown when the user connects to a network that doesn't have access to some services (e.g. Push notifications may not work). This is the notification's title. [CHAR LIMIT=50] -->
<string name="network_partial_connectivity"><xliff:g id="network_ssid" example="GoogleGuest">%1$s</xliff:g> has limited connectivity</string>
@@ -4403,12 +4401,72 @@
accessibility feature.
</string>
+ <!-- Title for a warning about security implications of enabling an accessibility
+ service. [CHAR LIMIT=NONE] -->
+ <string name="accessibility_enable_service_title">Allow
+ <xliff:g id="service" example="TalkBack">%1$s</xliff:g> to have full control of your
+ device?</string>
+
+ <!-- Warning that the device data will not be encrypted with password or PIN if
+ enabling an accessibility service and there is a secure lock setup. [CHAR LIMIT=NONE] -->
+ <string name="accessibility_enable_service_encryption_warning">If you turn on
+ <xliff:g id="service" example="TalkBack">%1$s</xliff:g>, your device won’t use your screen
+ lock to enhance data encryption.
+ </string>
+
+ <!-- Warning description that explains that it's appropriate for accessibility
+ services to have full control to help users with accessibility needs. [CHAR LIMIT=NONE] -->
+ <string name="accessibility_service_warning_description">Full control is appropriate for apps
+ that help you with accessibility needs, but not for most apps.
+ </string>
+
+ <!-- Title for the screen control in accessibility dialog. [CHAR LIMIT=NONE] -->
+ <string name="accessibility_service_screen_control_title">View and control screen</string>
+
+ <!-- Description for the screen control in accessibility dialog. [CHAR LIMIT=NONE] -->
+ <string name="accessibility_service_screen_control_description">It can read all content on the
+ screen and display content over other apps.
+ </string>
+
+ <!-- Title for the action perform in accessibility dialog. [CHAR LIMIT=NONE] -->
+ <string name="accessibility_service_action_perform_title">View and perform actions</string>
+
+ <!-- Description for the action perform in accessibility dialog. [CHAR LIMIT=NONE] -->
+ <string name="accessibility_service_action_perform_description">It can track your interactions
+ with an app or a hardware sensor, and interact with apps on your behalf.
+ </string>
+
+ <!-- String for the allow button in accessibility permission dialog. [CHAR LIMIT=10] -->
+ <string name="accessibility_dialog_button_allow">Allow</string>
+ <!-- String for the deny button in accessibility permission dialog. [CHAR LIMIT=10] -->
+ <string name="accessibility_dialog_button_deny">Deny</string>
+
+ <!-- Title for accessibility select shortcut menu dialog. [CHAR LIMIT=100] -->
+ <string name="accessibility_select_shortcut_menu_title">Tap a feature to start using it:</string>
+
+ <!-- Title for accessibility edit shortcut selection menu dialog, and dialog is triggered
+ from accessibility button. [CHAR LIMIT=100] -->
+ <string name="accessibility_edit_shortcut_menu_button_title">Choose apps to use with the
+ accessibility button
+ </string>
+
+ <!-- Title for accessibility edit shortcut selection menu dialog, and dialog is triggered
+ from volume key shortcut. [CHAR LIMIT=100] -->
+ <string name="accessibility_edit_shortcut_menu_volume_title">Choose apps to use with the
+ volume key shortcut
+ </string>
+
+ <!-- Text for showing the warning to user when uncheck the legacy app item in the accessibility
+ shortcut menu, user can aware the service to be disabled. [CHAR LIMIT=100] -->
+ <string name="accessibility_uncheck_legacy_item_warning">
+ <xliff:g id="service_name" example="TalkBack">%s</xliff:g> has been turned off</string>
+
<!-- Text in button that edit the accessibility shortcut menu, user can delete
any service item in the menu list. [CHAR LIMIT=100] -->
<string name="edit_accessibility_shortcut_menu_button">Edit shortcuts</string>
- <!-- Text in button that cancel the accessibility shortcut menu changed status. [CHAR LIMIT=100] -->
- <string name="cancel_accessibility_shortcut_menu_button">Cancel</string>
+ <!-- Text in button that complete the accessibility shortcut menu changed status. [CHAR LIMIT=100] -->
+ <string name="done_accessibility_shortcut_menu_button">Done</string>
<!-- Text in button that turns off the accessibility shortcut -->
<string name="disable_accessibility_shortcut">Turn off Shortcut</string>
@@ -5370,26 +5428,36 @@
<xliff:g id="package_name" example="com.android.example">%1$s</xliff:g> has been put into the RESTRICTED bucket</string>
<!-- ResolverActivity - profile tabs -->
- <!-- Label for the perosnal tab of the share sheet and intent resolver [CHAR LIMIT=NONE] -->
+ <!-- Label of a tab on a screen. A user can tap this tap to switch to the 'Personal' view (that shows their personal content) if they have a work profile on their device. [CHAR LIMIT=NONE] -->
<string name="resolver_personal_tab">Personal</string>
- <!-- Label for the work tab of the share sheet and intent resolver [CHAR LIMIT=NONE] -->
+ <!-- Label of a tab on a screen. A user can tap this tab to switch to the 'Work' view (that shows their work content) if they have a work profile on their device. [CHAR LIMIT=NONE] -->
<string name="resolver_work_tab">Work</string>
- <!-- Label to indicate that the user cannot share with work apps [CHAR LIMIT=NONE] -->
+ <!-- Accessibility label for the personal tab button. [CHAR LIMIT=NONE] -->
+ <string name="resolver_personal_tab_accessibility">Personal view</string>
+ <!-- Accessibility label for the work tab button. [CHAR LIMIT=NONE] -->
+ <string name="resolver_work_tab_accessibility">Work view</string>
+ <!-- Title of a screen. This text lets the user know that their IT admin doesn't allow them to share personal content with work apps. [CHAR LIMIT=NONE] -->
<string name="resolver_cant_share_with_work_apps">Can\u2019t share with work apps</string>
- <!-- Label to indicate that the user cannot share with personal apps [CHAR LIMIT=NONE] -->
+ <!-- Title of a screen. This text lets the user know that their IT admin doesn't allow them to share work content with personal apps. [CHAR LIMIT=NONE] -->
<string name="resolver_cant_share_with_personal_apps">Can\u2019t share with personal apps</string>
- <!-- Label to explain to the user that sharing between personal and work apps is not enabled by the IT admin [CHAR LIMIT=NONE] -->
- <string name="resolver_cant_share_cross_profile_explanation">Your IT admin blocked sharing between personal and work apps</string>
- <!-- Label to indicate that the user has to turn on work apps in order to access work data [CHAR LIMIT=NONE] -->
- <string name="resolver_turn_on_work_apps">Turn on work apps</string>
- <!-- Label to explain that the user has to turn on work apps in order to access work data [CHAR LIMIT=NONE] -->
- <string name="resolver_turn_on_work_apps_explanation">Turn on work apps to access work apps &amp; contacts</string>
- <!-- Label to indicate that no apps are resolved [CHAR LIMIT=NONE] -->
+ <!-- Error message. This text is explaining that the user's IT admin doesn't allow sharing between personal and work apps. [CHAR LIMIT=NONE] -->
+ <string name="resolver_cant_share_cross_profile_explanation">Your IT admin blocked sharing between personal and work profiles</string>
+ <!-- Title of an error screen. This error message lets the user know that their IT admin blocked access to work apps, and the personal content that they're trying to view in a work app, such as Chrome, isn't allowed. [CHAR LIMIT=NONE] -->
+ <string name="resolver_cant_access_work_apps">Can\u2019t access work apps</string>
+ <!-- Error message. This message lets the user know that their IT admin blocked access to work apps, and the personal content that they're trying to view in a work app, such as Chrome, isn't allowed. [CHAR LIMIT=NONE] -->
+ <string name="resolver_cant_access_work_apps_explanation">Your IT admin doesn\u2019t let you view personal content in work apps</string>
+ <!-- Title of an error screen. This error message lets the user know that their IT admin blocked access to personal apps, and the work content that they're trying to view in a personal app, such as Chrome, isn't allowed. [CHAR LIMIT=NONE] -->
+ <string name="resolver_cant_access_personal_apps">Can\u2019t access personal apps</string>
+ <!-- Error message. This message lets the user know that their IT admin blocked access to personal apps, and the work content that they're trying to view in a personal app, such as Chrome, isn't allowed. [CHAR LIMIT=NONE] -->
+ <string name="resolver_cant_access_personal_apps_explanation">Your IT admin doesn\u2019t let you view work content in personal apps</string>
+ <!-- Error message. This text lets the user know that they need to turn on work apps in order to share content. There's also a button a user can tap to turn on the apps. [CHAR LIMIT=NONE] -->
+ <string name="resolver_turn_on_work_apps_share">Turn on work profile to share content</string>
+ <!-- Error message. This text lets the user know that they need to turn on work apps in order to view content. There's also a button a user can tap to turn on the apps. [CHAR LIMIT=NONE] -->
+ <string name="resolver_turn_on_work_apps_view">Turn on work profile to view content</string>
+ <!-- Error message. This text lets the user know that work apps aren't available on the device. [CHAR LIMIT=NONE] -->
<string name="resolver_no_apps_available">No apps available</string>
- <!-- Label to explain that no apps are resolved [CHAR LIMIT=NONE] -->
- <string name="resolver_no_apps_available_explanation">We couldn\u2019t find any apps</string>
- <!-- Button which switches on the disabled work profile [CHAR LIMIT=NONE] -->
- <string name="resolver_switch_on_work">Switch on work</string>
+ <!-- Button text. This button turns on a user's work profile so they can access their work apps and data. [CHAR LIMIT=NONE] -->
+ <string name="resolver_switch_on_work">Turn on</string>
<!-- Title of an application permission, listed so the user can choose whether they want to allow the application to do this. [CHAR LIMIT=NONE] -->
<string name="permlab_accessCallAudio">Record or play audio in telephony calls</string>
diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml
index 1570f1d8232b..826379d69dd8 100644
--- a/core/res/res/values/symbols.xml
+++ b/core/res/res/values/symbols.xml
@@ -688,7 +688,6 @@
<java-symbol type="string" name="capability_title_canControlMagnification" />
<java-symbol type="string" name="capability_desc_canPerformGestures" />
<java-symbol type="string" name="capability_title_canPerformGestures" />
- <java-symbol type="string" name="captive_portal_logged_in_detailed" />
<java-symbol type="string" name="capital_off" />
<java-symbol type="string" name="capital_on" />
<java-symbol type="string" name="cfTemplateForwarded" />
@@ -1692,9 +1691,7 @@
<java-symbol type="dimen" name="docked_stack_divider_insets" />
<java-symbol type="dimen" name="docked_stack_minimize_thickness" />
<java-symbol type="dimen" name="pip_minimized_visible_size" />
- <java-symbol type="dimen" name="pip_fling_deceleration" />
<java-symbol type="integer" name="config_dockedStackDividerSnapMode" />
- <java-symbol type="integer" name="config_pictureInPictureSnapMode" />
<java-symbol type="fraction" name="docked_stack_divider_fixed_ratio" />
<java-symbol type="fraction" name="thumbnail_fullscreen_scale" />
<java-symbol type="integer" name="thumbnail_width_tv" />
@@ -3239,23 +3236,34 @@
<java-symbol type="string" name="config_defaultAccessibilityService" />
<java-symbol type="string" name="accessibility_shortcut_spoken_feedback" />
+ <java-symbol type="string" name="accessibility_select_shortcut_menu_title" />
+ <java-symbol type="string" name="accessibility_edit_shortcut_menu_button_title" />
+ <java-symbol type="string" name="accessibility_edit_shortcut_menu_volume_title" />
+ <java-symbol type="string" name="accessibility_uncheck_legacy_item_warning" />
+
+ <java-symbol type="layout" name="accessibility_enable_service_encryption_warning" />
+ <java-symbol type="id" name="accessibility_permissionDialog_icon" />
+ <java-symbol type="id" name="accessibility_permissionDialog_title" />
+ <java-symbol type="id" name="accessibility_encryption_warning" />
+ <java-symbol type="id" name="accessibility_permission_enable_allow_button" />
+ <java-symbol type="id" name="accessibility_permission_enable_deny_button" />
+ <java-symbol type="string" name="accessibility_enable_service_title" />
+ <java-symbol type="string" name="accessibility_enable_service_encryption_warning" />
+
<!-- Accessibility Button -->
<java-symbol type="layout" name="accessibility_button_chooser_item" />
+ <java-symbol type="id" name="accessibility_button_target_checkbox" />
<java-symbol type="id" name="accessibility_button_target_icon" />
<java-symbol type="id" name="accessibility_button_target_label" />
- <java-symbol type="id" name="accessibility_button_target_item_container" />
- <java-symbol type="id" name="accessibility_button_target_view_item" />
<java-symbol type="id" name="accessibility_button_target_switch_item" />
<java-symbol type="string" name="accessibility_magnification_chooser_text" />
<java-symbol type="string" name="edit_accessibility_shortcut_menu_button" />
- <java-symbol type="string" name="cancel_accessibility_shortcut_menu_button" />
+ <java-symbol type="string" name="done_accessibility_shortcut_menu_button" />
<java-symbol type="drawable" name="ic_accessibility_color_inversion" />
<java-symbol type="drawable" name="ic_accessibility_color_correction" />
<java-symbol type="drawable" name="ic_accessibility_magnification" />
- <java-symbol type="drawable" name="ic_delete_item" />
-
<!-- com.android.internal.widget.RecyclerView -->
<java-symbol type="id" name="item_touch_helper_previous_elevation"/>
<java-symbol type="dimen" name="item_touch_helper_max_drag_scroll_per_frame"/>
@@ -3872,7 +3880,9 @@
<java-symbol type="color" name="resolver_tabs_active_color" />
<java-symbol type="color" name="resolver_tabs_inactive_color" />
<java-symbol type="string" name="resolver_personal_tab" />
+ <java-symbol type="string" name="resolver_personal_tab_accessibility" />
<java-symbol type="string" name="resolver_work_tab" />
+ <java-symbol type="string" name="resolver_work_tab_accessibility" />
<java-symbol type="id" name="stub" />
<java-symbol type="id" name="resolver_empty_state" />
<java-symbol type="id" name="resolver_empty_state_icon" />
@@ -3884,11 +3894,13 @@
<java-symbol type="string" name="resolver_cant_share_with_work_apps" />
<java-symbol type="string" name="resolver_cant_share_with_personal_apps" />
<java-symbol type="string" name="resolver_cant_share_cross_profile_explanation" />
- <java-symbol type="string" name="resolver_turn_on_work_apps" />
- <java-symbol type="string" name="resolver_turn_on_work_apps_explanation" />
+ <java-symbol type="string" name="resolver_cant_access_work_apps" />
+ <java-symbol type="string" name="resolver_cant_access_work_apps_explanation" />
+ <java-symbol type="string" name="resolver_cant_access_personal_apps" />
+ <java-symbol type="string" name="resolver_cant_access_personal_apps_explanation" />
+ <java-symbol type="string" name="resolver_turn_on_work_apps_view" />
+ <java-symbol type="string" name="resolver_turn_on_work_apps_share" />
<java-symbol type="string" name="resolver_no_apps_available" />
- <java-symbol type="string" name="resolver_no_apps_available_explanation" />
- <java-symbol type="string" name="resolver_no_apps_available_explanation" />
<java-symbol type="string" name="resolver_switch_on_work" />
<java-symbol type="drawable" name="ic_work_apps_off" />
<java-symbol type="drawable" name="ic_sharing_disabled" />
@@ -3897,6 +3909,7 @@
<java-symbol type="dimen" name="resolver_empty_state_height_with_tabs" />
<java-symbol type="dimen" name="resolver_max_collapsed_height_with_tabs" />
<java-symbol type="bool" name="sharesheet_show_content_preview" />
+ <java-symbol type="dimen" name="resolver_tab_divider_bottom_padding" />
<!-- Toast message for background started foreground service while-in-use permission restriction feature -->
<java-symbol type="string" name="allow_while_in_use_permission_in_fgs" />
@@ -3912,4 +3925,6 @@
<java-symbol type="string" name="notification_history_title_placeholder" />
+ <java-symbol type="string" name="config_customMediaKeyDispatcher" />
+ <java-symbol type="string" name="config_customSessionPolicyProvider" />
</resources>
diff --git a/core/res/res/values/themes_material.xml b/core/res/res/values/themes_material.xml
index f3905e93a525..e516a6cf9d2b 100644
--- a/core/res/res/values/themes_material.xml
+++ b/core/res/res/values/themes_material.xml
@@ -962,7 +962,7 @@ please see themes_device_defaults.xml.
the entire screen and extends into the display overscan region. This theme
sets {@link android.R.attr#windowFullscreen} and {@link android.R.attr#windowOverscan}
to true.
- @deprecated Overscan areas aren't set by any Android product anymore.
+ @deprecated Overscan areas aren't set by any Android product anymore as of Android 11.
-->
<style name="Theme.Material.NoActionBar.Overscan">
<item name="windowFullscreen">true</item>
@@ -996,7 +996,7 @@ please see themes_device_defaults.xml.
the entire screen and extends into the display overscan region. This theme
sets {@link android.R.attr#windowFullscreen} and {@link android.R.attr#windowOverscan}
to true.
- @deprecated Overscan areas aren't set by any Android product anymore.
+ @deprecated Overscan areas aren't set by any Android product anymore as of Android 11.
-->
<style name="Theme.Material.Light.NoActionBar.Overscan">
<item name="windowFullscreen">true</item>
diff --git a/core/tests/coretests/Android.bp b/core/tests/coretests/Android.bp
index eb760b9c45cf..8d51a6000086 100644
--- a/core/tests/coretests/Android.bp
+++ b/core/tests/coretests/Android.bp
@@ -53,10 +53,7 @@ android_test {
"android.test.base",
"android.test.mock",
"framework-atb-backward-compatibility",
- // TODO(b/149928788): Remove this when statsd tests move into the statsd dir.
- "framework-statsd",
"framework",
- "icing-java-proto-lite",
"ext",
"framework-res",
],
diff --git a/core/tests/coretests/src/android/app/NotificationHistoryTest.java b/core/tests/coretests/src/android/app/NotificationHistoryTest.java
index 0443d3a9e73f..c9510918e555 100644
--- a/core/tests/coretests/src/android/app/NotificationHistoryTest.java
+++ b/core/tests/coretests/src/android/app/NotificationHistoryTest.java
@@ -351,5 +351,7 @@ public class NotificationHistoryTest {
HistoricalNotification postParcelNotification = parceledHistory.getNextNotification();
assertThat(postParcelNotification).isEqualTo(expectedEntries.get(i));
}
+ assertThat(parceledHistory.hasNextNotification()).isFalse();
+ assertThat(parceledHistory.getNextNotification()).isNull();
}
}
diff --git a/core/tests/coretests/src/android/app/appsearch/AppSearchDocumentTest.java b/core/tests/coretests/src/android/app/appsearch/AppSearchDocumentTest.java
deleted file mode 100644
index 4a4f13676cb3..000000000000
--- a/core/tests/coretests/src/android/app/appsearch/AppSearchDocumentTest.java
+++ /dev/null
@@ -1,262 +0,0 @@
-/*
- * Copyright (C) 2020 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.app.appsearch;
-
-import static com.google.common.truth.Truth.assertThat;
-
-import static org.testng.Assert.assertThrows;
-
-import androidx.test.filters.SmallTest;
-
-import com.google.android.icing.proto.DocumentProto;
-import com.google.android.icing.proto.PropertyProto;
-import com.google.android.icing.protobuf.ByteString;
-
-import org.junit.Test;
-
-import java.util.ArrayList;
-import java.util.Collections;
-import java.util.HashMap;
-import java.util.List;
-
-@SmallTest
-public class AppSearchDocumentTest {
- private static final byte[] sByteArray1 = new byte[]{(byte) 1, (byte) 2, (byte) 3};
- private static final byte[] sByteArray2 = new byte[]{(byte) 4, (byte) 5, (byte) 6};
- private static final AppSearchDocument sDocumentProperties1 = new AppSearchDocument
- .Builder("sDocumentProperties1", "sDocumentPropertiesSchemaType1")
- .build();
- private static final AppSearchDocument sDocumentProperties2 = new AppSearchDocument
- .Builder("sDocumentProperties2", "sDocumentPropertiesSchemaType2")
- .build();
-
- @Test
- public void testDocumentEquals_Identical() {
- AppSearchDocument document1 = new AppSearchDocument.Builder("uri1", "schemaType1")
- .setCreationTimestampMillis(5L)
- .setTtlMillis(1L)
- .setProperty("longKey1", 1L, 2L, 3L)
- .setProperty("doubleKey1", 1.0, 2.0, 3.0)
- .setProperty("booleanKey1", true, false, true)
- .setProperty("stringKey1", "test-value1", "test-value2", "test-value3")
- .setProperty("byteKey1", sByteArray1, sByteArray2)
- .setProperty("documentKey1", sDocumentProperties1, sDocumentProperties2)
- .build();
- AppSearchDocument document2 = new AppSearchDocument.Builder("uri1", "schemaType1")
- .setCreationTimestampMillis(5L)
- .setTtlMillis(1L)
- .setProperty("longKey1", 1L, 2L, 3L)
- .setProperty("doubleKey1", 1.0, 2.0, 3.0)
- .setProperty("booleanKey1", true, false, true)
- .setProperty("stringKey1", "test-value1", "test-value2", "test-value3")
- .setProperty("byteKey1", sByteArray1, sByteArray2)
- .setProperty("documentKey1", sDocumentProperties1, sDocumentProperties2)
- .build();
- assertThat(document1).isEqualTo(document2);
- assertThat(document1.hashCode()).isEqualTo(document2.hashCode());
- }
-
- @Test
- public void testDocumentEquals_DifferentOrder() {
- AppSearchDocument document1 = new AppSearchDocument.Builder("uri1", "schemaType1")
- .setCreationTimestampMillis(5L)
- .setProperty("longKey1", 1L, 2L, 3L)
- .setProperty("byteKey1", sByteArray1, sByteArray2)
- .setProperty("doubleKey1", 1.0, 2.0, 3.0)
- .setProperty("booleanKey1", true, false, true)
- .setProperty("documentKey1", sDocumentProperties1, sDocumentProperties2)
- .setProperty("stringKey1", "test-value1", "test-value2", "test-value3")
- .build();
-
- // Create second document with same parameter but different order.
- AppSearchDocument document2 = new AppSearchDocument.Builder("uri1", "schemaType1")
- .setCreationTimestampMillis(5L)
- .setProperty("booleanKey1", true, false, true)
- .setProperty("documentKey1", sDocumentProperties1, sDocumentProperties2)
- .setProperty("stringKey1", "test-value1", "test-value2", "test-value3")
- .setProperty("doubleKey1", 1.0, 2.0, 3.0)
- .setProperty("byteKey1", sByteArray1, sByteArray2)
- .setProperty("longKey1", 1L, 2L, 3L)
- .build();
- assertThat(document1).isEqualTo(document2);
- assertThat(document1.hashCode()).isEqualTo(document2.hashCode());
- }
-
- @Test
- public void testDocumentEquals_Failure() {
- AppSearchDocument document1 = new AppSearchDocument.Builder("uri1", "schemaType1")
- .setCreationTimestampMillis(5L)
- .setProperty("longKey1", 1L, 2L, 3L)
- .build();
-
- // Create second document with same order but different value.
- AppSearchDocument document2 = new AppSearchDocument.Builder("uri1", "schemaType1")
- .setCreationTimestampMillis(5L)
- .setProperty("longKey1", 1L, 2L, 4L) // Different
- .build();
- assertThat(document1).isNotEqualTo(document2);
- assertThat(document1.hashCode()).isNotEqualTo(document2.hashCode());
- }
-
- @Test
- public void testDocumentEquals_Failure_RepeatedFieldOrder() {
- AppSearchDocument document1 = new AppSearchDocument.Builder("uri1", "schemaType1")
- .setCreationTimestampMillis(5L)
- .setProperty("booleanKey1", true, false, true)
- .build();
-
- // Create second document with same order but different value.
- AppSearchDocument document2 = new AppSearchDocument.Builder("uri1", "schemaType1")
- .setCreationTimestampMillis(5L)
- .setProperty("booleanKey1", true, true, false) // Different
- .build();
- assertThat(document1).isNotEqualTo(document2);
- assertThat(document1.hashCode()).isNotEqualTo(document2.hashCode());
- }
-
- @Test
- public void testDocumentGetSingleValue() {
- AppSearchDocument document = new AppSearchDocument.Builder("uri1", "schemaType1")
- .setCreationTimestampMillis(5L)
- .setScore(1)
- .setTtlMillis(1L)
- .setProperty("longKey1", 1L)
- .setProperty("doubleKey1", 1.0)
- .setProperty("booleanKey1", true)
- .setProperty("stringKey1", "test-value1")
- .setProperty("byteKey1", sByteArray1)
- .setProperty("documentKey1", sDocumentProperties1)
- .build();
- assertThat(document.getUri()).isEqualTo("uri1");
- assertThat(document.getTtlMillis()).isEqualTo(1L);
- assertThat(document.getSchemaType()).isEqualTo("schemaType1");
- assertThat(document.getCreationTimestampMillis()).isEqualTo(5);
- assertThat(document.getScore()).isEqualTo(1);
- assertThat(document.getPropertyLong("longKey1")).isEqualTo(1L);
- assertThat(document.getPropertyDouble("doubleKey1")).isEqualTo(1.0);
- assertThat(document.getPropertyBoolean("booleanKey1")).isTrue();
- assertThat(document.getPropertyString("stringKey1")).isEqualTo("test-value1");
- assertThat(document.getPropertyBytes("byteKey1"))
- .asList().containsExactly((byte) 1, (byte) 2, (byte) 3);
- assertThat(document.getPropertyDocument("documentKey1")).isEqualTo(sDocumentProperties1);
- }
-
- @Test
- public void testDocumentGetArrayValues() {
- AppSearchDocument document = new AppSearchDocument.Builder("uri1", "schemaType1")
- .setCreationTimestampMillis(5L)
- .setProperty("longKey1", 1L, 2L, 3L)
- .setProperty("doubleKey1", 1.0, 2.0, 3.0)
- .setProperty("booleanKey1", true, false, true)
- .setProperty("stringKey1", "test-value1", "test-value2", "test-value3")
- .setProperty("byteKey1", sByteArray1, sByteArray2)
- .setProperty("documentKey1", sDocumentProperties1, sDocumentProperties2)
- .build();
-
- assertThat(document.getUri()).isEqualTo("uri1");
- assertThat(document.getSchemaType()).isEqualTo("schemaType1");
- assertThat(document.getPropertyLongArray("longKey1")).asList().containsExactly(1L, 2L, 3L);
- assertThat(document.getPropertyDoubleArray("doubleKey1")).usingExactEquality()
- .containsExactly(1.0, 2.0, 3.0);
- assertThat(document.getPropertyBooleanArray("booleanKey1")).asList()
- .containsExactly(true, false, true);
- assertThat(document.getPropertyStringArray("stringKey1")).asList()
- .containsExactly("test-value1", "test-value2", "test-value3");
- assertThat(document.getPropertyBytesArray("byteKey1")).asList()
- .containsExactly(sByteArray1, sByteArray2);
- assertThat(document.getPropertyDocumentArray("documentKey1")).asList()
- .containsExactly(sDocumentProperties1, sDocumentProperties2);
- }
-
- @Test
- public void testDocumentGetValues_DifferentTypes() {
- AppSearchDocument document = new AppSearchDocument.Builder("uri1", "schemaType1")
- .setScore(1)
- .setProperty("longKey1", 1L)
- .setProperty("booleanKey1", true, false, true)
- .setProperty("stringKey1", "test-value1", "test-value2", "test-value3")
- .build();
-
- // Get a value for a key that doesn't exist
- assertThat(document.getPropertyDouble("doubleKey1")).isNull();
- assertThat(document.getPropertyDoubleArray("doubleKey1")).isNull();
-
- // Get a value with a single element as an array and as a single value
- assertThat(document.getPropertyLong("longKey1")).isEqualTo(1L);
- assertThat(document.getPropertyLongArray("longKey1")).asList().containsExactly(1L);
-
- // Get a value with multiple elements as an array and as a single value
- assertThat(document.getPropertyString("stringKey1")).isEqualTo("test-value1");
- assertThat(document.getPropertyStringArray("stringKey1")).asList()
- .containsExactly("test-value1", "test-value2", "test-value3");
-
- // Get a value of the wrong type
- assertThat(document.getPropertyDouble("longKey1")).isNull();
- assertThat(document.getPropertyDoubleArray("longKey1")).isNull();
- }
-
- @Test
- public void testDocumentInvalid() {
- AppSearchDocument.Builder builder = new AppSearchDocument.Builder("uri1", "schemaType1");
- assertThrows(
- IllegalArgumentException.class, () -> builder.setProperty("test", new boolean[]{}));
- }
-
- @Test
- public void testDocumentProtoPopulation() {
- AppSearchDocument document = new AppSearchDocument.Builder("uri1", "schemaType1")
- .setCreationTimestampMillis(5L)
- .setScore(1)
- .setTtlMillis(1L)
- .setProperty("longKey1", 1L)
- .setProperty("doubleKey1", 1.0)
- .setProperty("booleanKey1", true)
- .setProperty("stringKey1", "test-value1")
- .setProperty("byteKey1", sByteArray1)
- .setProperty("documentKey1", sDocumentProperties1)
- .build();
-
- // Create the Document proto. Need to sort the property order by key.
- DocumentProto.Builder documentProtoBuilder = DocumentProto.newBuilder()
- .setUri("uri1")
- .setSchema("schemaType1")
- .setCreationTimestampMs(5L)
- .setScore(1)
- .setTtlMs(1L);
- HashMap<String, PropertyProto.Builder> propertyProtoMap = new HashMap<>();
- propertyProtoMap.put("longKey1",
- PropertyProto.newBuilder().setName("longKey1").addInt64Values(1L));
- propertyProtoMap.put("doubleKey1",
- PropertyProto.newBuilder().setName("doubleKey1").addDoubleValues(1.0));
- propertyProtoMap.put("booleanKey1",
- PropertyProto.newBuilder().setName("booleanKey1").addBooleanValues(true));
- propertyProtoMap.put("stringKey1",
- PropertyProto.newBuilder().setName("stringKey1").addStringValues("test-value1"));
- propertyProtoMap.put("byteKey1",
- PropertyProto.newBuilder().setName("byteKey1").addBytesValues(
- ByteString.copyFrom(sByteArray1)));
- propertyProtoMap.put("documentKey1",
- PropertyProto.newBuilder().setName("documentKey1")
- .addDocumentValues(sDocumentProperties1.getProto()));
- List<String> sortedKey = new ArrayList<>(propertyProtoMap.keySet());
- Collections.sort(sortedKey);
- for (String key : sortedKey) {
- documentProtoBuilder.addProperties(propertyProtoMap.get(key));
- }
- assertThat(document.getProto()).isEqualTo(documentProtoBuilder.build());
- }
-}
diff --git a/core/tests/coretests/src/android/app/appsearch/AppSearchEmailTest.java b/core/tests/coretests/src/android/app/appsearch/AppSearchEmailTest.java
deleted file mode 100644
index 6aa16cc1e323..000000000000
--- a/core/tests/coretests/src/android/app/appsearch/AppSearchEmailTest.java
+++ /dev/null
@@ -1,53 +0,0 @@
-/*
- * Copyright (C) 2020 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.app.appsearch;
-
-import static com.google.common.truth.Truth.assertThat;
-
-import androidx.test.filters.SmallTest;
-
-import org.junit.Test;
-
-@SmallTest
-public class AppSearchEmailTest {
-
- @Test
- public void testBuildEmailAndGetValue() {
- AppSearchEmail email = new AppSearchEmail.Builder("uri")
- .setFrom("FakeFromAddress")
- .setCc("CC1", "CC2")
- // Score and Property are mixed into the middle to make sure DocumentBuilder's
- // methods can be interleaved with EmailBuilder's methods.
- .setScore(1)
- .setProperty("propertyKey", "propertyValue1", "propertyValue2")
- .setSubject("subject")
- .setBody("EmailBody")
- .build();
-
- assertThat(email.getUri()).isEqualTo("uri");
- assertThat(email.getFrom()).isEqualTo("FakeFromAddress");
- assertThat(email.getTo()).isNull();
- assertThat(email.getCc()).asList().containsExactly("CC1", "CC2");
- assertThat(email.getBcc()).isNull();
- assertThat(email.getScore()).isEqualTo(1);
- assertThat(email.getPropertyString("propertyKey")).isEqualTo("propertyValue1");
- assertThat(email.getPropertyStringArray("propertyKey")).asList().containsExactly(
- "propertyValue1", "propertyValue2");
- assertThat(email.getSubject()).isEqualTo("subject");
- assertThat(email.getBody()).isEqualTo("EmailBody");
- }
-}
diff --git a/core/tests/coretests/src/android/app/appsearch/AppSearchSchemaTest.java b/core/tests/coretests/src/android/app/appsearch/AppSearchSchemaTest.java
deleted file mode 100644
index 08ec2d0b1067..000000000000
--- a/core/tests/coretests/src/android/app/appsearch/AppSearchSchemaTest.java
+++ /dev/null
@@ -1,166 +0,0 @@
-/*
- * Copyright (C) 2019 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.app.appsearch;
-
-import static com.google.common.truth.Truth.assertThat;
-
-import static org.testng.Assert.assertThrows;
-import static org.testng.Assert.expectThrows;
-
-import android.app.appsearch.AppSearchSchema.PropertyConfig;
-
-import androidx.test.filters.SmallTest;
-
-import com.google.android.icing.proto.IndexingConfig.TokenizerType;
-import com.google.android.icing.proto.PropertyConfigProto;
-import com.google.android.icing.proto.SchemaTypeConfigProto;
-import com.google.android.icing.proto.TermMatchType;
-
-import org.junit.Test;
-
-@SmallTest
-public class AppSearchSchemaTest {
- @Test
- public void testGetProto_Email() {
- AppSearchSchema emailSchema = AppSearchSchema.newBuilder("Email")
- .addProperty(AppSearchSchema.newPropertyBuilder("subject")
- .setDataType(PropertyConfig.DATA_TYPE_STRING)
- .setCardinality(PropertyConfig.CARDINALITY_OPTIONAL)
- .setIndexingType(PropertyConfig.INDEXING_TYPE_PREFIXES)
- .setTokenizerType(PropertyConfig.TOKENIZER_TYPE_PLAIN)
- .build()
- ).addProperty(AppSearchSchema.newPropertyBuilder("body")
- .setDataType(PropertyConfig.DATA_TYPE_STRING)
- .setCardinality(PropertyConfig.CARDINALITY_OPTIONAL)
- .setIndexingType(PropertyConfig.INDEXING_TYPE_PREFIXES)
- .setTokenizerType(PropertyConfig.TOKENIZER_TYPE_PLAIN)
- .build()
- ).build();
-
- SchemaTypeConfigProto expectedEmailProto = SchemaTypeConfigProto.newBuilder()
- .setSchemaType("Email")
- .addProperties(PropertyConfigProto.newBuilder()
- .setPropertyName("subject")
- .setDataType(PropertyConfigProto.DataType.Code.STRING)
- .setCardinality(PropertyConfigProto.Cardinality.Code.OPTIONAL)
- .setIndexingConfig(
- com.google.android.icing.proto.IndexingConfig.newBuilder()
- .setTokenizerType(TokenizerType.Code.PLAIN)
- .setTermMatchType(TermMatchType.Code.PREFIX)
- )
- ).addProperties(PropertyConfigProto.newBuilder()
- .setPropertyName("body")
- .setDataType(PropertyConfigProto.DataType.Code.STRING)
- .setCardinality(PropertyConfigProto.Cardinality.Code.OPTIONAL)
- .setIndexingConfig(
- com.google.android.icing.proto.IndexingConfig.newBuilder()
- .setTokenizerType(TokenizerType.Code.PLAIN)
- .setTermMatchType(TermMatchType.Code.PREFIX)
- )
- ).build();
-
- assertThat(emailSchema.getProto()).isEqualTo(expectedEmailProto);
- }
-
- @Test
- public void testGetProto_MusicRecording() {
- AppSearchSchema musicRecordingSchema = AppSearchSchema.newBuilder("MusicRecording")
- .addProperty(AppSearchSchema.newPropertyBuilder("artist")
- .setDataType(PropertyConfig.DATA_TYPE_STRING)
- .setCardinality(PropertyConfig.CARDINALITY_REPEATED)
- .setIndexingType(PropertyConfig.INDEXING_TYPE_PREFIXES)
- .setTokenizerType(PropertyConfig.TOKENIZER_TYPE_PLAIN)
- .build()
- ).addProperty(AppSearchSchema.newPropertyBuilder("pubDate")
- .setDataType(PropertyConfig.DATA_TYPE_INT64)
- .setCardinality(PropertyConfig.CARDINALITY_OPTIONAL)
- .setIndexingType(PropertyConfig.INDEXING_TYPE_NONE)
- .setTokenizerType(PropertyConfig.TOKENIZER_TYPE_NONE)
- .build()
- ).build();
-
- SchemaTypeConfigProto expectedMusicRecordingProto = SchemaTypeConfigProto.newBuilder()
- .setSchemaType("MusicRecording")
- .addProperties(PropertyConfigProto.newBuilder()
- .setPropertyName("artist")
- .setDataType(PropertyConfigProto.DataType.Code.STRING)
- .setCardinality(PropertyConfigProto.Cardinality.Code.REPEATED)
- .setIndexingConfig(
- com.google.android.icing.proto.IndexingConfig.newBuilder()
- .setTokenizerType(TokenizerType.Code.PLAIN)
- .setTermMatchType(TermMatchType.Code.PREFIX)
- )
- ).addProperties(PropertyConfigProto.newBuilder()
- .setPropertyName("pubDate")
- .setDataType(PropertyConfigProto.DataType.Code.INT64)
- .setCardinality(PropertyConfigProto.Cardinality.Code.OPTIONAL)
- .setIndexingConfig(
- com.google.android.icing.proto.IndexingConfig.newBuilder()
- .setTokenizerType(TokenizerType.Code.NONE)
- .setTermMatchType(TermMatchType.Code.UNKNOWN)
- )
- ).build();
-
- assertThat(musicRecordingSchema.getProto()).isEqualTo(expectedMusicRecordingProto);
- }
-
- @Test
- public void testInvalidEnums() {
- PropertyConfig.Builder builder = AppSearchSchema.newPropertyBuilder("test");
- assertThrows(IllegalArgumentException.class, () -> builder.setDataType(99));
- assertThrows(IllegalArgumentException.class, () -> builder.setCardinality(99));
- }
-
- @Test
- public void testMissingFields() {
- PropertyConfig.Builder builder = AppSearchSchema.newPropertyBuilder("test");
- Exception e = expectThrows(IllegalSchemaException.class, builder::build);
- assertThat(e).hasMessageThat().contains("Missing field: dataType");
-
- builder.setDataType(PropertyConfig.DATA_TYPE_DOCUMENT);
- e = expectThrows(IllegalSchemaException.class, builder::build);
- assertThat(e).hasMessageThat().contains("Missing field: schemaType");
-
- builder.setSchemaType("TestType");
- e = expectThrows(IllegalSchemaException.class, builder::build);
- assertThat(e).hasMessageThat().contains("Missing field: cardinality");
-
- builder.setCardinality(PropertyConfig.CARDINALITY_REPEATED);
- builder.build();
- }
-
- @Test
- public void testDuplicateProperties() {
- AppSearchSchema.Builder builder = AppSearchSchema.newBuilder("Email")
- .addProperty(AppSearchSchema.newPropertyBuilder("subject")
- .setDataType(PropertyConfig.DATA_TYPE_STRING)
- .setCardinality(PropertyConfig.CARDINALITY_OPTIONAL)
- .setIndexingType(PropertyConfig.INDEXING_TYPE_PREFIXES)
- .setTokenizerType(PropertyConfig.TOKENIZER_TYPE_PLAIN)
- .build()
- ).addProperty(AppSearchSchema.newPropertyBuilder("subject")
- .setDataType(PropertyConfig.DATA_TYPE_STRING)
- .setCardinality(PropertyConfig.CARDINALITY_OPTIONAL)
- .setIndexingType(PropertyConfig.INDEXING_TYPE_PREFIXES)
- .setTokenizerType(PropertyConfig.TOKENIZER_TYPE_PLAIN)
- .build()
- );
-
- Exception e = expectThrows(IllegalSchemaException.class, builder::build);
- assertThat(e).hasMessageThat().contains("Property defined more than once: subject");
- }
-}
diff --git a/core/tests/coretests/src/android/app/appsearch/SearchResultsTest.java b/core/tests/coretests/src/android/app/appsearch/SearchResultsTest.java
deleted file mode 100644
index 21259cc81758..000000000000
--- a/core/tests/coretests/src/android/app/appsearch/SearchResultsTest.java
+++ /dev/null
@@ -1,66 +0,0 @@
-/*
- * Copyright (C) 2020 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.app.appsearch;
-
-import static com.google.common.truth.Truth.assertThat;
-
-import static org.testng.Assert.assertThrows;
-
-import androidx.test.filters.SmallTest;
-
-import com.google.android.icing.proto.DocumentProto;
-import com.google.android.icing.proto.SearchResultProto;
-
-import org.junit.Test;
-
-@SmallTest
-public class SearchResultsTest {
-
- @Test
- public void testSearchResultsEqual() {
- final String uri = "testUri";
- final String schemaType = "testSchema";
- SearchResultProto.ResultProto result1 = SearchResultProto.ResultProto.newBuilder()
- .setDocument(DocumentProto.newBuilder()
- .setUri(uri)
- .setSchema(schemaType)
- .build())
- .build();
- SearchResultProto searchResults1 = SearchResultProto.newBuilder()
- .addResults(result1)
- .build();
- SearchResults res1 = new SearchResults(searchResults1);
- SearchResultProto.ResultProto result2 = SearchResultProto.ResultProto.newBuilder()
- .setDocument(DocumentProto.newBuilder()
- .setUri(uri)
- .setSchema(schemaType)
- .build())
- .build();
- SearchResultProto searchResults2 = SearchResultProto.newBuilder()
- .addResults(result2)
- .build();
- SearchResults res2 = new SearchResults(searchResults2);
- assertThat(res1.toString()).isEqualTo(res2.toString());
- }
-
- @Test
- public void buildSearchSpecWithoutTermMatchType() {
- assertThrows(RuntimeException.class, () -> SearchSpec.newBuilder()
- .setSchemaTypes("testSchemaType")
- .build());
- }
-}
diff --git a/core/tests/coretests/src/android/app/appsearch/SnippetTest.java b/core/tests/coretests/src/android/app/appsearch/SnippetTest.java
deleted file mode 100644
index 3103708f985d..000000000000
--- a/core/tests/coretests/src/android/app/appsearch/SnippetTest.java
+++ /dev/null
@@ -1,200 +0,0 @@
-/*
- * Copyright (C) 2019 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.app.appsearch;
-
-import static com.google.common.truth.Truth.assertThat;
-
-import androidx.test.filters.SmallTest;
-
-import com.google.android.icing.proto.DocumentProto;
-import com.google.android.icing.proto.PropertyProto;
-import com.google.android.icing.proto.SearchResultProto;
-import com.google.android.icing.proto.SnippetMatchProto;
-import com.google.android.icing.proto.SnippetProto;
-
-import org.junit.Test;
-
-@SmallTest
-public class SnippetTest {
-
- // TODO(sidchhabra): Add tests for Double and Long Snippets.
- @Test
- public void testSingleStringSnippet() {
-
- final String propertyKeyString = "content";
- final String propertyValueString = "A commonly used fake word is foo.\n"
- + " Another nonsense word that’s used a lot\n"
- + " is bar.\n";
- final String uri = "uri1";
- final String schemaType = "schema1";
- final String searchWord = "foo";
- final String exactMatch = "foo";
- final String window = "is foo";
-
- // Building the SearchResult received from query.
- PropertyProto property = PropertyProto.newBuilder()
- .setName(propertyKeyString)
- .addStringValues(propertyValueString)
- .build();
- DocumentProto documentProto = DocumentProto.newBuilder()
- .setUri(uri)
- .setSchema(schemaType)
- .addProperties(property)
- .build();
- SnippetProto snippetProto = SnippetProto.newBuilder()
- .addEntries(SnippetProto.EntryProto.newBuilder()
- .setPropertyName(propertyKeyString)
- .addSnippetMatches(SnippetMatchProto.newBuilder()
- .setValuesIndex(0)
- .setExactMatchPosition(29)
- .setExactMatchBytes(3)
- .setWindowPosition(26)
- .setWindowBytes(6)
- .build())
- .build())
- .build();
- SearchResultProto.ResultProto resultProto = SearchResultProto.ResultProto.newBuilder()
- .setDocument(documentProto)
- .setSnippet(snippetProto)
- .build();
- SearchResultProto searchResultProto = SearchResultProto.newBuilder()
- .addResults(resultProto)
- .build();
- SearchResults searchResults = new SearchResults(searchResultProto);
-
- // Making ResultReader and getting Snippet values.
- while (searchResults.hasNext()) {
- SearchResults.Result result = searchResults.next();
- MatchInfo match = result.getMatchInfo().get(0);
- assertThat(match.getPropertyPath()).isEqualTo(propertyKeyString);
- assertThat(match.getFullText()).isEqualTo(propertyValueString);
- assertThat(match.getExactMatch()).isEqualTo(exactMatch);
- assertThat(match.getSnippet()).isEqualTo(window);
- }
- }
-
- // TODO(sidchhabra): Add tests for Double and Long Snippets.
- @Test
- public void testNoSnippets() {
-
- final String propertyKeyString = "content";
- final String propertyValueString = "A commonly used fake word is foo.\n"
- + " Another nonsense word that’s used a lot\n"
- + " is bar.\n";
- final String uri = "uri1";
- final String schemaType = "schema1";
- final String searchWord = "foo";
- final String exactMatch = "foo";
- final String window = "is foo";
-
- // Building the SearchResult received from query.
- PropertyProto property = PropertyProto.newBuilder()
- .setName(propertyKeyString)
- .addStringValues(propertyValueString)
- .build();
- DocumentProto documentProto = DocumentProto.newBuilder()
- .setUri(uri)
- .setSchema(schemaType)
- .addProperties(property)
- .build();
- SearchResultProto.ResultProto resultProto = SearchResultProto.ResultProto.newBuilder()
- .setDocument(documentProto)
- .build();
- SearchResultProto searchResultProto = SearchResultProto.newBuilder()
- .addResults(resultProto)
- .build();
- SearchResults searchResults = new SearchResults(searchResultProto);
-
- while (searchResults.hasNext()) {
- SearchResults.Result result = searchResults.next();
- assertThat(result.getMatchInfo()).isEqualTo(null);
- }
- }
-
- @Test
- public void testMultipleStringSnippet() {
- final String searchWord = "Test";
-
- // Building the SearchResult received from query.
- PropertyProto property1 = PropertyProto.newBuilder()
- .setName("sender.name")
- .addStringValues("Test Name Jr.")
- .build();
- PropertyProto property2 = PropertyProto.newBuilder()
- .setName("sender.email")
- .addStringValues("TestNameJr@gmail.com")
- .build();
- DocumentProto documentProto = DocumentProto.newBuilder()
- .setUri("uri1")
- .setSchema("schema1")
- .addProperties(property1)
- .addProperties(property2)
- .build();
- SnippetProto snippetProto = SnippetProto.newBuilder()
- .addEntries(
- SnippetProto.EntryProto.newBuilder()
- .setPropertyName("sender.name")
- .addSnippetMatches(
- SnippetMatchProto.newBuilder()
- .setValuesIndex(0)
- .setExactMatchPosition(0)
- .setExactMatchBytes(4)
- .setWindowPosition(0)
- .setWindowBytes(9)
- .build())
- .build())
- .addEntries(
- SnippetProto.EntryProto.newBuilder()
- .setPropertyName("sender.email")
- .addSnippetMatches(
- SnippetMatchProto.newBuilder()
- .setValuesIndex(0)
- .setExactMatchPosition(0)
- .setExactMatchBytes(20)
- .setWindowPosition(0)
- .setWindowBytes(20)
- .build())
- .build()
- )
- .build();
- SearchResultProto.ResultProto resultProto = SearchResultProto.ResultProto.newBuilder()
- .setDocument(documentProto)
- .setSnippet(snippetProto)
- .build();
- SearchResultProto searchResultProto = SearchResultProto.newBuilder()
- .addResults(resultProto)
- .build();
- SearchResults searchResults = new SearchResults(searchResultProto);
-
- // Making ResultReader and getting Snippet values.
- while (searchResults.hasNext()) {
- SearchResults.Result result = searchResults.next();
-
- MatchInfo match1 = result.getMatchInfo().get(0);
- assertThat(match1.getPropertyPath()).isEqualTo("sender.name");
- assertThat(match1.getFullText()).isEqualTo("Test Name Jr.");
- assertThat(match1.getExactMatch()).isEqualTo("Test");
- assertThat(match1.getSnippet()).isEqualTo("Test Name");
-
- MatchInfo match2 = result.getMatchInfo().get(1);
- assertThat(match2.getPropertyPath()).isEqualTo("sender.email");
- assertThat(match2.getFullText()).isEqualTo("TestNameJr@gmail.com");
- assertThat(match2.getExactMatch()).isEqualTo("TestNameJr@gmail.com");
- assertThat(match2.getSnippet()).isEqualTo("TestNameJr@gmail.com");
- }
- }
-}
diff --git a/core/tests/coretests/src/android/app/appsearch/impl/CustomerDocumentTest.java b/core/tests/coretests/src/android/app/appsearch/impl/CustomerDocumentTest.java
deleted file mode 100644
index b29483c2e3b3..000000000000
--- a/core/tests/coretests/src/android/app/appsearch/impl/CustomerDocumentTest.java
+++ /dev/null
@@ -1,98 +0,0 @@
-/*
- * Copyright (C) 2020 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.app.appsearch.impl;
-
-import static com.google.common.truth.Truth.assertThat;
-
-import android.annotation.NonNull;
-import android.app.appsearch.AppSearchDocument;
-
-import androidx.test.filters.SmallTest;
-
-import org.junit.Test;
-
-/**
- * Tests that {@link AppSearchDocument} and {@link AppSearchDocument.Builder} are extendable by
- * developers.
- *
- * <p>This class is intentionally in a different package than {@link AppSearchDocument} to make sure
- * there are no package-private methods required for external developers to add custom types.
- */
-@SmallTest
-public class CustomerDocumentTest {
-
- private static byte[] sByteArray1 = new byte[]{(byte) 1, (byte) 2, (byte) 3};
- private static byte[] sByteArray2 = new byte[]{(byte) 4, (byte) 5, (byte) 6};
- private static AppSearchDocument sDocumentProperties1 = new AppSearchDocument
- .Builder("sDocumentProperties1", "sDocumentPropertiesSchemaType1")
- .build();
- private static AppSearchDocument sDocumentProperties2 = new AppSearchDocument
- .Builder("sDocumentProperties2", "sDocumentPropertiesSchemaType2")
- .build();
-
- @Test
- public void testBuildCustomerDocument() {
- CustomerDocument customerDocument = new CustomerDocument.Builder("uri1")
- .setScore(1)
- .setCreationTimestampMillis(0)
- .setProperty("longKey1", 1L, 2L, 3L)
- .setProperty("doubleKey1", 1.0, 2.0, 3.0)
- .setProperty("booleanKey1", true, false, true)
- .setProperty("stringKey1", "test-value1", "test-value2", "test-value3")
- .setProperty("byteKey1", sByteArray1, sByteArray2)
- .setProperty("documentKey1", sDocumentProperties1, sDocumentProperties2)
- .build();
-
- assertThat(customerDocument.getUri()).isEqualTo("uri1");
- assertThat(customerDocument.getSchemaType()).isEqualTo("customerDocument");
- assertThat(customerDocument.getScore()).isEqualTo(1);
- assertThat(customerDocument.getCreationTimestampMillis()).isEqualTo(0L);
- assertThat(customerDocument.getPropertyLongArray("longKey1")).asList()
- .containsExactly(1L, 2L, 3L);
- assertThat(customerDocument.getPropertyDoubleArray("doubleKey1")).usingExactEquality()
- .containsExactly(1.0, 2.0, 3.0);
- assertThat(customerDocument.getPropertyBooleanArray("booleanKey1")).asList()
- .containsExactly(true, false, true);
- assertThat(customerDocument.getPropertyStringArray("stringKey1")).asList()
- .containsExactly("test-value1", "test-value2", "test-value3");
- assertThat(customerDocument.getPropertyBytesArray("byteKey1")).asList()
- .containsExactly(sByteArray1, sByteArray2);
- assertThat(customerDocument.getPropertyDocumentArray("documentKey1")).asList()
- .containsExactly(sDocumentProperties1, sDocumentProperties2);
- }
-
- /**
- * An example document type for test purposes, defined outside of
- * {@link android.app.appsearch.AppSearch} (the way an external developer would define it).
- */
- private static class CustomerDocument extends AppSearchDocument {
- private CustomerDocument(AppSearchDocument document) {
- super(document);
- }
-
- public static class Builder extends AppSearchDocument.Builder<CustomerDocument.Builder> {
- private Builder(@NonNull String uri) {
- super(uri, "customerDocument");
- }
-
- @Override
- public CustomerDocument build() {
- return new CustomerDocument(super.build());
- }
- }
- }
-}
diff --git a/core/tests/coretests/src/android/content/ApexContextTest.java b/core/tests/coretests/src/android/content/ApexEnvironmentTest.java
index d15c64d0935d..438c5ae1b023 100644
--- a/core/tests/coretests/src/android/content/ApexContextTest.java
+++ b/core/tests/coretests/src/android/content/ApexEnvironmentTest.java
@@ -28,20 +28,21 @@ import org.junit.runner.RunWith;
@SmallTest
@RunWith(AndroidJUnit4.class)
-public class ApexContextTest {
+public class ApexEnvironmentTest {
@Test
public void dataDirectoryPathsAreAsExpected() {
- ApexContext apexContext = ApexContext.getApexContext("my.apex");
+ ApexEnvironment apexEnvironment = ApexEnvironment.getApexEnvironment("my.apex");
assertEquals("/data/misc/apexdata/my.apex",
- apexContext.getDeviceProtectedDataDir().getAbsolutePath());
+ apexEnvironment.getDeviceProtectedDataDir().getAbsolutePath());
assertEquals("/data/misc_de/5/apexdata/my.apex",
- apexContext.getDeviceProtectedDataDirForUser(UserHandle.of(5)).getAbsolutePath());
+ apexEnvironment
+ .getDeviceProtectedDataDirForUser(UserHandle.of(5)).getAbsolutePath());
assertEquals("/data/misc_ce/16/apexdata/my.apex",
- apexContext.getCredentialProtectedDataDirForUser(
+ apexEnvironment.getCredentialProtectedDataDirForUser(
UserHandle.of(16)).getAbsolutePath());
}
}
diff --git a/core/tests/coretests/src/android/os/EnvironmentTest.java b/core/tests/coretests/src/android/os/EnvironmentTest.java
index d98ceaf57dd9..c0325caf1425 100644
--- a/core/tests/coretests/src/android/os/EnvironmentTest.java
+++ b/core/tests/coretests/src/android/os/EnvironmentTest.java
@@ -23,7 +23,10 @@ import static android.os.Environment.HAS_OTHER;
import static android.os.Environment.classifyExternalStorageDirectory;
import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+import android.app.AppOpsManager;
import android.content.Context;
import androidx.test.InstrumentationRegistry;
@@ -40,10 +43,33 @@ import java.io.File;
public class EnvironmentTest {
private File dir;
- private Context getContext() {
+ private static Context getContext() {
return InstrumentationRegistry.getContext();
}
+ /**
+ * Sets {@code mode} for the given {@code ops} and the given {@code uid}.
+ *
+ * <p>This method drops shell permission identity.
+ */
+ private static void setAppOpsModeForUid(int uid, int mode, String... ops) {
+ if (ops == null) {
+ return;
+ }
+ InstrumentationRegistry.getInstrumentation()
+ .getUiAutomation()
+ .adoptShellPermissionIdentity();
+ try {
+ for (String op : ops) {
+ getContext().getSystemService(AppOpsManager.class).setUidMode(op, uid, mode);
+ }
+ } finally {
+ InstrumentationRegistry.getInstrumentation()
+ .getUiAutomation()
+ .dropShellPermissionIdentity();
+ }
+ }
+
@Before
public void setUp() throws Exception {
dir = getContext().getDir("testing", Context.MODE_PRIVATE);
@@ -101,4 +127,17 @@ public class EnvironmentTest {
Environment.buildPath(dir, "Taxes.pdf").createNewFile();
assertEquals(HAS_OTHER, classifyExternalStorageDirectory(dir));
}
+
+ @Test
+ public void testIsExternalStorageManager() throws Exception {
+ assertFalse(Environment.isExternalStorageManager());
+ try {
+ setAppOpsModeForUid(Process.myUid(), AppOpsManager.MODE_ALLOWED,
+ AppOpsManager.OPSTR_MANAGE_EXTERNAL_STORAGE);
+ assertTrue(Environment.isExternalStorageManager());
+ } finally {
+ setAppOpsModeForUid(Process.myUid(), AppOpsManager.MODE_DEFAULT,
+ AppOpsManager.OPSTR_MANAGE_EXTERNAL_STORAGE);
+ }
+ }
}
diff --git a/core/tests/coretests/src/android/service/controls/actions/ControlActionTest.java b/core/tests/coretests/src/android/service/controls/actions/ControlActionTest.java
index 10a7b76390ec..d8088b7735ad 100644
--- a/core/tests/coretests/src/android/service/controls/actions/ControlActionTest.java
+++ b/core/tests/coretests/src/android/service/controls/actions/ControlActionTest.java
@@ -56,16 +56,6 @@ public class ControlActionTest {
}
@Test
- public void testUnparcelingCorrectClass_multiFloat() {
- ControlAction toParcel = new MultiFloatAction(TEST_ID, new float[] {0f, 1f});
-
- ControlAction fromParcel = parcelAndUnparcel(toParcel);
-
- assertEquals(ControlAction.TYPE_MULTI_FLOAT, fromParcel.getActionType());
- assertTrue(fromParcel instanceof MultiFloatAction);
- }
-
- @Test
public void testUnparcelingCorrectClass_mode() {
ControlAction toParcel = new ModeAction(TEST_ID, 1);
diff --git a/core/tests/coretests/src/android/service/controls/templates/ControlTemplateTest.java b/core/tests/coretests/src/android/service/controls/templates/ControlTemplateTest.java
index 292ac0928f1d..87dc1b7c83d5 100644
--- a/core/tests/coretests/src/android/service/controls/templates/ControlTemplateTest.java
+++ b/core/tests/coretests/src/android/service/controls/templates/ControlTemplateTest.java
@@ -103,16 +103,6 @@ public class ControlTemplateTest {
}
@Test
- public void testUnparcelingCorrectClass_thumbnail() {
- ControlTemplate toParcel = new ThumbnailTemplate(TEST_ID, mIcon, TEST_ACTION_DESCRIPTION);
-
- ControlTemplate fromParcel = parcelAndUnparcel(toParcel);
-
- assertEquals(ControlTemplate.TYPE_THUMBNAIL, fromParcel.getTemplateType());
- assertTrue(fromParcel instanceof ThumbnailTemplate);
- }
-
- @Test
public void testUnparcelingCorrectClass_toggleRange() {
ControlTemplate toParcel = new ToggleRangeTemplate(TEST_ID, mControlButton,
new RangeTemplate(TEST_ID, 0, 2, 1, 1, "%f"));
diff --git a/core/tests/coretests/src/android/widget/EditorCursorDragTest.java b/core/tests/coretests/src/android/widget/EditorCursorDragTest.java
index 0a094c61d4d5..f81964c9cdf9 100644
--- a/core/tests/coretests/src/android/widget/EditorCursorDragTest.java
+++ b/core/tests/coretests/src/android/widget/EditorCursorDragTest.java
@@ -35,10 +35,13 @@ import static org.junit.Assert.assertTrue;
import android.app.Activity;
import android.app.Instrumentation;
+import android.graphics.Rect;
import android.text.Layout;
+import android.util.ArraySet;
import android.util.Log;
import android.view.InputDevice;
import android.view.MotionEvent;
+import android.view.View;
import androidx.test.InstrumentationRegistry;
import androidx.test.filters.SmallTest;
@@ -50,11 +53,13 @@ import com.android.frameworks.coretests.R;
import com.google.common.base.Strings;
+import org.junit.After;
import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;
+import java.util.Set;
import java.util.concurrent.atomic.AtomicLong;
@RunWith(AndroidJUnit4.class)
@@ -70,6 +75,7 @@ public class EditorCursorDragTest {
private Instrumentation mInstrumentation;
private Activity mActivity;
+ private Set<MotionEvent> mMotionEvents = new ArraySet<>();
@Before
public void before() throws Throwable {
@@ -77,6 +83,14 @@ public class EditorCursorDragTest {
mActivity = mActivityRule.getActivity();
}
+ @After
+ public void after() throws Throwable {
+ for (MotionEvent event : mMotionEvents) {
+ event.recycle();
+ }
+ mMotionEvents.clear();
+ }
+
@Test
public void testCursorDrag_horizontal_whenTextViewContentsFitOnScreen() throws Throwable {
String text = "Hello world!";
@@ -243,45 +257,45 @@ public class EditorCursorDragTest {
// Simulate a tap-and-drag gesture.
long event1Time = 1001;
- MotionEvent event1 = downEvent(event1Time, event1Time, 5f, 10f);
+ MotionEvent event1 = downEvent(tv, event1Time, event1Time, 5f, 10f);
mInstrumentation.runOnMainSync(() -> editor.onTouchEvent(event1));
assertFalse(editor.getInsertionController().isCursorBeingModified());
assertFalse(editor.getSelectionController().isCursorBeingModified());
long event2Time = 1002;
- MotionEvent event2 = moveEvent(event1Time, event2Time, 50f, 10f);
+ MotionEvent event2 = moveEvent(tv, event1Time, event2Time, 50f, 10f);
mInstrumentation.runOnMainSync(() -> editor.onTouchEvent(event2));
assertTrue(editor.getInsertionController().isCursorBeingModified());
assertFalse(editor.getSelectionController().isCursorBeingModified());
long event3Time = 1003;
- MotionEvent event3 = moveEvent(event1Time, event3Time, 100f, 10f);
+ MotionEvent event3 = moveEvent(tv, event1Time, event3Time, 100f, 10f);
mInstrumentation.runOnMainSync(() -> editor.onTouchEvent(event3));
assertTrue(editor.getInsertionController().isCursorBeingModified());
assertFalse(editor.getSelectionController().isCursorBeingModified());
long event4Time = 2004;
- MotionEvent event4 = upEvent(event1Time, event4Time, 100f, 10f);
+ MotionEvent event4 = upEvent(tv, event1Time, event4Time, 100f, 10f);
mInstrumentation.runOnMainSync(() -> editor.onTouchEvent(event4));
assertFalse(editor.getInsertionController().isCursorBeingModified());
assertFalse(editor.getSelectionController().isCursorBeingModified());
// Simulate a quick tap after the drag, near the location where the drag ended.
long event5Time = 2005;
- MotionEvent event5 = downEvent(event5Time, event5Time, 90f, 10f);
+ MotionEvent event5 = downEvent(tv, event5Time, event5Time, 90f, 10f);
mInstrumentation.runOnMainSync(() -> editor.onTouchEvent(event5));
assertFalse(editor.getInsertionController().isCursorBeingModified());
assertFalse(editor.getSelectionController().isCursorBeingModified());
long event6Time = 2006;
- MotionEvent event6 = upEvent(event5Time, event6Time, 90f, 10f);
+ MotionEvent event6 = upEvent(tv, event5Time, event6Time, 90f, 10f);
mInstrumentation.runOnMainSync(() -> editor.onTouchEvent(event6));
assertFalse(editor.getInsertionController().isCursorBeingModified());
assertFalse(editor.getSelectionController().isCursorBeingModified());
// Simulate another quick tap in the same location; now selection should be triggered.
long event7Time = 2007;
- MotionEvent event7 = downEvent(event7Time, event7Time, 90f, 10f);
+ MotionEvent event7 = downEvent(tv, event7Time, event7Time, 90f, 10f);
mInstrumentation.runOnMainSync(() -> editor.onTouchEvent(event7));
assertFalse(editor.getInsertionController().isCursorBeingModified());
assertTrue(editor.getSelectionController().isCursorBeingModified());
@@ -298,19 +312,19 @@ public class EditorCursorDragTest {
// Simulate a mouse click and drag. This should NOT trigger a cursor drag.
long event1Time = 1001;
- MotionEvent event1 = mouseDownEvent(event1Time, event1Time, 20f, 30f);
+ MotionEvent event1 = mouseDownEvent(tv, event1Time, event1Time, 20f, 30f);
mInstrumentation.runOnMainSync(() -> editor.onTouchEvent(event1));
assertFalse(editor.getInsertionController().isCursorBeingModified());
assertFalse(editor.getSelectionController().isCursorBeingModified());
long event2Time = 1002;
- MotionEvent event2 = mouseMoveEvent(event1Time, event2Time, 120f, 30f);
+ MotionEvent event2 = mouseMoveEvent(tv, event1Time, event2Time, 120f, 30f);
mInstrumentation.runOnMainSync(() -> editor.onTouchEvent(event2));
assertFalse(editor.getInsertionController().isCursorBeingModified());
assertTrue(editor.getSelectionController().isCursorBeingModified());
long event3Time = 1003;
- MotionEvent event3 = mouseUpEvent(event1Time, event3Time, 120f, 30f);
+ MotionEvent event3 = mouseUpEvent(tv, event1Time, event3Time, 120f, 30f);
mInstrumentation.runOnMainSync(() -> editor.onTouchEvent(event3));
assertFalse(editor.getInsertionController().isCursorBeingModified());
assertFalse(editor.getSelectionController().isCursorBeingModified());
@@ -327,25 +341,25 @@ public class EditorCursorDragTest {
// Simulate a tap-and-drag gesture. This should trigger a cursor drag.
long event1Time = 1001;
- MotionEvent event1 = downEvent(event1Time, event1Time, 20f, 30f);
+ MotionEvent event1 = downEvent(tv, event1Time, event1Time, 20f, 30f);
mInstrumentation.runOnMainSync(() -> editor.onTouchEvent(event1));
assertFalse(editor.getInsertionController().isCursorBeingModified());
assertFalse(editor.getSelectionController().isCursorBeingModified());
long event2Time = 1002;
- MotionEvent event2 = moveEvent(event1Time, event2Time, 21f, 30f);
+ MotionEvent event2 = moveEvent(tv, event1Time, event2Time, 21f, 30f);
mInstrumentation.runOnMainSync(() -> editor.onTouchEvent(event2));
assertFalse(editor.getInsertionController().isCursorBeingModified());
assertFalse(editor.getSelectionController().isCursorBeingModified());
long event3Time = 1003;
- MotionEvent event3 = moveEvent(event1Time, event3Time, 120f, 30f);
+ MotionEvent event3 = moveEvent(tv, event1Time, event3Time, 120f, 30f);
mInstrumentation.runOnMainSync(() -> editor.onTouchEvent(event3));
assertTrue(editor.getInsertionController().isCursorBeingModified());
assertFalse(editor.getSelectionController().isCursorBeingModified());
long event4Time = 1004;
- MotionEvent event4 = upEvent(event1Time, event4Time, 120f, 30f);
+ MotionEvent event4 = upEvent(tv, event1Time, event4Time, 120f, 30f);
mInstrumentation.runOnMainSync(() -> editor.onTouchEvent(event4));
assertFalse(editor.getInsertionController().isCursorBeingModified());
assertFalse(editor.getSelectionController().isCursorBeingModified());
@@ -362,31 +376,31 @@ public class EditorCursorDragTest {
// Simulate a double-tap followed by a drag. This should trigger a selection drag.
long event1Time = 1001;
- MotionEvent event1 = downEvent(event1Time, event1Time, 20f, 30f);
+ MotionEvent event1 = downEvent(tv, event1Time, event1Time, 20f, 30f);
mInstrumentation.runOnMainSync(() -> editor.onTouchEvent(event1));
assertFalse(editor.getInsertionController().isCursorBeingModified());
assertFalse(editor.getSelectionController().isCursorBeingModified());
long event2Time = 1002;
- MotionEvent event2 = upEvent(event1Time, event2Time, 20f, 30f);
+ MotionEvent event2 = upEvent(tv, event1Time, event2Time, 20f, 30f);
mInstrumentation.runOnMainSync(() -> editor.onTouchEvent(event2));
assertFalse(editor.getInsertionController().isCursorBeingModified());
assertFalse(editor.getSelectionController().isCursorBeingModified());
long event3Time = 1003;
- MotionEvent event3 = downEvent(event3Time, event3Time, 20f, 30f);
+ MotionEvent event3 = downEvent(tv, event3Time, event3Time, 20f, 30f);
mInstrumentation.runOnMainSync(() -> editor.onTouchEvent(event3));
assertFalse(editor.getInsertionController().isCursorBeingModified());
assertTrue(editor.getSelectionController().isCursorBeingModified());
long event4Time = 1004;
- MotionEvent event4 = moveEvent(event3Time, event4Time, 120f, 30f);
+ MotionEvent event4 = moveEvent(tv, event3Time, event4Time, 120f, 30f);
mInstrumentation.runOnMainSync(() -> editor.onTouchEvent(event4));
assertFalse(editor.getInsertionController().isCursorBeingModified());
assertTrue(editor.getSelectionController().isCursorBeingModified());
long event5Time = 1005;
- MotionEvent event5 = upEvent(event3Time, event5Time, 120f, 30f);
+ MotionEvent event5 = upEvent(tv, event3Time, event5Time, 120f, 30f);
mInstrumentation.runOnMainSync(() -> editor.onTouchEvent(event5));
assertFalse(editor.getInsertionController().isCursorBeingModified());
assertFalse(editor.getSelectionController().isCursorBeingModified());
@@ -403,7 +417,7 @@ public class EditorCursorDragTest {
// Simulate a tap. No error should be thrown.
long event1Time = 1001;
- MotionEvent event1 = downEvent(event1Time, event1Time, 20f, 30f);
+ MotionEvent event1 = downEvent(tv, event1Time, event1Time, 20f, 30f);
mInstrumentation.runOnMainSync(() -> editor.onTouchEvent(event1));
// Swipe left to right. No error should be thrown.
@@ -440,7 +454,8 @@ public class EditorCursorDragTest {
public void testCursorDrag_snapToHandle() throws Throwable {
String text = "line1: This is the 1st line: A\n"
+ "line2: This is the 2nd line: B\n"
- + "line3: This is the 3rd line: C\n";
+ + "line3: This is the 3rd line: C\n"
+ + "line4: This is the 4th line: D\n";
onView(withId(R.id.textview)).perform(replaceText(text));
onView(withId(R.id.textview)).check(hasInsertionPointerAtIndex(0));
TextView tv = mActivity.findViewById(R.id.textview);
@@ -454,8 +469,8 @@ public class EditorCursorDragTest {
// Start dragging along the first line
motionEventInfo(text.indexOf("line1"), 1.0f),
motionEventInfo(text.indexOf("This is the 1st"), 1.0f),
- // Move to the bottom of the third line; cursor should end up on second line
- motionEventInfo(text.indexOf("he 3rd"), 0.0f, text.indexOf("he 2nd")),
+ // Move to the middle of the fourth line; cursor should end up on second line
+ motionEventInfo(text.indexOf("he 4th"), 0.5f, text.indexOf("he 2nd")),
// Move to the middle of the second line; cursor should end up on the first line
motionEventInfo(text.indexOf("he 2nd"), 0.5f, text.indexOf("he 1st"))
};
@@ -473,39 +488,139 @@ public class EditorCursorDragTest {
simulateDrag(tv, events, true);
}
- private static MotionEvent downEvent(long downTime, long eventTime, float x, float y) {
- return MotionEvent.obtain(downTime, eventTime, MotionEvent.ACTION_DOWN, x, y, 0);
+ @Test
+ public void testCursorDrag_snapDistance() throws Throwable {
+ String text = "line1: This is the 1st line: A\n"
+ + "line2: This is the 2nd line: B\n"
+ + "line3: This is the 3rd line: C\n";
+ onView(withId(R.id.textview)).perform(replaceText(text));
+ TextView tv = mActivity.findViewById(R.id.textview);
+ Editor editor = tv.getEditorForTesting();
+ final int startIndex = text.indexOf("he 2nd");
+ Layout layout = tv.getLayout();
+ final float cursorStartX = layout.getPrimaryHorizontal(startIndex) + tv.getTotalPaddingLeft();
+ final float cursorStartY = layout.getLineTop(1) + tv.getTotalPaddingTop();
+ final float dragHandleStartX = 20;
+ final float dragHandleStartY = 20;
+
+ // Drag the handle from the 2nd line to the 3rd line.
+ tapAtPoint(tv, cursorStartX, cursorStartY);
+ onView(withId(R.id.textview)).check(hasInsertionPointerAtIndex(startIndex));
+ View handleView = editor.getInsertionController().getHandle();
+ final int rawYOfHandleDrag = dragDownUntilLineChange(
+ handleView, dragHandleStartX, dragHandleStartY, tv.getSelectionStart());
+
+ // Drag the cursor from the 2nd line to the 3rd line.
+ tapAtPoint(tv, cursorStartX, cursorStartY);
+ onView(withId(R.id.textview)).check(hasInsertionPointerAtIndex(startIndex));
+ final int rawYOfCursorDrag =
+ dragDownUntilLineChange(tv, cursorStartX, cursorStartY, tv.getSelectionStart());
+
+ // Drag the handle with touch through from the 2nd line to the 3rd line.
+ tv.getEditorForTesting().setFlagInsertionHandleGesturesEnabled(true);
+ tapAtPoint(tv, cursorStartX, cursorStartY);
+ onView(withId(R.id.textview)).check(hasInsertionPointerAtIndex(startIndex));
+ handleView = editor.getInsertionController().getHandle();
+ int rawYOfHandleDragWithTouchThrough =
+ dragDownUntilLineChange(handleView, dragHandleStartX, dragHandleStartY, tv.getSelectionStart());
+
+ String msg = String.format(
+ "rawYOfHandleDrag: %d, rawYOfCursorDrag: %d, rawYOfHandleDragWithTouchThrough: %d",
+ rawYOfHandleDrag, rawYOfCursorDrag, rawYOfHandleDragWithTouchThrough);
+ final int max = Math.max(
+ rawYOfCursorDrag, Math.max(rawYOfHandleDrag, rawYOfHandleDragWithTouchThrough));
+ final int min = Math.min(
+ rawYOfCursorDrag, Math.min(rawYOfHandleDrag, rawYOfHandleDragWithTouchThrough));
+ // The drag step is 5 pixels in dragDownUntilLineChange().
+ // The difference among the 3 raw Y values should be no bigger than the drag step.
+ assertWithMessage(msg).that(max - min).isLessThan(6);
}
- private static MotionEvent upEvent(long downTime, long eventTime, float x, float y) {
- return MotionEvent.obtain(downTime, eventTime, MotionEvent.ACTION_UP, x, y, 0);
+ private void dispatchTouchEvent(View view, MotionEvent event) {
+ mInstrumentation.runOnMainSync(() -> view.dispatchTouchEvent(event));
}
- private static MotionEvent moveEvent(long downTime, long eventTime, float x, float y) {
- return MotionEvent.obtain(downTime, eventTime, MotionEvent.ACTION_MOVE, x, y, 0);
+ private void tapAtPoint(TextView tv, final float x, final float y) {
+ long downTime = sTicker.addAndGet(10_000);
+ dispatchTouchEvent(tv, downEvent(tv, downTime, downTime, x, y));
+ dispatchTouchEvent(tv, upEvent(tv, downTime, downTime + 1, x, y));
}
- private static MotionEvent mouseDownEvent(long downTime, long eventTime, float x, float y) {
- MotionEvent event = downEvent(downTime, eventTime, x, y);
- event.setSource(InputDevice.SOURCE_MOUSE);
- event.setButtonState(MotionEvent.BUTTON_PRIMARY);
- return event;
+ private int dragDownUntilLineChange(View view, final float startX, final float startY,
+ final int startOffset) {
+ TextView tv = mActivity.findViewById(R.id.textview);
+ final int startLine = tv.getLayout().getLineForOffset(startOffset);
+
+ int rawY = 0;
+ long downTime = sTicker.addAndGet(10_000);
+ long eventTime = downTime;
+ // Move horizontally first to initiate the cursor drag.
+ dispatchTouchEvent(view, downEvent(view, downTime, eventTime++, startX, startY));
+ dispatchTouchEvent(view, moveEvent(view, downTime, eventTime++, startX + 50, startY));
+ dispatchTouchEvent(view, moveEvent(view, downTime, eventTime++, startX, startY));
+ // Move downwards 5 pixels at a time until a line change occurs.
+ for (int i = 0; i < 200; i++) {
+ MotionEvent ev = moveEvent(view, downTime, eventTime++, startX, startY + i * 5);
+ rawY = (int) ev.getRawY();
+ dispatchTouchEvent(view, ev);
+ if (tv.getLayout().getLineForOffset(tv.getSelectionStart()) > startLine) {
+ break;
+ }
+ }
+ String msg = String.format("The cursor didn't jump from %d!", startOffset);
+ assertWithMessage(msg).that(
+ tv.getLayout().getLineForOffset(tv.getSelectionStart())).isGreaterThan(startLine);
+ dispatchTouchEvent(view, upEvent(view, downTime, eventTime, startX, startY));
+ return rawY;
}
- private static MotionEvent mouseUpEvent(long downTime, long eventTime, float x, float y) {
- MotionEvent event = upEvent(downTime, eventTime, x, y);
- event.setSource(InputDevice.SOURCE_MOUSE);
- event.setButtonState(0);
+ private MotionEvent obtainTouchEvent(
+ View view, int action, long downTime, long eventTime, float x, float y) {
+ Rect r = new Rect();
+ view.getBoundsOnScreen(r);
+ float rawX = x + r.left;
+ float rawY = y + r.top;
+ MotionEvent event =
+ MotionEvent.obtain(downTime, eventTime, action, rawX, rawY, 0);
+ view.toLocalMotionEvent(event);
+ mMotionEvents.add(event);
return event;
}
- private static MotionEvent mouseMoveEvent(long downTime, long eventTime, float x, float y) {
- MotionEvent event = moveEvent(downTime, eventTime, x, y);
+ private MotionEvent obtainMouseEvent(
+ View view, int action, long downTime, long eventTime, float x, float y) {
+ MotionEvent event = obtainTouchEvent(view, action, downTime, eventTime, x, y);
event.setSource(InputDevice.SOURCE_MOUSE);
- event.setButtonState(MotionEvent.BUTTON_PRIMARY);
+ if (action != MotionEvent.ACTION_UP) {
+ event.setButtonState(MotionEvent.BUTTON_PRIMARY);
+ }
return event;
}
+ private MotionEvent downEvent(View view, long downTime, long eventTime, float x, float y) {
+ return obtainTouchEvent(view, MotionEvent.ACTION_DOWN, downTime, eventTime, x, y);
+ }
+
+ private MotionEvent moveEvent(View view, long downTime, long eventTime, float x, float y) {
+ return obtainTouchEvent(view, MotionEvent.ACTION_MOVE, downTime, eventTime, x, y);
+ }
+
+ private MotionEvent upEvent(View view, long downTime, long eventTime, float x, float y) {
+ return obtainTouchEvent(view, MotionEvent.ACTION_UP, downTime, eventTime, x, y);
+ }
+
+ private MotionEvent mouseDownEvent(View view, long downTime, long eventTime, float x, float y) {
+ return obtainMouseEvent(view, MotionEvent.ACTION_DOWN, downTime, eventTime, x, y);
+ }
+
+ private MotionEvent mouseMoveEvent(View view, long downTime, long eventTime, float x, float y) {
+ return obtainMouseEvent(view, MotionEvent.ACTION_MOVE, downTime, eventTime, x, y);
+ }
+
+ private MotionEvent mouseUpEvent(View view, long downTime, long eventTime, float x, float y) {
+ return obtainMouseEvent(view, MotionEvent.ACTION_UP, downTime, eventTime, x, y);
+ }
+
public static MotionEventInfo motionEventInfo(int index, float ratioToLineTop) {
return new MotionEventInfo(index, ratioToLineTop, index);
}
@@ -543,14 +658,15 @@ public class EditorCursorDragTest {
float[] downCoords = events[0].getCoordinates(tv);
long downEventTime = sTicker.addAndGet(10_000);
- MotionEvent downEvent = downEvent(downEventTime, downEventTime,
+ MotionEvent downEvent = downEvent(tv, downEventTime, downEventTime,
downCoords[0], downCoords[1]);
mInstrumentation.runOnMainSync(() -> editor.onTouchEvent(downEvent));
for (int i = 1; i < events.length; i++) {
float[] moveCoords = events[i].getCoordinates(tv);
long eventTime = downEventTime + i;
- MotionEvent event = moveEvent(downEventTime, eventTime, moveCoords[0], moveCoords[1]);
+ MotionEvent event = moveEvent(tv, downEventTime, eventTime, moveCoords[0],
+ moveCoords[1]);
mInstrumentation.runOnMainSync(() -> editor.onTouchEvent(event));
assertCursorPosition(tv, events[i].expectedCursorIndex, runAssertions);
}
@@ -558,7 +674,7 @@ public class EditorCursorDragTest {
MotionEventInfo lastEvent = events[events.length - 1];
float[] upCoords = lastEvent.getCoordinates(tv);
long upEventTime = downEventTime + events.length;
- MotionEvent upEvent = upEvent(downEventTime, upEventTime, upCoords[0], upCoords[1]);
+ MotionEvent upEvent = upEvent(tv, downEventTime, upEventTime, upCoords[0], upCoords[1]);
mInstrumentation.runOnMainSync(() -> editor.onTouchEvent(upEvent));
}
diff --git a/core/tests/coretests/src/android/widget/TextViewActivityTest.java b/core/tests/coretests/src/android/widget/TextViewActivityTest.java
index 88a6f9e4af4b..a72be25fedb5 100644
--- a/core/tests/coretests/src/android/widget/TextViewActivityTest.java
+++ b/core/tests/coretests/src/android/widget/TextViewActivityTest.java
@@ -497,7 +497,7 @@ public class TextViewActivityTest {
@Test
public void testInsertionHandle_multiLine() {
- final String text = "abcd\n" + "efg\n" + "hijk\n";
+ final String text = "abcd\n" + "efg\n" + "hijk\n" + "lmn\n";
onView(withId(R.id.textview)).perform(replaceText(text));
onView(withId(R.id.textview)).perform(clickOnTextAtIndex(text.length()));
@@ -506,12 +506,12 @@ public class TextViewActivityTest {
final TextView textView = mActivity.findViewById(R.id.textview);
onHandleView(com.android.internal.R.id.insertion_handle)
- .perform(dragHandle(textView, Handle.INSERTION, text.indexOf('a')));
- onView(withId(R.id.textview)).check(hasInsertionPointerAtIndex(text.indexOf("a")));
-
- onHandleView(com.android.internal.R.id.insertion_handle)
.perform(dragHandle(textView, Handle.INSERTION, text.indexOf('f')));
onView(withId(R.id.textview)).check(hasInsertionPointerAtIndex(text.indexOf("f")));
+
+ onHandleView(com.android.internal.R.id.insertion_handle)
+ .perform(dragHandle(textView, Handle.INSERTION, text.indexOf('i')));
+ onView(withId(R.id.textview)).check(hasInsertionPointerAtIndex(text.indexOf("i")));
}
private void enableFlagsForInsertionHandleGestures() {
diff --git a/core/tests/coretests/src/com/android/internal/app/ChooserActivityTest.java b/core/tests/coretests/src/com/android/internal/app/ChooserActivityTest.java
index 6d0e58bc89be..24e96d4b8463 100644
--- a/core/tests/coretests/src/com/android/internal/app/ChooserActivityTest.java
+++ b/core/tests/coretests/src/com/android/internal/app/ChooserActivityTest.java
@@ -1340,7 +1340,7 @@ public class ChooserActivityTest {
onView(withText(R.string.resolver_work_tab)).perform(click());
waitForIdle();
- onView(withText(R.string.resolver_turn_on_work_apps))
+ onView(withText(R.string.resolver_turn_on_work_apps_share))
.check(matches(isDisplayed()));
}
diff --git a/core/tests/coretests/src/com/android/internal/app/ResolverActivityTest.java b/core/tests/coretests/src/com/android/internal/app/ResolverActivityTest.java
index a7bf48858e42..9d1ca615e54b 100644
--- a/core/tests/coretests/src/com/android/internal/app/ResolverActivityTest.java
+++ b/core/tests/coretests/src/com/android/internal/app/ResolverActivityTest.java
@@ -624,7 +624,7 @@ public class ResolverActivityTest {
onView(withText(R.string.resolver_work_tab)).perform(click());
waitForIdle();
- onView(withText(R.string.resolver_turn_on_work_apps))
+ onView(withText(R.string.resolver_turn_on_work_apps_view))
.check(matches(isDisplayed()));
}
diff --git a/data/etc/com.android.systemui.xml b/data/etc/com.android.systemui.xml
index 5d2e303b921e..38e18a941905 100644
--- a/data/etc/com.android.systemui.xml
+++ b/data/etc/com.android.systemui.xml
@@ -39,6 +39,7 @@
<permission name="android.permission.MOUNT_UNMOUNT_FILESYSTEMS"/>
<permission name="android.permission.OBSERVE_NETWORK_POLICY"/>
<permission name="android.permission.OVERRIDE_WIFI_CONFIG"/>
+ <permission name="android.permission.PACKAGE_USAGE_STATS" />
<permission name="android.permission.READ_DREAM_STATE"/>
<permission name="android.permission.READ_FRAME_BUFFER"/>
<permission name="android.permission.READ_NETWORK_USAGE_HISTORY"/>
diff --git a/data/etc/privapp-permissions-platform.xml b/data/etc/privapp-permissions-platform.xml
index afa58d5a9c82..49edcf7aa347 100644
--- a/data/etc/privapp-permissions-platform.xml
+++ b/data/etc/privapp-permissions-platform.xml
@@ -195,6 +195,7 @@ applications that come with the platform
<permission name="android.permission.GET_ACCOUNTS_PRIVILEGED"/>
<permission name="android.permission.INTERACT_ACROSS_USERS"/>
<permission name="android.permission.MANAGE_USERS"/>
+ <permission name="android.permission.READ_PRIVILEGED_PHONE_STATE"/>
<permission name="android.permission.UPDATE_APP_OPS_STATS"/>
<permission name="android.permission.USE_RESERVED_DISK"/>
</privapp-permissions>
diff --git a/identity/java/android/security/identity/CredstoreResultData.java b/identity/java/android/security/identity/CredstoreResultData.java
index ef7afca6b888..2ef735eec81d 100644
--- a/identity/java/android/security/identity/CredstoreResultData.java
+++ b/identity/java/android/security/identity/CredstoreResultData.java
@@ -66,7 +66,7 @@ class CredstoreResultData extends ResultData {
}
@Override
- public @NonNull Collection<String> getNamespaceNames() {
+ public @NonNull Collection<String> getNamespaces() {
return Collections.unmodifiableCollection(mData.keySet());
}
diff --git a/identity/java/android/security/identity/CredstoreWritableIdentityCredential.java b/identity/java/android/security/identity/CredstoreWritableIdentityCredential.java
index 335636cb07ae..725e3d8e429a 100644
--- a/identity/java/android/security/identity/CredstoreWritableIdentityCredential.java
+++ b/identity/java/android/security/identity/CredstoreWritableIdentityCredential.java
@@ -105,11 +105,11 @@ class CredstoreWritableIdentityCredential extends WritableIdentityCredential {
n++;
}
- Collection<String> namespaceNames = personalizationData.getNamespaceNames();
+ Collection<String> namespaces = personalizationData.getNamespaces();
- EntryNamespaceParcel[] ensParcels = new EntryNamespaceParcel[namespaceNames.size()];
+ EntryNamespaceParcel[] ensParcels = new EntryNamespaceParcel[namespaces.size()];
n = 0;
- for (String namespaceName : namespaceNames) {
+ for (String namespaceName : namespaces) {
PersonalizationData.NamespaceData nsd =
personalizationData.getNamespaceData(namespaceName);
diff --git a/identity/java/android/security/identity/IdentityCredential.java b/identity/java/android/security/identity/IdentityCredential.java
index bd439199f914..1db2f6357308 100644
--- a/identity/java/android/security/identity/IdentityCredential.java
+++ b/identity/java/android/security/identity/IdentityCredential.java
@@ -209,6 +209,11 @@ public abstract class IdentityCredential {
* <p>Note that only items referenced in {@code entriesToRequest} are returned - the
* {@code requestMessage} parameter is only used to for enforcing reader authentication.
*
+ * <p>The reason for having {@code requestMessage} and {@code entriesToRequest} as separate
+ * parameters is that the former represents a request from the remote verifier device
+ * (optionally signed) and this allows the application to filter the request to not include
+ * data elements which the user has not consented to sharing.
+ *
* @param requestMessage If not {@code null}, must contain CBOR data conforming to
* the schema mentioned above.
* @param entriesToRequest The entries to request, organized as a map of namespace
diff --git a/identity/java/android/security/identity/PersonalizationData.java b/identity/java/android/security/identity/PersonalizationData.java
index 44370a1780f8..b34f2505a6a6 100644
--- a/identity/java/android/security/identity/PersonalizationData.java
+++ b/identity/java/android/security/identity/PersonalizationData.java
@@ -46,7 +46,7 @@ public class PersonalizationData {
return Collections.unmodifiableCollection(mProfiles);
}
- Collection<String> getNamespaceNames() {
+ Collection<String> getNamespaces() {
return Collections.unmodifiableCollection(mNamespaces.keySet());
}
@@ -120,7 +120,7 @@ public class PersonalizationData {
* @param value The value to add, in CBOR encoding.
* @return The builder.
*/
- public @NonNull Builder setEntry(@NonNull String namespace, @NonNull String name,
+ public @NonNull Builder putEntry(@NonNull String namespace, @NonNull String name,
@NonNull Collection<AccessControlProfileId> accessControlProfileIds,
@NonNull byte[] value) {
NamespaceData namespaceData = mData.mNamespaces.get(namespace);
diff --git a/identity/java/android/security/identity/ResultData.java b/identity/java/android/security/identity/ResultData.java
index 0982c8a4ab31..13552d619e05 100644
--- a/identity/java/android/security/identity/ResultData.java
+++ b/identity/java/android/security/identity/ResultData.java
@@ -152,7 +152,7 @@ public abstract class ResultData {
* @return collection of name of namespaces containing retrieved entries. May be empty if no
* data was retrieved.
*/
- public abstract @NonNull Collection<String> getNamespaceNames();
+ public abstract @NonNull Collection<String> getNamespaces();
/**
* Get the names of all entries.
@@ -196,8 +196,7 @@ public abstract class ResultData {
* @param name the name of the entry to get the value for.
* @return the status indicating whether the value was retrieved and if not, why.
*/
- @Status
- public abstract int getStatus(@NonNull String namespaceName, @NonNull String name);
+ public abstract @Status int getStatus(@NonNull String namespaceName, @NonNull String name);
/**
* Gets the raw CBOR data for the value of an entry.
diff --git a/keystore/java/android/security/keystore/KeyGenParameterSpec.java b/keystore/java/android/security/keystore/KeyGenParameterSpec.java
index d683041fbfdc..d9d2eea3536e 100644
--- a/keystore/java/android/security/keystore/KeyGenParameterSpec.java
+++ b/keystore/java/android/security/keystore/KeyGenParameterSpec.java
@@ -1264,8 +1264,7 @@ public final class KeyGenParameterSpec implements AlgorithmParameterSpec, UserAu
* successfully.
*
* @param timeout duration in seconds or {@code 0} if user authentication must take place
- * for every use of the key. {@code -1} is also accepted for legacy purposes. It is
- * functionally the same as {@code 0}.
+ * for every use of the key.
* @param type set of authentication types which can authorize use of the key. See
* {@link KeyProperties}.{@code AUTH} flags.
*
@@ -1275,12 +1274,10 @@ public final class KeyGenParameterSpec implements AlgorithmParameterSpec, UserAu
* @see KeyguardManager
*/
@NonNull
- public Builder setUserAuthenticationParameters(@IntRange(from = -1) int timeout,
+ public Builder setUserAuthenticationParameters(@IntRange(from = 0) int timeout,
@KeyProperties.AuthEnum int type) {
- if (timeout < -1) {
- throw new IllegalArgumentException("timeout must be -1 or larger");
- } else if (timeout == -1) {
- timeout = 0;
+ if (timeout < 0) {
+ throw new IllegalArgumentException("timeout must be 0 or larger");
}
mUserAuthenticationValidityDurationSeconds = timeout;
mUserAuthenticationType = type;
diff --git a/keystore/java/android/security/keystore/KeyProtection.java b/keystore/java/android/security/keystore/KeyProtection.java
index e230b7c3708b..8120a93e30e9 100644
--- a/keystore/java/android/security/keystore/KeyProtection.java
+++ b/keystore/java/android/security/keystore/KeyProtection.java
@@ -894,8 +894,7 @@ public final class KeyProtection implements ProtectionParameter, UserAuthArgs {
* successfully.
*
* @param timeout duration in seconds or {@code 0} if user authentication must take place
- * for every use of the key. {@code -1} is also accepted for legacy purposes. It is
- * functionally the same as {@code 0}.
+ * for every use of the key.
* @param type set of authentication types which can authorize use of the key. See
* {@link KeyProperties}.{@code AUTH} flags.
*
@@ -905,12 +904,10 @@ public final class KeyProtection implements ProtectionParameter, UserAuthArgs {
* @see KeyguardManager
*/
@NonNull
- public Builder setUserAuthenticationParameters(@IntRange(from = -1) int timeout,
+ public Builder setUserAuthenticationParameters(@IntRange(from = 0) int timeout,
@KeyProperties.AuthEnum int type) {
- if (timeout < -1) {
- throw new IllegalArgumentException("timeout must be -1 or larger");
- } else if (timeout == -1) {
- timeout = 0;
+ if (timeout < 0) {
+ throw new IllegalArgumentException("timeout must be 0 or larger");
}
mUserAuthenticationValidityDurationSeconds = timeout;
mUserAuthenticationType = type;
diff --git a/libs/WindowManager/Jetpack/Android.bp b/libs/WindowManager/Jetpack/Android.bp
new file mode 100644
index 000000000000..308c1a59a7aa
--- /dev/null
+++ b/libs/WindowManager/Jetpack/Android.bp
@@ -0,0 +1,38 @@
+// Copyright (C) 2020 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+android_library_import {
+ name: "window-extensions",
+ aars: ["window-extensions-release.aar"],
+ sdk_version: "current",
+}
+
+java_library {
+ name: "androidx.window.extensions",
+ srcs: ["src/**/*.java"],
+ static_libs: ["window-extensions"],
+ installable: true,
+ sdk_version: "core_platform",
+ vendor: true,
+ libs: ["framework", "androidx.annotation_annotation",],
+ required: ["androidx.window.extensions.xml",],
+}
+
+prebuilt_etc {
+ name: "androidx.window.extensions.xml",
+ vendor: true,
+ sub_dir: "permissions",
+ src: "androidx.window.extensions.xml",
+ filename_from_src: true,
+}
diff --git a/libs/WindowManager/Jetpack/androidx.window.extensions.xml b/libs/WindowManager/Jetpack/androidx.window.extensions.xml
new file mode 100644
index 000000000000..1f0ff6656de0
--- /dev/null
+++ b/libs/WindowManager/Jetpack/androidx.window.extensions.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Copyright 2020 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+<permissions>
+ <library
+ name="androidx.window.extensions"
+ file="/vendor/framework/androidx.window.extensions.jar"/>
+</permissions>
diff --git a/libs/WindowManager/Jetpack/src/androidx/window/extensions/ExtensionHelper.java b/libs/WindowManager/Jetpack/src/androidx/window/extensions/ExtensionHelper.java
new file mode 100644
index 000000000000..c4f11a0a370c
--- /dev/null
+++ b/libs/WindowManager/Jetpack/src/androidx/window/extensions/ExtensionHelper.java
@@ -0,0 +1,130 @@
+/*
+ * Copyright 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package androidx.window.extensions;
+
+import static android.view.Display.INVALID_DISPLAY;
+import static android.view.Surface.ROTATION_0;
+import static android.view.Surface.ROTATION_180;
+import static android.view.Surface.ROTATION_270;
+import static android.view.Surface.ROTATION_90;
+
+import android.app.Activity;
+import android.app.ActivityThread;
+import android.graphics.Rect;
+import android.hardware.display.DisplayManagerGlobal;
+import android.os.IBinder;
+import android.view.DisplayInfo;
+import android.view.Surface;
+
+/**
+ * Toolkit class for calculation of the display feature bounds within the window.
+ * NOTE: This sample implementation only works for Activity windows, because there is no public APIs
+ * to obtain layout params or bounds for arbitrary windows.
+ */
+class ExtensionHelper {
+ /**
+ * Rotate the input rectangle specified in default display orientation to the current display
+ * rotation.
+ */
+ static void rotateRectToDisplayRotation(Rect inOutRect, int displayId) {
+ DisplayManagerGlobal dmGlobal = DisplayManagerGlobal.getInstance();
+ DisplayInfo displayInfo = dmGlobal.getDisplayInfo(displayId);
+ int rotation = displayInfo.rotation;
+
+ boolean isSideRotation = rotation == ROTATION_90 || rotation == ROTATION_270;
+ int displayWidth = isSideRotation ? displayInfo.logicalHeight : displayInfo.logicalWidth;
+ int displayHeight = isSideRotation ? displayInfo.logicalWidth : displayInfo.logicalHeight;
+
+ inOutRect.intersect(0, 0, displayWidth, displayHeight);
+
+ rotateBounds(inOutRect, displayWidth, displayHeight, rotation);
+ }
+
+ /**
+ * Rotate the input rectangle within parent bounds for a given delta.
+ */
+ private static void rotateBounds(Rect inOutRect, int parentWidth, int parentHeight,
+ @Surface.Rotation int delta) {
+ int origLeft = inOutRect.left;
+ switch (delta) {
+ case ROTATION_0:
+ return;
+ case ROTATION_90:
+ inOutRect.left = inOutRect.top;
+ inOutRect.top = parentWidth - inOutRect.right;
+ inOutRect.right = inOutRect.bottom;
+ inOutRect.bottom = parentWidth - origLeft;
+ return;
+ case ROTATION_180:
+ inOutRect.left = parentWidth - inOutRect.right;
+ inOutRect.right = parentWidth - origLeft;
+ return;
+ case ROTATION_270:
+ inOutRect.left = parentHeight - inOutRect.bottom;
+ inOutRect.bottom = inOutRect.right;
+ inOutRect.right = parentHeight - inOutRect.top;
+ inOutRect.top = origLeft;
+ return;
+ }
+ }
+
+ /** Transform rectangle from absolute coordinate space to the window coordinate space. */
+ static void transformToWindowSpaceRect(Rect inOutRect, IBinder windowToken) {
+ Rect windowRect = getWindowRect(windowToken);
+ if (windowRect == null) {
+ inOutRect.setEmpty();
+ return;
+ }
+ if (!Rect.intersects(inOutRect, windowRect)) {
+ inOutRect.setEmpty();
+ return;
+ }
+ inOutRect.intersect(windowRect);
+ inOutRect.offset(-windowRect.left, -windowRect.top);
+ }
+
+ /**
+ * Get the current window bounds in absolute coordinates.
+ * NOTE: Only works with Activity windows.
+ */
+ private static Rect getWindowRect(IBinder windowToken) {
+ Activity activity = ActivityThread.currentActivityThread().getActivity(windowToken);
+ final Rect windowRect = new Rect();
+ if (activity != null) {
+ activity.getWindow().getDecorView().getWindowDisplayFrame(windowRect);
+ }
+ return windowRect;
+ }
+
+ /**
+ * Check if this window is an Activity window that is in multi-window mode.
+ */
+ static boolean isInMultiWindow(IBinder windowToken) {
+ Activity activity = ActivityThread.currentActivityThread().getActivity(windowToken);
+ return activity != null && activity.isInMultiWindowMode();
+ }
+
+ /**
+ * Get the id of the parent display for the window.
+ * NOTE: Only works with Activity windows.
+ */
+ static int getWindowDisplay(IBinder windowToken) {
+ Activity activity = ActivityThread.currentActivityThread().getActivity(windowToken);
+ return activity != null
+ ? activity.getWindowManager().getDefaultDisplay().getDisplayId() : INVALID_DISPLAY;
+ }
+}
diff --git a/libs/WindowManager/Jetpack/src/androidx/window/extensions/ExtensionProvider.java b/libs/WindowManager/Jetpack/src/androidx/window/extensions/ExtensionProvider.java
new file mode 100644
index 000000000000..47349f11fb93
--- /dev/null
+++ b/libs/WindowManager/Jetpack/src/androidx/window/extensions/ExtensionProvider.java
@@ -0,0 +1,42 @@
+/*
+ * Copyright 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package androidx.window.extensions;
+
+import android.content.Context;
+
+/**
+ * Provider class that will instantiate the library implementation. It must be included in the
+ * vendor library, and the vendor implementation must match the signature of this class.
+ */
+public class ExtensionProvider {
+
+ /**
+ * The support library will instantiate the vendor implementation using this interface.
+ * @return An implementation of {@link ExtensionInterface}.
+ */
+ public static ExtensionInterface getExtensionImpl(Context context) {
+ return new SettingsExtensionImpl(context);
+ }
+
+ /**
+ * The support library will use this method to check API version compatibility.
+ * @return API version string in MAJOR.MINOR.PATCH-description format.
+ */
+ public static String getApiVersion() {
+ return "1.0.0-settings_sample";
+ }
+}
diff --git a/libs/WindowManager/Jetpack/src/androidx/window/extensions/SettingsExtensionImpl.java b/libs/WindowManager/Jetpack/src/androidx/window/extensions/SettingsExtensionImpl.java
new file mode 100644
index 000000000000..7a3fbf3ad9b8
--- /dev/null
+++ b/libs/WindowManager/Jetpack/src/androidx/window/extensions/SettingsExtensionImpl.java
@@ -0,0 +1,217 @@
+/*
+ * Copyright 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package androidx.window.extensions;
+
+import static android.view.Display.DEFAULT_DISPLAY;
+
+import static androidx.window.extensions.ExtensionHelper.getWindowDisplay;
+import static androidx.window.extensions.ExtensionHelper.isInMultiWindow;
+import static androidx.window.extensions.ExtensionHelper.rotateRectToDisplayRotation;
+import static androidx.window.extensions.ExtensionHelper.transformToWindowSpaceRect;
+
+import android.content.ContentResolver;
+import android.content.Context;
+import android.database.ContentObserver;
+import android.graphics.Rect;
+import android.net.Uri;
+import android.os.Handler;
+import android.os.IBinder;
+import android.os.Looper;
+import android.provider.Settings;
+import android.text.TextUtils;
+import android.util.Log;
+
+import androidx.annotation.NonNull;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+class SettingsExtensionImpl extends StubExtension {
+ private static final String TAG = "SettingsExtension";
+
+ private static final String DEVICE_POSTURE = "device_posture";
+ private static final String DISPLAY_FEATURES = "display_features";
+
+ private static final Pattern FEATURE_PATTERN =
+ Pattern.compile("([a-z]+)-\\[(\\d+),(\\d+),(\\d+),(\\d+)]");
+
+ private static final String FEATURE_TYPE_FOLD = "fold";
+ private static final String FEATURE_TYPE_HINGE = "hinge";
+
+ private Context mContext;
+ private SettingsObserver mSettingsObserver;
+
+ final class SettingsObserver extends ContentObserver {
+ private final Uri mDevicePostureUri =
+ Settings.Global.getUriFor(DEVICE_POSTURE);
+ private final Uri mDisplayFeaturesUri =
+ Settings.Global.getUriFor(DISPLAY_FEATURES);
+ private final ContentResolver mResolver = mContext.getContentResolver();
+ private boolean mRegisteredObservers;
+
+
+ private SettingsObserver() {
+ super(new Handler(Looper.getMainLooper()));
+ }
+
+ private void registerObserversIfNeeded() {
+ if (mRegisteredObservers) {
+ return;
+ }
+ mRegisteredObservers = true;
+ mResolver.registerContentObserver(mDevicePostureUri, false /* notifyForDescendents */,
+ this /* ContentObserver */);
+ mResolver.registerContentObserver(mDisplayFeaturesUri, false /* notifyForDescendents */,
+ this /* ContentObserver */);
+ }
+
+ private void unregisterObserversIfNeeded() {
+ if (!mRegisteredObservers) {
+ return;
+ }
+ mRegisteredObservers = false;
+ mResolver.unregisterContentObserver(this);
+ }
+
+ @Override
+ public void onChange(boolean selfChange, Uri uri) {
+ if (uri == null) {
+ return;
+ }
+
+ if (mDevicePostureUri.equals(uri)) {
+ updateDevicePosture();
+ return;
+ }
+ if (mDisplayFeaturesUri.equals(uri)) {
+ updateDisplayFeatures();
+ return;
+ }
+ }
+ }
+
+ SettingsExtensionImpl(Context context) {
+ mContext = context;
+ mSettingsObserver = new SettingsObserver();
+ }
+
+ private void updateDevicePosture() {
+ updateDeviceState(getDeviceState());
+ }
+
+ /** Update display features with values read from settings. */
+ private void updateDisplayFeatures() {
+ for (IBinder windowToken : getWindowsListeningForLayoutChanges()) {
+ ExtensionWindowLayoutInfo newLayout = getWindowLayoutInfo(windowToken);
+ updateWindowLayout(windowToken, newLayout);
+ }
+ }
+
+ @NonNull
+ @Override
+ public ExtensionDeviceState getDeviceState() {
+ ContentResolver resolver = mContext.getContentResolver();
+ int posture = Settings.Global.getInt(resolver, DEVICE_POSTURE,
+ ExtensionDeviceState.POSTURE_UNKNOWN);
+ return new ExtensionDeviceState(posture);
+ }
+
+ @NonNull
+ @Override
+ public ExtensionWindowLayoutInfo getWindowLayoutInfo(@NonNull IBinder windowToken) {
+ List<ExtensionDisplayFeature> displayFeatures = readDisplayFeatures(windowToken);
+ return new ExtensionWindowLayoutInfo(displayFeatures);
+ }
+
+ private List<ExtensionDisplayFeature> readDisplayFeatures(IBinder windowToken) {
+ List<ExtensionDisplayFeature> features = new ArrayList<ExtensionDisplayFeature>();
+ int displayId = getWindowDisplay(windowToken);
+ if (displayId != DEFAULT_DISPLAY) {
+ Log.w(TAG, "This sample doesn't support display features on secondary displays");
+ return features;
+ }
+
+ ContentResolver resolver = mContext.getContentResolver();
+ final String displayFeaturesString = Settings.Global.getString(resolver, DISPLAY_FEATURES);
+ if (isInMultiWindow(windowToken)) {
+ // It is recommended not to report any display features in multi-window mode, since it
+ // won't be possible to synchronize the display feature positions with window movement.
+ return features;
+ }
+ if (TextUtils.isEmpty(displayFeaturesString)) {
+ return features;
+ }
+
+ String[] featureStrings = displayFeaturesString.split(";");
+ for (String featureString : featureStrings) {
+ Matcher featureMatcher = FEATURE_PATTERN.matcher(featureString);
+ if (!featureMatcher.matches()) {
+ Log.e(TAG, "Malformed feature description format: " + featureString);
+ continue;
+ }
+ try {
+ String featureType = featureMatcher.group(1);
+ int type;
+ switch (featureType) {
+ case FEATURE_TYPE_FOLD:
+ type = ExtensionDisplayFeature.TYPE_FOLD;
+ break;
+ case FEATURE_TYPE_HINGE:
+ type = ExtensionDisplayFeature.TYPE_HINGE;
+ break;
+ default: {
+ Log.e(TAG, "Malformed feature type: " + featureType);
+ continue;
+ }
+ }
+
+ int left = Integer.parseInt(featureMatcher.group(2));
+ int top = Integer.parseInt(featureMatcher.group(3));
+ int right = Integer.parseInt(featureMatcher.group(4));
+ int bottom = Integer.parseInt(featureMatcher.group(5));
+ Rect featureRect = new Rect(left, top, right, bottom);
+ rotateRectToDisplayRotation(featureRect, displayId);
+ transformToWindowSpaceRect(featureRect, windowToken);
+ if (!featureRect.isEmpty()) {
+ ExtensionDisplayFeature feature =
+ new ExtensionDisplayFeature(featureRect, type);
+ features.add(feature);
+ } else {
+ Log.w(TAG, "Failed to adjust feature to window");
+ }
+ } catch (NumberFormatException e) {
+ Log.e(TAG, "Malformed feature description: " + featureString);
+ }
+ }
+ return features;
+ }
+
+ @Override
+ protected void onListenersChanged() {
+ if (mSettingsObserver == null) {
+ return;
+ }
+
+ if (hasListeners()) {
+ mSettingsObserver.registerObserversIfNeeded();
+ } else {
+ mSettingsObserver.unregisterObserversIfNeeded();
+ }
+ }
+}
diff --git a/libs/WindowManager/Jetpack/window-extensions-release.aar b/libs/WindowManager/Jetpack/window-extensions-release.aar
new file mode 100644
index 000000000000..0ebbb86daf82
--- /dev/null
+++ b/libs/WindowManager/Jetpack/window-extensions-release.aar
Binary files differ
diff --git a/libs/hwui/Readback.cpp b/libs/hwui/Readback.cpp
index 84c07d7d9dff..39900e65cb8a 100644
--- a/libs/hwui/Readback.cpp
+++ b/libs/hwui/Readback.cpp
@@ -146,12 +146,11 @@ CopyResult Readback::copyImageInto(const sk_sp<SkImage>& image, Matrix4& texTran
}
Layer layer(mRenderThread.renderState(), nullptr, 255, SkBlendMode::kSrc);
- bool disableFilter = MathUtils::areEqual(skiaSrcRect.width(), skiaDestRect.width()) &&
- MathUtils::areEqual(skiaSrcRect.height(), skiaDestRect.height());
- layer.setForceFilter(!disableFilter);
layer.setSize(displayedWidth, displayedHeight);
texTransform.copyTo(layer.getTexTransform());
layer.setImage(image);
+ // Scaling filter is not explicitly set here, because it is done inside copyLayerInfo
+ // after checking the necessity based on the src/dest rect size and the transformation.
if (copyLayerInto(&layer, &skiaSrcRect, &skiaDestRect, bitmap)) {
copyResult = CopyResult::Success;
}
diff --git a/libs/hwui/RenderNode.cpp b/libs/hwui/RenderNode.cpp
index 31e45558139d..6761435a8171 100644
--- a/libs/hwui/RenderNode.cpp
+++ b/libs/hwui/RenderNode.cpp
@@ -27,6 +27,7 @@
#include "DamageAccumulator.h"
#include "pipeline/skia/SkiaDisplayList.h"
#endif
+#include "utils/FatVector.h"
#include "utils/MathUtils.h"
#include "utils/StringUtils.h"
#include "utils/TraceUtils.h"
@@ -36,7 +37,6 @@
#include <atomic>
#include <sstream>
#include <string>
-#include <ui/FatVector.h>
namespace android {
namespace uirenderer {
diff --git a/libs/hwui/RenderNode.h b/libs/hwui/RenderNode.h
index c0ec2174bb35..d55e5b0ce836 100644
--- a/libs/hwui/RenderNode.h
+++ b/libs/hwui/RenderNode.h
@@ -27,8 +27,6 @@
#include <androidfw/ResourceTypes.h>
-#include <ui/FatVector.h>
-
#include "AnimatorManager.h"
#include "CanvasTransform.h"
#include "Debug.h"
@@ -37,6 +35,7 @@
#include "RenderProperties.h"
#include "pipeline/skia/SkiaDisplayList.h"
#include "pipeline/skia/SkiaLayer.h"
+#include "utils/FatVector.h"
#include <vector>
diff --git a/libs/hwui/jni/FontFamily.cpp b/libs/hwui/jni/FontFamily.cpp
index a2fef1e19328..0ce04a2437b9 100644
--- a/libs/hwui/jni/FontFamily.cpp
+++ b/libs/hwui/jni/FontFamily.cpp
@@ -29,9 +29,9 @@
#include <hwui/MinikinSkia.h>
#include <hwui/Typeface.h>
+#include <utils/FatVector.h>
#include <minikin/FontFamily.h>
#include <minikin/LocaleList.h>
-#include <ui/FatVector.h>
#include <memory>
@@ -104,7 +104,7 @@ static jlong FontFamily_getFamilyReleaseFunc(CRITICAL_JNI_PARAMS) {
static bool addSkTypeface(NativeFamilyBuilder* builder, sk_sp<SkData>&& data, int ttcIndex,
jint weight, jint italic) {
- FatVector<SkFontArguments::Axis, 2> skiaAxes;
+ uirenderer::FatVector<SkFontArguments::Axis, 2> skiaAxes;
for (const auto& axis : builder->axes) {
skiaAxes.emplace_back(SkFontArguments::Axis{axis.axisTag, axis.value});
}
diff --git a/libs/hwui/jni/fonts/Font.cpp b/libs/hwui/jni/fonts/Font.cpp
index 5714cd1d0390..7e8f8d8d173c 100644
--- a/libs/hwui/jni/fonts/Font.cpp
+++ b/libs/hwui/jni/fonts/Font.cpp
@@ -28,8 +28,8 @@
#include <hwui/MinikinSkia.h>
#include <hwui/Typeface.h>
+#include <utils/FatVector.h>
#include <minikin/FontFamily.h>
-#include <ui/FatVector.h>
#include <memory>
@@ -93,7 +93,7 @@ static jlong Font_Builder_build(JNIEnv* env, jobject clazz, jlong builderPtr, jo
sk_sp<SkData> data(SkData::MakeWithProc(fontPtr, fontSize,
release_global_ref, reinterpret_cast<void*>(fontRef)));
- FatVector<SkFontArguments::Axis, 2> skiaAxes;
+ uirenderer::FatVector<SkFontArguments::Axis, 2> skiaAxes;
for (const auto& axis : builder->axes) {
skiaAxes.emplace_back(SkFontArguments::Axis{axis.axisTag, axis.value});
}
diff --git a/libs/hwui/pipeline/skia/ReorderBarrierDrawables.h b/libs/hwui/pipeline/skia/ReorderBarrierDrawables.h
index d669f84c5ee2..cfc0f9b258da 100644
--- a/libs/hwui/pipeline/skia/ReorderBarrierDrawables.h
+++ b/libs/hwui/pipeline/skia/ReorderBarrierDrawables.h
@@ -21,7 +21,7 @@
#include <SkCanvas.h>
#include <SkDrawable.h>
-#include <ui/FatVector.h>
+#include <utils/FatVector.h>
namespace android {
namespace uirenderer {
diff --git a/libs/hwui/renderthread/RenderThread.cpp b/libs/hwui/renderthread/RenderThread.cpp
index 206b58f62ea7..cae3e3b5188c 100644
--- a/libs/hwui/renderthread/RenderThread.cpp
+++ b/libs/hwui/renderthread/RenderThread.cpp
@@ -27,6 +27,7 @@
#include "pipeline/skia/SkiaOpenGLPipeline.h"
#include "pipeline/skia/SkiaVulkanPipeline.h"
#include "renderstate/RenderState.h"
+#include "utils/FatVector.h"
#include "utils/TimeUtils.h"
#include "utils/TraceUtils.h"
@@ -39,8 +40,6 @@
#include <utils/Mutex.h>
#include <thread>
-#include <ui/FatVector.h>
-
namespace android {
namespace uirenderer {
namespace renderthread {
diff --git a/libs/hwui/renderthread/VulkanManager.cpp b/libs/hwui/renderthread/VulkanManager.cpp
index ba70afc8b8d2..a5355fc3499d 100644
--- a/libs/hwui/renderthread/VulkanManager.cpp
+++ b/libs/hwui/renderthread/VulkanManager.cpp
@@ -23,13 +23,13 @@
#include <GrContext.h>
#include <GrTypes.h>
#include <android/sync.h>
-#include <ui/FatVector.h>
#include <vk/GrVkExtensions.h>
#include <vk/GrVkTypes.h>
#include "Properties.h"
#include "RenderThread.h"
#include "renderstate/RenderState.h"
+#include "utils/FatVector.h"
#include "utils/TraceUtils.h"
namespace android {
diff --git a/libs/hwui/tests/unit/FatVectorTests.cpp b/libs/hwui/tests/unit/FatVectorTests.cpp
index 6585a6249b44..8523e6c9e973 100644
--- a/libs/hwui/tests/unit/FatVectorTests.cpp
+++ b/libs/hwui/tests/unit/FatVectorTests.cpp
@@ -15,7 +15,7 @@
*/
#include <gtest/gtest.h>
-#include <ui/FatVector.h>
+#include <utils/FatVector.h>
#include <tests/common/TestUtils.h>
diff --git a/libs/hwui/utils/FatVector.h b/libs/hwui/utils/FatVector.h
new file mode 100644
index 000000000000..49f1984b779f
--- /dev/null
+++ b/libs/hwui/utils/FatVector.h
@@ -0,0 +1,96 @@
+/*
+ * Copyright 2015, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef ANDROID_FAT_VECTOR_H
+#define ANDROID_FAT_VECTOR_H
+
+#include "utils/Macros.h"
+
+#include <stddef.h>
+#include <stdlib.h>
+#include <utils/Log.h>
+#include <type_traits>
+
+#include <vector>
+
+namespace android {
+namespace uirenderer {
+
+template <typename T, size_t SIZE>
+class InlineStdAllocator {
+public:
+ struct Allocation {
+ PREVENT_COPY_AND_ASSIGN(Allocation);
+
+ public:
+ Allocation(){};
+ // char array instead of T array, so memory is uninitialized, with no destructors run
+ char array[sizeof(T) * SIZE];
+ bool inUse = false;
+ };
+
+ typedef T value_type; // needed to implement std::allocator
+ typedef T* pointer; // needed to implement std::allocator
+
+ explicit InlineStdAllocator(Allocation& allocation) : mAllocation(allocation) {}
+ InlineStdAllocator(const InlineStdAllocator& other) : mAllocation(other.mAllocation) {}
+ ~InlineStdAllocator() {}
+
+ T* allocate(size_t num, const void* = 0) {
+ if (!mAllocation.inUse && num <= SIZE) {
+ mAllocation.inUse = true;
+ return (T*)mAllocation.array;
+ } else {
+ return (T*)malloc(num * sizeof(T));
+ }
+ }
+
+ void deallocate(pointer p, size_t num) {
+ if (p == (T*)mAllocation.array) {
+ mAllocation.inUse = false;
+ } else {
+ // 'free' instead of delete here - destruction handled separately
+ free(p);
+ }
+ }
+ Allocation& mAllocation;
+};
+
+/**
+ * std::vector with SIZE elements preallocated into an internal buffer.
+ *
+ * Useful for avoiding the cost of malloc in cases where only SIZE or
+ * fewer elements are needed in the common case.
+ */
+template <typename T, size_t SIZE>
+class FatVector : public std::vector<T, InlineStdAllocator<T, SIZE>> {
+public:
+ FatVector()
+ : std::vector<T, InlineStdAllocator<T, SIZE>>(
+ InlineStdAllocator<T, SIZE>(mAllocation)) {
+ this->reserve(SIZE);
+ }
+
+ explicit FatVector(size_t capacity) : FatVector() { this->resize(capacity); }
+
+private:
+ typename InlineStdAllocator<T, SIZE>::Allocation mAllocation;
+};
+
+} // namespace uirenderer
+} // namespace android
+
+#endif // ANDROID_FAT_VECTOR_H
diff --git a/libs/incident/include_priv/android/os/IncidentReportArgs.h b/libs/incident/include_priv/android/os/IncidentReportArgs.h
index 0e6159032e45..ec3aabb3b49d 100644
--- a/libs/incident/include_priv/android/os/IncidentReportArgs.h
+++ b/libs/incident/include_priv/android/os/IncidentReportArgs.h
@@ -53,6 +53,7 @@ public:
void setReceiverPkg(const string& pkg);
void setReceiverCls(const string& cls);
void addHeader(const vector<uint8_t>& headerProto);
+ void setGzip(bool gzip);
inline bool all() const { return mAll; }
bool containsSection(int section, bool specific) const;
@@ -61,6 +62,7 @@ public:
inline const string& receiverPkg() const { return mReceiverPkg; }
inline const string& receiverCls() const { return mReceiverCls; }
inline const vector<vector<uint8_t>>& headers() const { return mHeaders; }
+ inline bool gzip() const {return mGzip; }
void merge(const IncidentReportArgs& that);
@@ -71,6 +73,7 @@ private:
int mPrivacyPolicy;
string mReceiverPkg;
string mReceiverCls;
+ bool mGzip;
};
}
diff --git a/libs/incident/src/IncidentReportArgs.cpp b/libs/incident/src/IncidentReportArgs.cpp
index 9d8a98338ef0..db495cfbf7e1 100644
--- a/libs/incident/src/IncidentReportArgs.cpp
+++ b/libs/incident/src/IncidentReportArgs.cpp
@@ -26,7 +26,8 @@ namespace os {
IncidentReportArgs::IncidentReportArgs()
:mSections(),
mAll(false),
- mPrivacyPolicy(-1)
+ mPrivacyPolicy(-1),
+ mGzip(false)
{
}
@@ -36,7 +37,8 @@ IncidentReportArgs::IncidentReportArgs(const IncidentReportArgs& that)
mAll(that.mAll),
mPrivacyPolicy(that.mPrivacyPolicy),
mReceiverPkg(that.mReceiverPkg),
- mReceiverCls(that.mReceiverCls)
+ mReceiverCls(that.mReceiverCls),
+ mGzip(that.mGzip)
{
}
@@ -93,6 +95,11 @@ IncidentReportArgs::writeToParcel(Parcel* out) const
return err;
}
+ err = out->writeInt32(mGzip);
+ if (err != NO_ERROR) {
+ return err;
+ }
+
return NO_ERROR;
}
@@ -149,6 +156,15 @@ IncidentReportArgs::readFromParcel(const Parcel* in)
mReceiverPkg = String8(in->readString16()).string();
mReceiverCls = String8(in->readString16()).string();
+ int32_t gzip;
+ err = in->readInt32(&gzip);
+ if (err != NO_ERROR) {
+ return err;
+ }
+ if (gzip != 0) {
+ mGzip = gzip;
+ }
+
return OK;
}
@@ -193,6 +209,12 @@ IncidentReportArgs::addHeader(const vector<uint8_t>& headerProto)
mHeaders.push_back(headerProto);
}
+void
+IncidentReportArgs::setGzip(bool gzip)
+{
+ mGzip = gzip;
+}
+
bool
IncidentReportArgs::containsSection(int section, bool specific) const
{
diff --git a/location/java/android/location/LocationManager.java b/location/java/android/location/LocationManager.java
index e2309178b297..550e41f28f85 100644
--- a/location/java/android/location/LocationManager.java
+++ b/location/java/android/location/LocationManager.java
@@ -103,6 +103,16 @@ public class LocationManager {
private final Object mLock = new Object();
/**
+ * For apps targeting Android R and above, {@link #getProvider(String)} will no longer throw any
+ * security exceptions.
+ *
+ * @hide
+ */
+ @ChangeId
+ @EnabledAfter(targetSdkVersion = Build.VERSION_CODES.Q)
+ private static final long GET_PROVIDER_SECURITY_EXCEPTIONS = 150935354L;
+
+ /**
* For apps targeting Android K and above, supplied {@link PendingIntent}s must be targeted to a
* specific package.
*
@@ -1401,6 +1411,22 @@ public class LocationManager {
*/
public @Nullable LocationProvider getProvider(@NonNull String provider) {
Preconditions.checkArgument(provider != null, "invalid null provider");
+
+ if (!Compatibility.isChangeEnabled(GET_PROVIDER_SECURITY_EXCEPTIONS)) {
+ if (NETWORK_PROVIDER.equals(provider) || FUSED_PROVIDER.equals(provider)) {
+ try {
+ mContext.enforcePermission(ACCESS_FINE_LOCATION, Process.myPid(),
+ Process.myUid(), null);
+ } catch (SecurityException e) {
+ mContext.enforcePermission(ACCESS_COARSE_LOCATION, Process.myPid(),
+ Process.myUid(), null);
+ }
+ } else {
+ mContext.enforcePermission(ACCESS_FINE_LOCATION, Process.myPid(), Process.myUid(),
+ null);
+ }
+ }
+
try {
ProviderProperties properties = mService.getProviderProperties(provider);
if (properties == null) {
diff --git a/location/java/com/android/internal/location/gnssmetrics/GnssMetrics.java b/location/java/com/android/internal/location/gnssmetrics/GnssMetrics.java
index 1ac4b4b29fbf..323bba3fdd71 100644
--- a/location/java/com/android/internal/location/gnssmetrics/GnssMetrics.java
+++ b/location/java/com/android/internal/location/gnssmetrics/GnssMetrics.java
@@ -624,7 +624,7 @@ public class GnssMetrics {
private void registerGnssStats() {
mPullAtomCallback = new StatsPullAtomCallbackImpl();
- mStatsManager.registerPullAtomCallback(
+ mStatsManager.setPullAtomCallback(
FrameworkStatsLog.GNSS_STATS,
null, // use default PullAtomMetadata values
BackgroundThread.getExecutor(), mPullAtomCallback);
diff --git a/media/java/android/media/AudioMetadata.java b/media/java/android/media/AudioMetadata.java
index 7245aab41eec..e67ba5905aae 100644
--- a/media/java/android/media/AudioMetadata.java
+++ b/media/java/android/media/AudioMetadata.java
@@ -16,10 +16,18 @@
package android.media;
+import android.annotation.IntRange;
import android.annotation.NonNull;
import android.annotation.Nullable;
+import android.util.Log;
import android.util.Pair;
+import java.lang.reflect.ParameterizedType;
+import java.nio.BufferUnderflowException;
+import java.nio.ByteBuffer;
+import java.nio.ByteOrder;
+import java.nio.charset.Charset;
+import java.nio.charset.StandardCharsets;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Objects;
@@ -30,6 +38,8 @@ import java.util.Set;
* configuration and capability requests within the Audio Framework.
*/
public final class AudioMetadata {
+ private static final String TAG = "AudioMetadata";
+
/**
* Key interface for the map.
*
@@ -273,7 +283,7 @@ public final class AudioMetadata {
* @hide
*/
@NonNull
- public static <T> Key<T> createKey(String name, Class<T> type) {
+ public static <T> Key<T> createKey(@NonNull String name, @NonNull Class<T> type) {
// Implementation specific.
return new Key<T>() {
private final String mName = name;
@@ -296,6 +306,26 @@ public final class AudioMetadata {
public boolean isFromFramework() {
return true;
}
+
+ /**
+ * Return true if the name and the type of two objects are the same.
+ */
+ @Override
+ public boolean equals(Object obj) {
+ if (obj == this) {
+ return true;
+ }
+ if (!(obj instanceof Key)) {
+ return false;
+ }
+ Key<?> other = (Key<?>) obj;
+ return mName.equals(other.getName()) && mType.equals(other.getValueClass());
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(mName, mType);
+ }
};
}
@@ -364,6 +394,27 @@ public final class AudioMetadata {
return mHashMap.size();
}
+ /**
+ * Return true if the object is a BaseMap and the content from two BaseMap are the same.
+ * Note: Need to override the equals functions of Key<T> for HashMap comparison.
+ */
+ @Override
+ public boolean equals(Object obj) {
+ if (obj == this) {
+ return true;
+ }
+ if (!(obj instanceof BaseMap)) {
+ return false;
+ }
+ BaseMap other = (BaseMap) obj;
+ return mHashMap.equals(other.mHashMap);
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(mHashMap);
+ }
+
/*
* Implementation specific.
*
@@ -401,6 +452,445 @@ public final class AudioMetadata {
new HashMap();
}
+ // The audio metadata object type index should be kept the same as
+ // the ones in audio_utils::metadata::metadata_types
+ private static final int AUDIO_METADATA_OBJ_TYPE_NONE = 0;
+ private static final int AUDIO_METADATA_OBJ_TYPE_INT = 1;
+ private static final int AUDIO_METADATA_OBJ_TYPE_LONG = 2;
+ private static final int AUDIO_METADATA_OBJ_TYPE_FLOAT = 3;
+ private static final int AUDIO_METADATA_OBJ_TYPE_DOUBLE = 4;
+ private static final int AUDIO_METADATA_OBJ_TYPE_STRING = 5;
+ // BaseMap is corresponding to audio_utils::metadata::Data
+ private static final int AUDIO_METADATA_OBJ_TYPE_BASEMAP = 6;
+
+ private static final HashMap<Class, Integer> AUDIO_METADATA_OBJ_TYPES = new HashMap<>() {{
+ put(Integer.class, AUDIO_METADATA_OBJ_TYPE_INT);
+ put(Long.class, AUDIO_METADATA_OBJ_TYPE_LONG);
+ put(Float.class, AUDIO_METADATA_OBJ_TYPE_FLOAT);
+ put(Double.class, AUDIO_METADATA_OBJ_TYPE_DOUBLE);
+ put(String.class, AUDIO_METADATA_OBJ_TYPE_STRING);
+ put(BaseMap.class, AUDIO_METADATA_OBJ_TYPE_BASEMAP);
+ }};
+
+ private static final Charset AUDIO_METADATA_CHARSET = StandardCharsets.UTF_8;
+
+ /**
+ * An auto growing byte buffer
+ */
+ private static class AutoGrowByteBuffer {
+ private static final int INTEGER_BYTE_COUNT = Integer.SIZE / Byte.SIZE;
+ private static final int LONG_BYTE_COUNT = Long.SIZE / Byte.SIZE;
+ private static final int FLOAT_BYTE_COUNT = Float.SIZE / Byte.SIZE;
+ private static final int DOUBLE_BYTE_COUNT = Double.SIZE / Byte.SIZE;
+
+ private ByteBuffer mBuffer;
+
+ AutoGrowByteBuffer() {
+ this(1024);
+ }
+
+ AutoGrowByteBuffer(@IntRange(from = 0) int initialCapacity) {
+ mBuffer = ByteBuffer.allocateDirect(initialCapacity);
+ }
+
+ public ByteBuffer getRawByteBuffer() {
+ // Slice the buffer from 0 to position.
+ int limit = mBuffer.limit();
+ int position = mBuffer.position();
+ mBuffer.limit(position);
+ mBuffer.position(0);
+ ByteBuffer buffer = mBuffer.slice();
+
+ // Restore position and limit.
+ mBuffer.limit(limit);
+ mBuffer.position(position);
+ return buffer;
+ }
+
+ public ByteOrder order() {
+ return mBuffer.order();
+ }
+
+ public int position() {
+ return mBuffer.position();
+ }
+
+ public AutoGrowByteBuffer position(int newPosition) {
+ mBuffer.position(newPosition);
+ return this;
+ }
+
+ public AutoGrowByteBuffer order(ByteOrder order) {
+ mBuffer.order(order);
+ return this;
+ }
+
+ public AutoGrowByteBuffer putInt(int value) {
+ ensureCapacity(INTEGER_BYTE_COUNT);
+ mBuffer.putInt(value);
+ return this;
+ }
+
+ public AutoGrowByteBuffer putLong(long value) {
+ ensureCapacity(LONG_BYTE_COUNT);
+ mBuffer.putLong(value);
+ return this;
+ }
+
+ public AutoGrowByteBuffer putFloat(float value) {
+ ensureCapacity(FLOAT_BYTE_COUNT);
+ mBuffer.putFloat(value);
+ return this;
+ }
+
+ public AutoGrowByteBuffer putDouble(double value) {
+ ensureCapacity(DOUBLE_BYTE_COUNT);
+ mBuffer.putDouble(value);
+ return this;
+ }
+
+ public AutoGrowByteBuffer put(byte[] src) {
+ ensureCapacity(src.length);
+ mBuffer.put(src);
+ return this;
+ }
+
+ /**
+ * Ensures capacity to append at least <code>count</code> values.
+ */
+ private void ensureCapacity(@IntRange int count) {
+ if (mBuffer.remaining() < count) {
+ int newCapacity = mBuffer.position() + count;
+ if (newCapacity > Integer.MAX_VALUE >> 1) {
+ throw new IllegalStateException(
+ "Item memory requirements too large: " + newCapacity);
+ }
+ newCapacity <<= 1;
+ ByteBuffer buffer = ByteBuffer.allocateDirect(newCapacity);
+ buffer.order(mBuffer.order());
+
+ // Copy data from old buffer to new buffer
+ mBuffer.flip();
+ buffer.put(mBuffer);
+
+ // Set buffer to new buffer
+ mBuffer = buffer;
+ }
+ }
+ }
+
+ /**
+ * @hide
+ * Describes a unpacking/packing contract of type {@code T} out of a {@link ByteBuffer}
+ *
+ * @param <T> the type being unpack
+ */
+ private interface DataPackage<T> {
+ /**
+ * Read an item from a {@link ByteBuffer}.
+ *
+ * The parceling format is assumed the same as the one described in
+ * audio_utils::Metadata.h. Copied here as a reference.
+ * All values are native endian order.
+ *
+ * Datum = { (type_size_t) Type (the type index from type_as_value<T>.)
+ * (datum_size_t) Size (size of datum, including the size field)
+ * (byte string) Payload<Type>
+ * }
+ *
+ * Primitive types:
+ * Payload<Type> = { bytes in native endian order }
+ *
+ * Vector, Map, Container types:
+ * Payload<Type> = { (index_size_t) number of elements
+ * (byte string) Payload<Element_Type> * number
+ * }
+ *
+ * Pair container types:
+ * Payload<Type> = { (byte string) Payload<first>,
+ * (byte string) Payload<second>
+ * }
+ *
+ * @param buffer the byte buffer to read from
+ * @return an object, which types is given type for {@link DataPackage}
+ * @throws BufferUnderflowException when there is no enough data remaining
+ * in the buffer for unpacking.
+ */
+ @Nullable
+ T unpack(ByteBuffer buffer);
+
+ /**
+ * Pack the item into a byte array. This is the reversed way of unpacking.
+ *
+ * @param output is the stream to which to write the data
+ * @param obj the item to pack
+ * @return true if packing successfully. Otherwise, return false.
+ */
+ boolean pack(AutoGrowByteBuffer output, T obj);
+
+ /**
+ * Return what kind of data is contained in the package.
+ */
+ default Class getMyType() {
+ return (Class) ((ParameterizedType) getClass().getGenericInterfaces()[0])
+ .getActualTypeArguments()[0];
+ }
+ }
+
+ /*****************************************************************************************
+ * Following class are common {@link DataPackage} implementations, which include types
+ * that are defined in audio_utils::metadata::metadata_types
+ *
+ * For Java
+ * int32_t corresponds to Integer
+ * int64_t corresponds to Long
+ * float corresponds to Float
+ * double corresponds to Double
+ * std::string corresponds to String
+ * Data corresponds to BaseMap
+ * Datum corresponds to Object
+ ****************************************************************************************/
+
+ private static final HashMap<Integer, DataPackage<?>> DATA_PACKAGES = new HashMap<>() {{
+ put(AUDIO_METADATA_OBJ_TYPE_INT, new DataPackage<Integer>() {
+ @Override
+ @Nullable
+ public Integer unpack(ByteBuffer buffer) {
+ return buffer.getInt();
+ }
+
+ @Override
+ public boolean pack(AutoGrowByteBuffer output, Integer obj) {
+ output.putInt(obj);
+ return true;
+ }
+ });
+ put(AUDIO_METADATA_OBJ_TYPE_LONG, new DataPackage<Long>() {
+ @Override
+ @Nullable
+ public Long unpack(ByteBuffer buffer) {
+ return buffer.getLong();
+ }
+
+ @Override
+ public boolean pack(AutoGrowByteBuffer output, Long obj) {
+ output.putLong(obj);
+ return true;
+ }
+ });
+ put(AUDIO_METADATA_OBJ_TYPE_FLOAT, new DataPackage<Float>() {
+ @Override
+ @Nullable
+ public Float unpack(ByteBuffer buffer) {
+ return buffer.getFloat();
+ }
+
+ @Override
+ public boolean pack(AutoGrowByteBuffer output, Float obj) {
+ output.putFloat(obj);
+ return true;
+ }
+ });
+ put(AUDIO_METADATA_OBJ_TYPE_DOUBLE, new DataPackage<Double>() {
+ @Override
+ @Nullable
+ public Double unpack(ByteBuffer buffer) {
+ return buffer.getDouble();
+ }
+
+ @Override
+ public boolean pack(AutoGrowByteBuffer output, Double obj) {
+ output.putDouble(obj);
+ return true;
+ }
+ });
+ put(AUDIO_METADATA_OBJ_TYPE_STRING, new DataPackage<String>() {
+ @Override
+ @Nullable
+ public String unpack(ByteBuffer buffer) {
+ int dataSize = buffer.getInt();
+ if (buffer.position() + dataSize > buffer.limit()) {
+ return null;
+ }
+ byte[] valueArr = new byte[dataSize];
+ buffer.get(valueArr);
+ String value = new String(valueArr, AUDIO_METADATA_CHARSET);
+ return value;
+ }
+
+ /**
+ * This is a reversed operation of unpack. It is needed to write the String
+ * at bytes encoded with AUDIO_METADATA_CHARSET. There should be an integer
+ * value representing the length of the bytes written before the bytes.
+ */
+ @Override
+ public boolean pack(AutoGrowByteBuffer output, String obj) {
+ byte[] valueArr = obj.getBytes(AUDIO_METADATA_CHARSET);
+ output.putInt(valueArr.length);
+ output.put(valueArr);
+ return true;
+ }
+ });
+ put(AUDIO_METADATA_OBJ_TYPE_BASEMAP, new BaseMapPackage());
+ }};
+ // ObjectPackage is a special case that it is expected to unpack audio_utils::metadata::Datum,
+ // which contains data type and data size besides the payload for the data.
+ private static final ObjectPackage OBJECT_PACKAGE = new ObjectPackage();
+
+ private static class ObjectPackage implements DataPackage<Pair<Class, Object>> {
+ /**
+ * The {@link ObjectPackage} will unpack byte string for audio_utils::metadata::Datum.
+ * Since the Datum is a std::any, {@link Object} is used to carrying the data. The
+ * data type is stored in the data package header. In that case, a {@link Class}
+ * will also be returned to indicate the actual type for the object.
+ */
+ @Override
+ @Nullable
+ public Pair<Class, Object> unpack(ByteBuffer buffer) {
+ int dataType = buffer.getInt();
+ DataPackage dataPackage = DATA_PACKAGES.get(dataType);
+ if (dataPackage == null) {
+ Log.e(TAG, "Cannot find DataPackage for type:" + dataType);
+ return null;
+ }
+ int dataSize = buffer.getInt();
+ int position = buffer.position();
+ Object obj = dataPackage.unpack(buffer);
+ if (buffer.position() - position != dataSize) {
+ Log.e(TAG, "Broken data package");
+ return null;
+ }
+ return new Pair<Class, Object>(dataPackage.getMyType(), obj);
+ }
+
+ @Override
+ public boolean pack(AutoGrowByteBuffer output, Pair<Class, Object> obj) {
+ final Integer dataType = AUDIO_METADATA_OBJ_TYPES.get(obj.first);
+ if (dataType == null) {
+ Log.e(TAG, "Cannot find data type for " + obj.first);
+ return false;
+ }
+ DataPackage dataPackage = DATA_PACKAGES.get(dataType);
+ if (dataPackage == null) {
+ Log.e(TAG, "Cannot find DataPackage for type:" + dataType);
+ return false;
+ }
+ output.putInt(dataType);
+ int position = output.position(); // Keep current position.
+ output.putInt(0); // Keep a place for the size of payload.
+ int payloadIdx = output.position();
+ if (!dataPackage.pack(output, obj.second)) {
+ Log.i(TAG, "Failed to pack object: " + obj.second);
+ return false;
+ }
+ // Put the actual payload size.
+ int currentPosition = output.position();
+ output.position(position);
+ output.putInt(currentPosition - payloadIdx);
+ output.position(currentPosition);
+ return true;
+ }
+ }
+
+ /**
+ * BaseMap will be corresponding to audio_utils::metadata::Data.
+ */
+ private static class BaseMapPackage implements DataPackage<BaseMap> {
+ @Override
+ @Nullable
+ public BaseMap unpack(ByteBuffer buffer) {
+ BaseMap ret = new BaseMap();
+ int mapSize = buffer.getInt();
+ DataPackage<String> strDataPackage =
+ (DataPackage<String>) DATA_PACKAGES.get(AUDIO_METADATA_OBJ_TYPE_STRING);
+ if (strDataPackage == null) {
+ Log.e(TAG, "Cannot find DataPackage for String");
+ return null;
+ }
+ for (int i = 0; i < mapSize; i++) {
+ String key = strDataPackage.unpack(buffer);
+ if (key == null) {
+ Log.e(TAG, "Failed to unpack key for map");
+ return null;
+ }
+ Pair<Class, Object> value = OBJECT_PACKAGE.unpack(buffer);
+ if (value == null) {
+ Log.e(TAG, "Failed to unpack value for map");
+ return null;
+ }
+ ret.set(createKey(key, value.first), value.first.cast(value.second));
+ }
+ return ret;
+ }
+
+ @Override
+ public boolean pack(AutoGrowByteBuffer output, BaseMap obj) {
+ output.putInt(obj.size());
+ DataPackage<String> strDataPackage =
+ (DataPackage<String>) DATA_PACKAGES.get(AUDIO_METADATA_OBJ_TYPE_STRING);
+ if (strDataPackage == null) {
+ Log.e(TAG, "Cannot find DataPackage for String");
+ return false;
+ }
+ for (Key<?> key : obj.keySet()) {
+ if (!strDataPackage.pack(output, key.getName())) {
+ Log.i(TAG, "Failed to pack key: " + key.getName());
+ return false;
+ }
+ if (!OBJECT_PACKAGE.pack(output, new Pair<>(key.getValueClass(), obj.get(key)))) {
+ Log.i(TAG, "Failed to pack value: " + obj.get(key));
+ return false;
+ }
+ }
+ return true;
+ }
+ }
+
+ /**
+ * @hide
+ * Extract a {@link BaseMap} from a given {@link ByteBuffer}
+ * @param buffer is a byte string that contains information to unpack.
+ * @return a {@link BaseMap} object if extracting successfully from given byte buffer.
+ * Otherwise, returns {@code null}.
+ */
+ @Nullable
+ public static BaseMap fromByteBuffer(ByteBuffer buffer) {
+ DataPackage dataPackage = DATA_PACKAGES.get(AUDIO_METADATA_OBJ_TYPE_BASEMAP);
+ if (dataPackage == null) {
+ Log.e(TAG, "Cannot find DataPackage for BaseMap");
+ return null;
+ }
+ try {
+ return (BaseMap) dataPackage.unpack(buffer);
+ } catch (BufferUnderflowException e) {
+ Log.e(TAG, "No enough data to unpack");
+ }
+ return null;
+ }
+
+ /**
+ * @hide
+ * Pack a {link BaseMap} to a {@link ByteBuffer}
+ * @param data is the object for packing
+ * @param order is the byte order
+ * @return a {@link ByteBuffer} if successfully packing the data.
+ * Otherwise, returns {@code null};
+ */
+ @Nullable
+ public static ByteBuffer toByteBuffer(BaseMap data, ByteOrder order) {
+ DataPackage dataPackage = DATA_PACKAGES.get(AUDIO_METADATA_OBJ_TYPE_BASEMAP);
+ if (dataPackage == null) {
+ Log.e(TAG, "Cannot find DataPackage for BaseMap");
+ return null;
+ }
+ AutoGrowByteBuffer output = new AutoGrowByteBuffer();
+ output.order(order);
+ if (dataPackage.pack(output, data)) {
+ return output.getRawByteBuffer();
+ }
+ return null;
+ }
+
// Delete the constructor as there is nothing to implement here.
private AudioMetadata() {}
}
diff --git a/media/java/android/media/AudioTrack.java b/media/java/android/media/AudioTrack.java
index 81275f6891ab..94d4fcc02eea 100644
--- a/media/java/android/media/AudioTrack.java
+++ b/media/java/android/media/AudioTrack.java
@@ -4050,8 +4050,15 @@ public class AudioTrack extends PlayerBase
}
if (what == NATIVE_EVENT_CODEC_FORMAT_CHANGE) {
- track.mCodecFormatChangedListeners.notify(
- 0 /* eventCode, unused */, (AudioMetadata.ReadMap) obj);
+ ByteBuffer buffer = (ByteBuffer) obj;
+ buffer.order(ByteOrder.nativeOrder());
+ buffer.rewind();
+ AudioMetadata.ReadMap audioMetaData = AudioMetadata.fromByteBuffer(buffer);
+ if (audioMetaData == null) {
+ Log.e(TAG, "Unable to get audio metadata from byte buffer");
+ return;
+ }
+ track.mCodecFormatChangedListeners.notify(0 /* eventCode, unused */, audioMetaData);
return;
}
diff --git a/media/java/android/media/IMediaRoute2ProviderService.aidl b/media/java/android/media/IMediaRoute2ProviderService.aidl
index 6cd2547dcbcf..eee3d22c7252 100644
--- a/media/java/android/media/IMediaRoute2ProviderService.aidl
+++ b/media/java/android/media/IMediaRoute2ProviderService.aidl
@@ -29,13 +29,13 @@ oneway interface IMediaRoute2ProviderService {
// MediaRoute2ProviderService#MediaRoute2ProviderServiceStub for readability.
void setCallback(IMediaRoute2ProviderServiceCallback callback);
void updateDiscoveryPreference(in RouteDiscoveryPreference discoveryPreference);
- void setRouteVolume(String routeId, int volume, long requestId);
+ void setRouteVolume(long requestId, String routeId, int volume);
- void requestCreateSession(String packageName, String routeId, long requestId,
+ void requestCreateSession(long requestId, String packageName, String routeId,
in @nullable Bundle sessionHints);
- void selectRoute(String sessionId, String routeId, long requestId);
- void deselectRoute(String sessionId, String routeId, long requestId);
- void transferToRoute(String sessionId, String routeId, long requestId);
- void setSessionVolume(String sessionId, int volume, long requestId);
- void releaseSession(String sessionId, long requestId);
+ void selectRoute(long requestId, String sessionId, String routeId);
+ void deselectRoute(long requestId, String sessionId, String routeId);
+ void transferToRoute(long requestId, String sessionId, String routeId);
+ void setSessionVolume(long requestId, String sessionId, int volume);
+ void releaseSession(long requestId, String sessionId);
}
diff --git a/media/java/android/media/IMediaRoute2ProviderServiceCallback.aidl b/media/java/android/media/IMediaRoute2ProviderServiceCallback.aidl
index ab42d75bf14f..1755657ddc64 100644
--- a/media/java/android/media/IMediaRoute2ProviderServiceCallback.aidl
+++ b/media/java/android/media/IMediaRoute2ProviderServiceCallback.aidl
@@ -27,8 +27,7 @@ import android.os.Bundle;
oneway interface IMediaRoute2ProviderServiceCallback {
// TODO: Change it to updateRoutes?
void updateState(in MediaRoute2ProviderInfo providerInfo);
- void notifySessionCreated(in RoutingSessionInfo sessionInfo, long requestId);
- void notifySessionCreationFailed(long requestId);
+ void notifySessionCreated(long requestId, in RoutingSessionInfo sessionInfo);
void notifySessionUpdated(in RoutingSessionInfo sessionInfo);
void notifySessionReleased(in RoutingSessionInfo sessionInfo);
void notifyRequestFailed(long requestId, int reason);
diff --git a/media/java/android/media/IMediaRouter2.aidl b/media/java/android/media/IMediaRouter2.aidl
index 550ecfd02041..dc06153ffa9f 100644
--- a/media/java/android/media/IMediaRouter2.aidl
+++ b/media/java/android/media/IMediaRouter2.aidl
@@ -28,7 +28,7 @@ oneway interface IMediaRouter2 {
void notifyRoutesAdded(in List<MediaRoute2Info> routes);
void notifyRoutesRemoved(in List<MediaRoute2Info> routes);
void notifyRoutesChanged(in List<MediaRoute2Info> routes);
- void notifySessionCreated(in @nullable RoutingSessionInfo sessionInfo, int requestId);
+ void notifySessionCreated(int requestId, in @nullable RoutingSessionInfo sessionInfo);
void notifySessionInfoChanged(in RoutingSessionInfo sessionInfo);
void notifySessionReleased(in RoutingSessionInfo sessionInfo);
}
diff --git a/media/java/android/media/IMediaRouterService.aidl b/media/java/android/media/IMediaRouterService.aidl
index c7cb07d4ac1c..0d87736cfd47 100644
--- a/media/java/android/media/IMediaRouterService.aidl
+++ b/media/java/android/media/IMediaRouterService.aidl
@@ -57,8 +57,8 @@ interface IMediaRouterService {
in RouteDiscoveryPreference preference);
void setRouteVolumeWithRouter2(IMediaRouter2 router, in MediaRoute2Info route, int volume);
- void requestCreateSessionWithRouter2(IMediaRouter2 router, in MediaRoute2Info route,
- int requestId, in @nullable Bundle sessionHints);
+ void requestCreateSessionWithRouter2(IMediaRouter2 router, int requestId,
+ in MediaRoute2Info route, in @nullable Bundle sessionHints);
void selectRouteWithRouter2(IMediaRouter2 router, String sessionId, in MediaRoute2Info route);
void deselectRouteWithRouter2(IMediaRouter2 router, String sessionId, in MediaRoute2Info route);
void transferToRouteWithRouter2(IMediaRouter2 router, String sessionId,
@@ -70,18 +70,18 @@ interface IMediaRouterService {
List<RoutingSessionInfo> getActiveSessions(IMediaRouter2Manager manager);
void registerManager(IMediaRouter2Manager manager, String packageName);
void unregisterManager(IMediaRouter2Manager manager);
- void setRouteVolumeWithManager(IMediaRouter2Manager manager, in MediaRoute2Info route,
- int volume, int requestId);
+ void setRouteVolumeWithManager(IMediaRouter2Manager manager, int requestId,
+ in MediaRoute2Info route, int volume);
- void requestCreateSessionWithManager(IMediaRouter2Manager manager, String packageName,
- in @nullable MediaRoute2Info route, int requestId);
- void selectRouteWithManager(IMediaRouter2Manager manager, String sessionId,
- in MediaRoute2Info route, int requestId);
- void deselectRouteWithManager(IMediaRouter2Manager manager, String sessionId,
- in MediaRoute2Info route, int requestId);
- void transferToRouteWithManager(IMediaRouter2Manager manager, String sessionId,
- in MediaRoute2Info route, int requestId);
- void setSessionVolumeWithManager(IMediaRouter2Manager manager, String sessionId, int volume,
- int requestId);
- void releaseSessionWithManager(IMediaRouter2Manager manager, String sessionId, int requestId);
+ void requestCreateSessionWithManager(IMediaRouter2Manager manager, int requestId,
+ String packageName, in @nullable MediaRoute2Info route);
+ void selectRouteWithManager(IMediaRouter2Manager manager, int requestId,
+ String sessionId, in MediaRoute2Info route);
+ void deselectRouteWithManager(IMediaRouter2Manager manager, int requestId,
+ String sessionId, in MediaRoute2Info route);
+ void transferToRouteWithManager(IMediaRouter2Manager manager, int requestId,
+ String sessionId, in MediaRoute2Info route);
+ void setSessionVolumeWithManager(IMediaRouter2Manager manager, int requestId,
+ String sessionId, int volume);
+ void releaseSessionWithManager(IMediaRouter2Manager manager, int requestId, String sessionId);
}
diff --git a/media/java/android/media/MediaPlayer.java b/media/java/android/media/MediaPlayer.java
index 2d820e7c3c98..49e416080041 100644
--- a/media/java/android/media/MediaPlayer.java
+++ b/media/java/android/media/MediaPlayer.java
@@ -1105,7 +1105,6 @@ public class MediaPlayer extends PlayerBase
setDataSource(afd);
return true;
} catch (NullPointerException | SecurityException | IOException ex) {
- Log.w(TAG, "Couldn't open " + (uri == null ? "null uri" : uri.toSafeString()), ex);
return false;
}
}
diff --git a/media/java/android/media/MediaRoute2Info.java b/media/java/android/media/MediaRoute2Info.java
index 8d63cf04da6d..36ccf001bad2 100644
--- a/media/java/android/media/MediaRoute2Info.java
+++ b/media/java/android/media/MediaRoute2Info.java
@@ -112,38 +112,6 @@ public final class MediaRoute2Info implements Parcelable {
public @interface Type {}
/**
- * The default receiver device type of the route indicating the type is unknown.
- *
- * @see #getDeviceType
- */
- public static final int DEVICE_TYPE_UNKNOWN = 0;
-
- /**
- * A receiver device type of the route indicating the presentation of the media is happening
- * on a TV.
- *
- * @see #getDeviceType
- */
- public static final int DEVICE_TYPE_REMOTE_TV = 1;
-
- /**
- * A receiver device type of the route indicating the presentation of the media is happening
- * on a speaker.
- *
- * @see #getDeviceType
- */
- public static final int DEVICE_TYPE_REMOTE_SPEAKER = 2;
-
- /**
- * A receiver device type of the route indicating the presentation of the media is happening
- * on a bluetooth device such as a bluetooth speaker.
- *
- * @see #getDeviceType
- */
- public static final int DEVICE_TYPE_BLUETOOTH = 3;
-
-
- /**
* The default route type indicating the type is unknown.
*
* @see #getType
@@ -396,18 +364,6 @@ public final class MediaRoute2Info implements Parcelable {
}
/**
- * Gets the type of the receiver device associated with this route.
- *
- * @return The type of the receiver device associated with this route:
- * {@link #DEVICE_TYPE_REMOTE_TV}, {@link #DEVICE_TYPE_REMOTE_SPEAKER},
- * {@link #DEVICE_TYPE_BLUETOOTH}.
- */
- @Type
- public int getDeviceType() {
- return getType();
- }
-
- /**
* Gets the type of this route.
*
* @return The type of this route:
@@ -599,7 +555,6 @@ public final class MediaRoute2Info implements Parcelable {
.append("id=").append(getId())
.append(", name=").append(getName())
.append(", features=").append(getFeatures())
- .append(", deviceType=").append(getDeviceType())
.append(", iconUri=").append(getIconUri())
.append(", description=").append(getDescription())
.append(", connectionState=").append(getConnectionState())
@@ -752,14 +707,6 @@ public final class MediaRoute2Info implements Parcelable {
}
/**
- * Sets the route's device type.
- */
- @NonNull
- public Builder setDeviceType(@Type int type) {
- return setType(type);
- }
-
- /**
* Sets the route's type.
* @hide
*/
diff --git a/media/java/android/media/MediaRoute2ProviderService.java b/media/java/android/media/MediaRoute2ProviderService.java
index aa0eda1fdbb1..8e39dfae7c57 100644
--- a/media/java/android/media/MediaRoute2ProviderService.java
+++ b/media/java/android/media/MediaRoute2ProviderService.java
@@ -78,11 +78,11 @@ public abstract class MediaRoute2ProviderService extends Service {
public static final String SERVICE_INTERFACE = "android.media.MediaRoute2ProviderService";
/**
- * The request ID to pass {@link #notifySessionCreated(RoutingSessionInfo, long)}
+ * The request ID to pass {@link #notifySessionCreated(long, RoutingSessionInfo)}
* when {@link MediaRoute2ProviderService} created a session although there was no creation
* request.
*
- * @see #notifySessionCreated(RoutingSessionInfo, long)
+ * @see #notifySessionCreated(long, RoutingSessionInfo)
*/
public static final long REQUEST_ID_NONE = 0;
@@ -218,21 +218,22 @@ public abstract class MediaRoute2ProviderService extends Service {
* If this session is created without any creation request, use {@link #REQUEST_ID_NONE}
* as the request ID.
*
- * @param sessionInfo information of the new session.
- * The {@link RoutingSessionInfo#getId() id} of the session must be unique.
* @param requestId id of the previous request to create this session provided in
* {@link #onCreateSession(long, String, String, Bundle)}. Can be
* {@link #REQUEST_ID_NONE} if this session is created without any request.
+ * @param sessionInfo information of the new session.
+ * The {@link RoutingSessionInfo#getId() id} of the session must be unique.
* @see #onCreateSession(long, String, String, Bundle)
* @see #getSessionInfo(String)
*/
- public final void notifySessionCreated(@NonNull RoutingSessionInfo sessionInfo,
- long requestId) {
+ public final void notifySessionCreated(long requestId,
+ @NonNull RoutingSessionInfo sessionInfo) {
Objects.requireNonNull(sessionInfo, "sessionInfo must not be null");
String sessionId = sessionInfo.getId();
synchronized (mSessionLock) {
if (mSessionInfo.containsKey(sessionId)) {
+ // TODO: Notify failure to the requester, and throw exception if needed.
Log.w(TAG, "Ignoring duplicate session id.");
return;
}
@@ -246,31 +247,13 @@ public abstract class MediaRoute2ProviderService extends Service {
// TODO: Calling binder calls in multiple thread may cause timing issue.
// Consider to change implementations to avoid the problems.
// For example, post binder calls, always send all sessions at once, etc.
- mRemoteCallback.notifySessionCreated(sessionInfo, requestId);
+ mRemoteCallback.notifySessionCreated(requestId, sessionInfo);
} catch (RemoteException ex) {
Log.w(TAG, "Failed to notify session created.");
}
}
/**
- * Notifies clients of that the session could not be created.
- *
- * @param requestId id of the previous request to create the session provided in
- * {@link #onCreateSession(long, String, String, Bundle)}.
- * @see #onCreateSession(long, String, String, Bundle)
- */
- public final void notifySessionCreationFailed(long requestId) {
- if (mRemoteCallback == null) {
- return;
- }
- try {
- mRemoteCallback.notifySessionCreationFailed(requestId);
- } catch (RemoteException ex) {
- Log.w(TAG, "Failed to notify session creation failed.");
- }
- }
-
- /**
* Notifies the existing session is updated. For example, when
* {@link RoutingSessionInfo#getSelectedRoutes() selected routes} are changed.
*/
@@ -354,7 +337,7 @@ public abstract class MediaRoute2ProviderService extends Service {
* Called when the service receives a request to create a session.
* <p>
* You should create and maintain your own session and notifies the client of
- * session info. Call {@link #notifySessionCreated(RoutingSessionInfo, long)}
+ * session info. Call {@link #notifySessionCreated(long, RoutingSessionInfo)}
* with the given {@code requestId} to notify the information of a new session.
* The created session must have the same route feature and must include the given route
* specified by {@code routeId}.
@@ -364,7 +347,7 @@ public abstract class MediaRoute2ProviderService extends Service {
* {@link Bundle} which contains how to control the session.
* <p>
* If you can't create the session or want to reject the request, call
- * {@link #notifySessionCreationFailed(long)} with the given {@code requestId}.
+ * {@link #notifyRequestFailed(long, int)} with the given {@code requestId}.
*
* @param requestId the id of this request
* @param packageName the package name of the application that selected the route
@@ -521,7 +504,7 @@ public abstract class MediaRoute2ProviderService extends Service {
}
@Override
- public void setRouteVolume(String routeId, int volume, long requestId) {
+ public void setRouteVolume(long requestId, String routeId, int volume) {
if (!checkCallerisSystem()) {
return;
}
@@ -530,7 +513,7 @@ public abstract class MediaRoute2ProviderService extends Service {
}
@Override
- public void requestCreateSession(String packageName, String routeId, long requestId,
+ public void requestCreateSession(long requestId, String packageName, String routeId,
@Nullable Bundle requestCreateSession) {
if (!checkCallerisSystem()) {
return;
@@ -541,7 +524,7 @@ public abstract class MediaRoute2ProviderService extends Service {
}
@Override
- public void selectRoute(String sessionId, String routeId, long requestId) {
+ public void selectRoute(long requestId, String sessionId, String routeId) {
if (!checkCallerisSystem()) {
return;
}
@@ -554,7 +537,7 @@ public abstract class MediaRoute2ProviderService extends Service {
}
@Override
- public void deselectRoute(String sessionId, String routeId, long requestId) {
+ public void deselectRoute(long requestId, String sessionId, String routeId) {
if (!checkCallerisSystem()) {
return;
}
@@ -567,7 +550,7 @@ public abstract class MediaRoute2ProviderService extends Service {
}
@Override
- public void transferToRoute(String sessionId, String routeId, long requestId) {
+ public void transferToRoute(long requestId, String sessionId, String routeId) {
if (!checkCallerisSystem()) {
return;
}
@@ -580,7 +563,7 @@ public abstract class MediaRoute2ProviderService extends Service {
}
@Override
- public void setSessionVolume(String sessionId, int volume, long requestId) {
+ public void setSessionVolume(long requestId, String sessionId, int volume) {
if (!checkCallerisSystem()) {
return;
}
@@ -589,7 +572,7 @@ public abstract class MediaRoute2ProviderService extends Service {
}
@Override
- public void releaseSession(String sessionId, long requestId) {
+ public void releaseSession(long requestId, String sessionId) {
if (!checkCallerisSystem()) {
return;
}
diff --git a/media/java/android/media/MediaRouter2.java b/media/java/android/media/MediaRouter2.java
index fd2408935fff..37e2ab53a1a1 100644
--- a/media/java/android/media/MediaRouter2.java
+++ b/media/java/android/media/MediaRouter2.java
@@ -47,6 +47,11 @@ import java.util.concurrent.atomic.AtomicInteger;
import java.util.stream.Collectors;
/**
+ * This API is not generally intended for third party application developers.
+ * Use the <a href="{@docRoot}jetpack/androidx.html">AndroidX</a>
+ <a href="{@docRoot}reference/androidx/mediarouter/media/package-summary.html">Media Router
+ * Library</a> for consistent behavior across all devices.
+ *
* Media Router 2 allows applications to control the routing of media channels
* and streams from the current device to remote speakers and devices.
*/
@@ -372,7 +377,9 @@ public class MediaRouter2 {
* @see TransferCallback#onTransferred
* @see TransferCallback#onTransferFailed
*/
- public void transferTo(@Nullable MediaRoute2Info route) {
+ public void transferTo(@NonNull MediaRoute2Info route) {
+ Objects.requireNonNull(route, "route must not be null");
+
List<RoutingController> controllers = getControllers();
RoutingController controller = controllers.get(controllers.size() - 1);
@@ -380,19 +387,25 @@ public class MediaRouter2 {
}
/**
+ * Stops the current media routing. If the {@link #getSystemController() system controller}
+ * controls the media routing, this method is a no-op.
+ */
+ public void stop() {
+ List<RoutingController> controllers = getControllers();
+ RoutingController controller = controllers.get(controllers.size() - 1);
+
+ controller.release();
+ }
+
+ /**
* Transfers the media of a routing controller to the given route.
* @param controller a routing controller controlling media routing.
- * @param route the route you want to transfer the media to. Pass {@code null} to stop
- * routing controlled by the given controller.
+ * @param route the route you want to transfer the media to.
* @hide
*/
- void transfer(@NonNull RoutingController controller, @Nullable MediaRoute2Info route) {
+ void transfer(@NonNull RoutingController controller, @NonNull MediaRoute2Info route) {
Objects.requireNonNull(controller, "controller must not be null");
-
- if (route == null) {
- controller.release();
- return;
- }
+ Objects.requireNonNull(route, "route must not be null");
// TODO: Check thread-safety
if (!mRoutes.containsKey(route.getId())) {
@@ -429,11 +442,11 @@ public class MediaRouter2 {
if (stub != null) {
try {
mMediaRouterService.requestCreateSessionWithRouter2(
- stub, route, requestId, controllerHints);
+ stub, requestId, route, controllerHints);
} catch (RemoteException ex) {
Log.e(TAG, "transfer: Unable to request to create controller.", ex);
mHandler.sendMessage(obtainMessage(MediaRouter2::createControllerOnHandler,
- MediaRouter2.this, null, requestId));
+ MediaRouter2.this, requestId, null));
}
}
}
@@ -559,7 +572,7 @@ public class MediaRouter2 {
* <p>
* Pass {@code null} to sessionInfo for the failure case.
*/
- void createControllerOnHandler(@Nullable RoutingSessionInfo sessionInfo, int requestId) {
+ void createControllerOnHandler(int requestId, @Nullable RoutingSessionInfo sessionInfo) {
ControllerCreationRequest matchingRequest = null;
for (ControllerCreationRequest request : mControllerCreationRequests) {
if (request.mRequestId == requestId) {
@@ -676,7 +689,7 @@ public class MediaRouter2 {
if (removed) {
matchingController.release();
- notifyControllerReleased(matchingController);
+ notifyStopped(matchingController);
}
}
@@ -733,16 +746,16 @@ public class MediaRouter2 {
}
}
- private void notifyControllerUpdated(RoutingController controller) {
- for (ControllerCallbackRecord record: mControllerCallbackRecords) {
- record.mExecutor.execute(() -> record.mCallback.onControllerUpdated(controller));
+ private void notifyStopped(RoutingController controller) {
+ for (TransferCallbackRecord record: mTransferCallbackRecords) {
+ record.mExecutor.execute(
+ () -> record.mTransferCallback.onStopped(controller));
}
}
- private void notifyControllerReleased(RoutingController controller) {
- for (TransferCallbackRecord record: mTransferCallbackRecords) {
- record.mExecutor.execute(
- () -> record.mTransferCallback.onTransferred(controller, null));
+ private void notifyControllerUpdated(RoutingController controller) {
+ for (ControllerCallbackRecord record: mControllerCallbackRecords) {
+ record.mExecutor.execute(() -> record.mCallback.onControllerUpdated(controller));
}
}
@@ -783,20 +796,26 @@ public class MediaRouter2 {
* This can happen by calling {@link #transferTo(MediaRoute2Info)} or
* {@link RoutingController#release()}.
*
- * @param oldController the previous controller that controlled routing.
- * @param newController the new controller to control routing or {@code null} if the
- * previous controller is released.
+ * @param oldController the previous controller that controlled routing
+ * @param newController the new controller to control routing
* @see #transferTo(MediaRoute2Info)
*/
public void onTransferred(@NonNull RoutingController oldController,
- @Nullable RoutingController newController) {}
+ @NonNull RoutingController newController) {}
/**
* Called when {@link #transferTo(MediaRoute2Info)} failed.
*
- * @param requestedRoute the route info which was used for the transfer.
+ * @param requestedRoute the route info which was used for the transfer
*/
public void onTransferFailed(@NonNull MediaRoute2Info requestedRoute) {}
+
+ /**
+ * Called when a media routing stops. It can be stopped by a user or a provider.
+ *
+ * @param controller the controller that controlled the stopped media routing.
+ */
+ public void onStopped(@NonNull RoutingController controller) { }
}
/**
@@ -1181,7 +1200,7 @@ public class MediaRouter2 {
}
if (removed) {
- mHandler.post(() -> notifyControllerReleased(RoutingController.this));
+ mHandler.post(() -> notifyStopped(RoutingController.this));
}
if (stub != null) {
@@ -1378,9 +1397,9 @@ public class MediaRouter2 {
}
@Override
- public void notifySessionCreated(@Nullable RoutingSessionInfo sessionInfo, int requestId) {
+ public void notifySessionCreated(int requestId, @Nullable RoutingSessionInfo sessionInfo) {
mHandler.sendMessage(obtainMessage(MediaRouter2::createControllerOnHandler,
- MediaRouter2.this, sessionInfo, requestId));
+ MediaRouter2.this, requestId, sessionInfo));
}
@Override
diff --git a/media/java/android/media/MediaRouter2Manager.java b/media/java/android/media/MediaRouter2Manager.java
index fb45ae170461..11c9fe199521 100644
--- a/media/java/android/media/MediaRouter2Manager.java
+++ b/media/java/android/media/MediaRouter2Manager.java
@@ -304,13 +304,9 @@ public class MediaRouter2Manager {
* @see Callback#onTransferFailed(RoutingSessionInfo, MediaRoute2Info)
*/
public void transfer(@NonNull RoutingSessionInfo sessionInfo,
- @Nullable MediaRoute2Info route) {
+ @NonNull MediaRoute2Info route) {
Objects.requireNonNull(sessionInfo, "sessionInfo must not be null");
-
- if (route == null) {
- releaseSession(sessionInfo);
- return;
- }
+ Objects.requireNonNull(route, "route must not be null");
//TODO: Ignore unknown route.
if (sessionInfo.getTransferableRoutes().contains(route.getId())) {
@@ -333,11 +329,11 @@ public class MediaRouter2Manager {
try {
int requestId = mNextRequestId.getAndIncrement();
mMediaRouterService.requestCreateSessionWithManager(
- client, sessionInfo.getClientPackageName(), route, requestId);
- //TODO: release the previous session?
+ client, requestId, sessionInfo.getClientPackageName(), route);
} catch (RemoteException ex) {
Log.e(TAG, "Unable to select media route", ex);
}
+ releaseSession(sessionInfo);
}
}
@@ -377,7 +373,7 @@ public class MediaRouter2Manager {
if (client != null) {
try {
int requestId = mNextRequestId.getAndIncrement();
- mMediaRouterService.setRouteVolumeWithManager(client, route, volume, requestId);
+ mMediaRouterService.setRouteVolumeWithManager(client, requestId, route, volume);
} catch (RemoteException ex) {
Log.e(TAG, "Unable to send control request.", ex);
}
@@ -410,7 +406,7 @@ public class MediaRouter2Manager {
try {
int requestId = mNextRequestId.getAndIncrement();
mMediaRouterService.setSessionVolumeWithManager(
- client, sessionInfo.getId(), volume, requestId);
+ client, requestId, sessionInfo.getId(), volume);
} catch (RemoteException ex) {
Log.e(TAG, "Unable to send control request.", ex);
}
@@ -598,7 +594,7 @@ public class MediaRouter2Manager {
try {
int requestId = mNextRequestId.getAndIncrement();
mMediaRouterService.selectRouteWithManager(
- mClient, sessionInfo.getId(), route, requestId);
+ mClient, requestId, sessionInfo.getId(), route);
} catch (RemoteException ex) {
Log.e(TAG, "selectRoute: Failed to send a request.", ex);
}
@@ -643,7 +639,7 @@ public class MediaRouter2Manager {
try {
int requestId = mNextRequestId.getAndIncrement();
mMediaRouterService.deselectRouteWithManager(
- mClient, sessionInfo.getId(), route, requestId);
+ mClient, requestId, sessionInfo.getId(), route);
} catch (RemoteException ex) {
Log.e(TAG, "deselectRoute: Failed to send a request.", ex);
}
@@ -679,7 +675,7 @@ public class MediaRouter2Manager {
try {
int requestId = mNextRequestId.getAndIncrement();
mMediaRouterService.transferToRouteWithManager(
- mClient, sessionInfo.getId(), route, requestId);
+ mClient, requestId, sessionInfo.getId(), route);
} catch (RemoteException ex) {
Log.e(TAG, "transferToRoute: Failed to send a request.", ex);
}
@@ -707,7 +703,7 @@ public class MediaRouter2Manager {
try {
int requestId = mNextRequestId.getAndIncrement();
mMediaRouterService.releaseSessionWithManager(
- mClient, sessionInfo.getId(), requestId);
+ mClient, requestId, sessionInfo.getId());
} catch (RemoteException ex) {
Log.e(TAG, "releaseSession: Failed to send a request", ex);
}
diff --git a/media/java/android/media/RoutingSessionInfo.java b/media/java/android/media/RoutingSessionInfo.java
index 2276b6aba770..629cf1544bd1 100644
--- a/media/java/android/media/RoutingSessionInfo.java
+++ b/media/java/android/media/RoutingSessionInfo.java
@@ -74,7 +74,6 @@ public final class RoutingSessionInfo implements Parcelable {
mClientPackageName = builder.mClientPackageName;
mProviderId = builder.mProviderId;
- // TODO: Needs to check that the routes already have unique IDs.
mSelectedRoutes = Collections.unmodifiableList(
convertToUniqueRouteIds(builder.mSelectedRoutes));
mSelectableRoutes = Collections.unmodifiableList(
@@ -369,7 +368,6 @@ public final class RoutingSessionInfo implements Parcelable {
Bundle mControlHints;
boolean mIsSystemSession;
- //TODO: Remove this.
/**
* Constructor for builder to create {@link RoutingSessionInfo}.
* <p>
@@ -416,6 +414,14 @@ public final class RoutingSessionInfo implements Parcelable {
mDeselectableRoutes = new ArrayList<>(sessionInfo.mDeselectableRoutes);
mTransferableRoutes = new ArrayList<>(sessionInfo.mTransferableRoutes);
+ if (mProviderId != null) {
+ // They must have unique IDs.
+ mSelectedRoutes.replaceAll(MediaRouter2Utils::getOriginalId);
+ mSelectableRoutes.replaceAll(MediaRouter2Utils::getOriginalId);
+ mDeselectableRoutes.replaceAll(MediaRouter2Utils::getOriginalId);
+ mTransferableRoutes.replaceAll(MediaRouter2Utils::getOriginalId);
+ }
+
mVolumeHandling = sessionInfo.mVolumeHandling;
mVolumeMax = sessionInfo.mVolumeMax;
mVolume = sessionInfo.mVolume;
diff --git a/media/java/android/media/session/ISessionManager.aidl b/media/java/android/media/session/ISessionManager.aidl
index c8502a51ee23..6c1b2a6b60db 100644
--- a/media/java/android/media/session/ISessionManager.aidl
+++ b/media/java/android/media/session/ISessionManager.aidl
@@ -73,4 +73,6 @@ interface ISessionManager {
void setOnMediaKeyListener(in IOnMediaKeyListener listener);
boolean isTrusted(String controllerPackageName, int controllerPid, int controllerUid);
+ void setCustomMediaKeyDispatcherForTesting(String name);
+ void setCustomSessionPolicyProviderForTesting(String name);
}
diff --git a/media/java/android/media/session/MediaSessionManager.java b/media/java/android/media/session/MediaSessionManager.java
index 69be8b307950..4d01301859f3 100644
--- a/media/java/android/media/session/MediaSessionManager.java
+++ b/media/java/android/media/session/MediaSessionManager.java
@@ -45,6 +45,7 @@ import android.util.Log;
import android.view.KeyEvent;
import com.android.internal.annotations.GuardedBy;
+import com.android.internal.annotations.VisibleForTesting;
import java.util.ArrayList;
import java.util.HashMap;
@@ -61,7 +62,8 @@ import java.util.concurrent.Executor;
* @see MediaSession
* @see MediaController
*/
-// TODO: (jinpark) Add API for getting and setting session policies from MediaSessionService.
+// TODO: (jinpark) Add API for getting and setting session policies from MediaSessionService once
+// b/149006225 is fixed.
@SystemService(Context.MEDIA_SESSION_SERVICE)
public final class MediaSessionManager {
private static final String TAG = "SessionManager";
@@ -877,6 +879,40 @@ public final class MediaSessionManager {
}
/**
+ * Set the component name for the custom
+ * {@link com.android.server.media.MediaKeyDispatcher} class. Set to null to restore to the
+ * custom {@link com.android.server.media.MediaKeyDispatcher} class name retrieved from the
+ * config value.
+ *
+ * @hide
+ */
+ @VisibleForTesting
+ public void setCustomMediaKeyDispatcherForTesting(@Nullable String name) {
+ try {
+ mService.setCustomMediaKeyDispatcherForTesting(name);
+ } catch (RemoteException e) {
+ Log.e(TAG, "Failed to set custom media key dispatcher name", e);
+ }
+ }
+
+ /**
+ * Set the component name for the custom
+ * {@link com.android.server.media.SessionPolicyProvider} class. Set to null to restore to the
+ * custom {@link com.android.server.media.SessionPolicyProvider} class name retrieved from the
+ * config value.
+ *
+ * @hide
+ */
+ @VisibleForTesting
+ public void setCustomSessionPolicyProviderForTesting(@Nullable String name) {
+ try {
+ mService.setCustomSessionPolicyProviderForTesting(name);
+ } catch (RemoteException e) {
+ Log.e(TAG, "Failed to set custom session policy provider name", e);
+ }
+ }
+
+ /**
* Listens for changes to the list of active sessions. This can be added
* using {@link #addOnActiveSessionsChangedListener}.
*/
diff --git a/media/java/android/media/tv/TvInputManager.java b/media/java/android/media/tv/TvInputManager.java
index 6bf9e19ae079..f058a02ceb1e 100644
--- a/media/java/android/media/tv/TvInputManager.java
+++ b/media/java/android/media/tv/TvInputManager.java
@@ -16,6 +16,7 @@
package android.media.tv;
+import android.annotation.CallbackExecutor;
import android.annotation.IntDef;
import android.annotation.NonNull;
import android.annotation.Nullable;
@@ -27,6 +28,7 @@ import android.content.Intent;
import android.graphics.Rect;
import android.media.PlaybackParams;
import android.net.Uri;
+import android.os.Binder;
import android.os.Bundle;
import android.os.Handler;
import android.os.IBinder;
@@ -56,6 +58,7 @@ import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
+import java.util.concurrent.Executor;
/**
* Central system API to the overall TV input framework (TIF) architecture, which arbitrates
@@ -1743,8 +1746,8 @@ public final class TvInputManager {
* <p>Otherwise default priority will be applied.
*
* @param deviceId The device ID to acquire Hardware for.
- * @param callback A callback to receive updates on Hardware.
* @param info The TV input which will use the acquired Hardware.
+ * @param callback A callback to receive updates on Hardware.
* @return Hardware on success, {@code null} otherwise.
*
* @hide
@@ -1755,8 +1758,12 @@ public final class TvInputManager {
@NonNull final HardwareCallback callback) {
Preconditions.checkNotNull(info);
Preconditions.checkNotNull(callback);
- return acquireTvInputHardwareInternal(deviceId, info, callback, null,
- TvInputService.PRIORITY_HINT_USE_CASE_TYPE_LIVE);
+ return acquireTvInputHardwareInternal(deviceId, info, null,
+ TvInputService.PRIORITY_HINT_USE_CASE_TYPE_LIVE, new Executor() {
+ public void execute(Runnable r) {
+ r.run();
+ }
+ }, callback);
}
/**
@@ -1767,12 +1774,13 @@ public final class TvInputManager {
* request.
*
* @param deviceId The device ID to acquire Hardware for.
- * @param callback A callback to receive updates on Hardware.
* @param info The TV input which will use the acquired Hardware.
* @param tvInputSessionId a String returned to TIS when the session was created.
* {@see TvInputService#onCreateSession(String, String)}. If null, the client will be
* treated as a background app.
* @param priorityHint The use case of the client. {@see TvInputService#PriorityHintUseCaseType}
+ * @param executor the executor on which the listener would be invoked.
+ * @param callback A callback to receive updates on Hardware.
* @return Hardware on success, {@code null} otherwise. When the TRM decides to not grant
* resource, null is returned and the {@link IllegalStateException} is thrown with
* "No enough resources".
@@ -1783,28 +1791,40 @@ public final class TvInputManager {
@Nullable
@RequiresPermission(android.Manifest.permission.TV_INPUT_HARDWARE)
public Hardware acquireTvInputHardware(int deviceId, @NonNull TvInputInfo info,
- @NonNull final HardwareCallback callback,
@Nullable String tvInputSessionId,
- @TvInputService.PriorityHintUseCaseType int priorityHint) {
+ @TvInputService.PriorityHintUseCaseType int priorityHint,
+ @NonNull @CallbackExecutor Executor executor,
+ @NonNull final HardwareCallback callback) {
Preconditions.checkNotNull(info);
Preconditions.checkNotNull(callback);
- return acquireTvInputHardwareInternal(deviceId, info, callback,
- tvInputSessionId, priorityHint);
+ return acquireTvInputHardwareInternal(deviceId, info, tvInputSessionId, priorityHint,
+ executor, callback);
}
private Hardware acquireTvInputHardwareInternal(int deviceId, TvInputInfo info,
- final HardwareCallback callback, String tvInputSessionId, int priorityHint) {
+ String tvInputSessionId, int priorityHint,
+ Executor executor, final HardwareCallback callback) {
try {
return new Hardware(
mService.acquireTvInputHardware(deviceId, new ITvInputHardwareCallback.Stub() {
@Override
public void onReleased() {
- callback.onReleased();
+ final long identity = Binder.clearCallingIdentity();
+ try {
+ executor.execute(() -> callback.onReleased());
+ } finally {
+ Binder.restoreCallingIdentity(identity);
+ }
}
@Override
public void onStreamConfigChanged(TvStreamConfig[] configs) {
- callback.onStreamConfigChanged(configs);
+ final long identity = Binder.clearCallingIdentity();
+ try {
+ executor.execute(() -> callback.onStreamConfigChanged(configs));
+ } finally {
+ Binder.restoreCallingIdentity(identity);
+ }
}
}, info, mUserId, tvInputSessionId, priorityHint));
} catch (RemoteException e) {
diff --git a/media/java/android/media/tv/tuner/Lnb.java b/media/java/android/media/tv/tuner/Lnb.java
index a8d2cba46440..7932dcb06d88 100644
--- a/media/java/android/media/tv/tuner/Lnb.java
+++ b/media/java/android/media/tv/tuner/Lnb.java
@@ -154,6 +154,8 @@ public class Lnb implements AutoCloseable {
private native int nativeSendDiseqcMessage(byte[] message);
private native int nativeClose();
+ private long mNativeContext;
+
Lnb(int id) {
mId = id;
}
diff --git a/media/java/android/media/tv/tuner/Tuner.java b/media/java/android/media/tv/tuner/Tuner.java
index c79e72d86823..bcbc12b51a73 100644
--- a/media/java/android/media/tv/tuner/Tuner.java
+++ b/media/java/android/media/tv/tuner/Tuner.java
@@ -685,6 +685,8 @@ public class Tuner implements AutoCloseable {
/**
* Opens an LNB (low-noise block downconverter) object.
*
+ * <p>If there is an existing Lnb object, it will be replace by the newly opened one.
+ *
* @param executor the executor on which callback will be invoked. The default event handler
* executor is used if it's {@code null}.
* @param cb the callback to receive notifications from LNB.
diff --git a/media/java/android/media/tv/tuner/dvr/DvrPlayback.java b/media/java/android/media/tv/tuner/dvr/DvrPlayback.java
index 7c15bb74a94b..dbd9db4b6a45 100644
--- a/media/java/android/media/tv/tuner/dvr/DvrPlayback.java
+++ b/media/java/android/media/tv/tuner/dvr/DvrPlayback.java
@@ -89,6 +89,9 @@ public class DvrPlayback implements AutoCloseable {
/**
* Attaches a filter to DVR interface for recording.
*
+ * <p>There can be multiple filters attached. Attached filters are independent, so the order
+ * doesn't matter.
+ *
* @param filter the filter to be attached.
* @return result status of the operation.
*/
@@ -135,6 +138,7 @@ public class DvrPlayback implements AutoCloseable {
* Stops DVR.
*
* <p>Stops consuming playback data or producing data for recording.
+ * <p>Does nothing if the filter is stopped or not started.</p>
*
* @return result status of the operation.
*/
@@ -164,9 +168,14 @@ public class DvrPlayback implements AutoCloseable {
}
/**
- * Sets file descriptor to read/write data.
+ * Sets file descriptor to read data.
+ *
+ * <p>When a read operation of the filter object is happening, this method should not be
+ * called.
*
- * @param fd the file descriptor to read/write data.
+ * @param fd the file descriptor to read data.
+ * @see #read(long)
+ * @see #read(byte[], long, long)
*/
public void setFileDescriptor(@NonNull ParcelFileDescriptor fd) {
nativeSetFileDescriptor(fd.getFd());
diff --git a/media/java/android/media/tv/tuner/dvr/DvrRecorder.java b/media/java/android/media/tv/tuner/dvr/DvrRecorder.java
index 52ef5e63389f..c1c6c624454e 100644
--- a/media/java/android/media/tv/tuner/dvr/DvrRecorder.java
+++ b/media/java/android/media/tv/tuner/dvr/DvrRecorder.java
@@ -50,6 +50,9 @@ public class DvrRecorder implements AutoCloseable {
/**
* Attaches a filter to DVR interface for recording.
*
+ * <p>There can be multiple filters attached. Attached filters are independent, so the order
+ * doesn't matter.
+ *
* @param filter the filter to be attached.
* @return result status of the operation.
*/
@@ -84,6 +87,7 @@ public class DvrRecorder implements AutoCloseable {
* Starts DVR.
*
* <p>Starts consuming playback data or producing data for recording.
+ * <p>Does nothing if the filter is stopped or not started.</p>
*
* @return result status of the operation.
*/
@@ -125,9 +129,14 @@ public class DvrRecorder implements AutoCloseable {
}
/**
- * Sets file descriptor to read/write data.
+ * Sets file descriptor to write data.
+ *
+ * <p>When a write operation of the filter object is happening, this method should not be
+ * called.
*
- * @param fd the file descriptor to read/write data.
+ * @param fd the file descriptor to write data.
+ * @see #write(long)
+ * @see #write(byte[], long, long)
*/
public void setFileDescriptor(@NonNull ParcelFileDescriptor fd) {
nativeSetFileDescriptor(fd.getFd());
diff --git a/media/java/android/media/tv/tuner/filter/AlpFilterConfiguration.java b/media/java/android/media/tv/tuner/filter/AlpFilterConfiguration.java
index 064ab80efb5c..7b2949472396 100644
--- a/media/java/android/media/tv/tuner/filter/AlpFilterConfiguration.java
+++ b/media/java/android/media/tv/tuner/filter/AlpFilterConfiguration.java
@@ -34,6 +34,27 @@ import java.lang.annotation.RetentionPolicy;
*/
@SystemApi
public class AlpFilterConfiguration extends FilterConfiguration {
+ /**
+ * IPv4 packet type.
+ */
+ public static final int PACKET_TYPE_IPV4 = 0;
+ /**
+ * Compressed packet type.
+ */
+ public static final int PACKET_TYPE_COMPRESSED = 2;
+ /**
+ * Signaling packet type.
+ */
+ public static final int PACKET_TYPE_SIGNALING = 4;
+ /**
+ * Extension packet type.
+ */
+ public static final int PACKET_TYPE_EXTENSION = 6;
+ /**
+ * MPEG-2 TS packet type.
+ */
+ public static final int PACKET_TYPE_MPEG2_TS = 7;
+
/** @hide */
@Retention(RetentionPolicy.SOURCE)
@IntDef(prefix = "LENGTH_TYPE_", value =
@@ -73,8 +94,9 @@ public class AlpFilterConfiguration extends FilterConfiguration {
/**
* Gets packet type.
+ *
+ * <p>The meaning of each packet type value is shown in ATSC A/330:2019 table 5.2.
*/
- @FilterConfiguration.PacketType
public int getPacketType() {
return mPacketType;
}
@@ -110,9 +132,11 @@ public class AlpFilterConfiguration extends FilterConfiguration {
/**
* Sets packet type.
+ *
+ * <p>The meaning of each packet type value is shown in ATSC A/330:2019 table 5.2.
*/
@NonNull
- public Builder setPacketType(@FilterConfiguration.PacketType int packetType) {
+ public Builder setPacketType(int packetType) {
mPacketType = packetType;
return this;
}
diff --git a/media/java/android/media/tv/tuner/filter/Filter.java b/media/java/android/media/tv/tuner/filter/Filter.java
index b63c6b40db0a..4777fe861420 100644
--- a/media/java/android/media/tv/tuner/filter/Filter.java
+++ b/media/java/android/media/tv/tuner/filter/Filter.java
@@ -45,6 +45,10 @@ public class Filter implements AutoCloseable {
public @interface Type {}
/**
+ * Undefined filter type.
+ */
+ public static final int TYPE_UNDEFINED = 0;
+ /**
* TS filter type.
*/
public static final int TYPE_TS = Constants.DemuxFilterMainType.TS;
@@ -249,7 +253,6 @@ public class Filter implements AutoCloseable {
/**
* Gets the filter Id.
*/
- @Result
public int getId() {
return nativeGetId();
}
@@ -274,6 +277,8 @@ public class Filter implements AutoCloseable {
/**
* Starts filtering data.
*
+ * <p>Does nothing if the filter is already started.
+ *
* @return result status of the operation.
*/
@Result
@@ -285,6 +290,8 @@ public class Filter implements AutoCloseable {
/**
* Stops filtering data.
*
+ * <p>Does nothing if the filter is stopped or not started.
+ *
* @return result status of the operation.
*/
@Result
@@ -313,14 +320,13 @@ public class Filter implements AutoCloseable {
* @param size the maximum number of bytes to read.
* @return the number of bytes read.
*/
- @Result
public int read(@NonNull byte[] buffer, @BytesLong long offset, @BytesLong long size) {
size = Math.min(size, buffer.length - offset);
return nativeRead(buffer, offset, size);
}
/**
- * Releases the Filter instance.
+ * Stops filtering data and releases the Filter instance.
*/
@Override
public void close() {
diff --git a/media/java/android/media/tv/tuner/filter/FilterConfiguration.java b/media/java/android/media/tv/tuner/filter/FilterConfiguration.java
index c1d2275d3bdb..a8c9356b570a 100644
--- a/media/java/android/media/tv/tuner/filter/FilterConfiguration.java
+++ b/media/java/android/media/tv/tuner/filter/FilterConfiguration.java
@@ -16,14 +16,10 @@
package android.media.tv.tuner.filter;
-import android.annotation.IntDef;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.annotation.SystemApi;
-import java.lang.annotation.Retention;
-import java.lang.annotation.RetentionPolicy;
-
/**
* Filter configuration used to configure filters.
*
@@ -32,26 +28,6 @@ import java.lang.annotation.RetentionPolicy;
@SystemApi
public abstract class FilterConfiguration {
- /** @hide */
- @IntDef(prefix = "PACKET_TYPE_", value =
- {PACKET_TYPE_IPV4, PACKET_TYPE_COMPRESSED, PACKET_TYPE_SIGNALING})
- @Retention(RetentionPolicy.SOURCE)
- public @interface PacketType {}
-
- /**
- * IP v4 packet type.
- */
- public static final int PACKET_TYPE_IPV4 = 0;
- /**
- * Compressed packet type.
- */
- public static final int PACKET_TYPE_COMPRESSED = 2;
- /**
- * Signaling packet type.
- */
- public static final int PACKET_TYPE_SIGNALING = 4;
-
-
@Nullable
/* package */ final Settings mSettings;
diff --git a/media/java/android/media/tv/tuner/filter/TlvFilterConfiguration.java b/media/java/android/media/tv/tuner/filter/TlvFilterConfiguration.java
index 3d83a74a500c..ac4fc8313460 100644
--- a/media/java/android/media/tv/tuner/filter/TlvFilterConfiguration.java
+++ b/media/java/android/media/tv/tuner/filter/TlvFilterConfiguration.java
@@ -29,6 +29,27 @@ import android.media.tv.tuner.TunerUtils;
*/
@SystemApi
public class TlvFilterConfiguration extends FilterConfiguration {
+ /**
+ * IPv4 packet type.
+ */
+ public static final int PACKET_TYPE_IPV4 = 0x01;
+ /**
+ * IPv6 packet type.
+ */
+ public static final int PACKET_TYPE_IPV6 = 0x02;
+ /**
+ * Compressed packet type.
+ */
+ public static final int PACKET_TYPE_COMPRESSED = 0x03;
+ /**
+ * Signaling packet type.
+ */
+ public static final int PACKET_TYPE_SIGNALING = 0xFE;
+ /**
+ * NULL packet type.
+ */
+ public static final int PACKET_TYPE_NULL = 0xFF;
+
private final int mPacketType;
private final boolean mIsCompressedIpPacket;
private final boolean mPassthrough;
@@ -48,8 +69,9 @@ public class TlvFilterConfiguration extends FilterConfiguration {
/**
* Gets packet type.
+ *
+ * <p>The description of each packet type value is shown in ITU-R BT.1869 table 2.
*/
- @FilterConfiguration.PacketType
public int getPacketType() {
return mPacketType;
}
@@ -96,9 +118,11 @@ public class TlvFilterConfiguration extends FilterConfiguration {
/**
* Sets packet type.
+ *
+ * <p>The description of each packet type value is shown in ITU-R BT.1869 table 2.
*/
@NonNull
- public Builder setPacketType(@FilterConfiguration.PacketType int packetType) {
+ public Builder setPacketType(int packetType) {
mPacketType = packetType;
return this;
}
diff --git a/media/jni/android_media_MediaCodec.cpp b/media/jni/android_media_MediaCodec.cpp
index 737c95d73e6c..893e51654b68 100644
--- a/media/jni/android_media_MediaCodec.cpp
+++ b/media/jni/android_media_MediaCodec.cpp
@@ -242,13 +242,6 @@ void JMediaCodec::release() {
});
}
-void JMediaCodec::releaseAsync() {
- if (mCodec != NULL) {
- mCodec->releaseAsync();
- }
- mInitStatus = NO_INIT;
-}
-
JMediaCodec::~JMediaCodec() {
if (mLooper != NULL) {
/* MediaCodec and looper should have been released explicitly already
@@ -1131,10 +1124,7 @@ static sp<JMediaCodec> getMediaCodec(JNIEnv *env, jobject thiz) {
}
static void android_media_MediaCodec_release(JNIEnv *env, jobject thiz) {
- sp<JMediaCodec> codec = getMediaCodec(env, thiz);
- if (codec != NULL) {
- codec->releaseAsync();
- }
+ setMediaCodec(env, thiz, NULL);
}
static void throwCodecException(JNIEnv *env, status_t err, int32_t actionCode, const char *msg) {
@@ -2807,7 +2797,7 @@ static void android_media_MediaCodec_native_setup(
static void android_media_MediaCodec_native_finalize(
JNIEnv *env, jobject thiz) {
- setMediaCodec(env, thiz, NULL);
+ android_media_MediaCodec_release(env, thiz);
}
// MediaCodec.LinearBlock
diff --git a/media/jni/android_media_MediaCodec.h b/media/jni/android_media_MediaCodec.h
index 400ce1bc98e7..8899fee7a73d 100644
--- a/media/jni/android_media_MediaCodec.h
+++ b/media/jni/android_media_MediaCodec.h
@@ -61,7 +61,6 @@ struct JMediaCodec : public AHandler {
void registerSelf();
void release();
- void releaseAsync();
status_t enableOnFrameRenderedListener(jboolean enable);
diff --git a/media/jni/android_media_tv_Tuner.cpp b/media/jni/android_media_tv_Tuner.cpp
index 0c07c265d0dd..01f068a05fc3 100644
--- a/media/jni/android_media_tv_Tuner.cpp
+++ b/media/jni/android_media_tv_Tuner.cpp
@@ -126,11 +126,15 @@ using ::android::hardware::tv::tuner::V1_0::FrontendIsdbtSettings;
using ::android::hardware::tv::tuner::V1_0::FrontendScanAtsc3PlpInfo;
using ::android::hardware::tv::tuner::V1_0::FrontendType;
using ::android::hardware::tv::tuner::V1_0::ITuner;
+using ::android::hardware::tv::tuner::V1_0::LnbPosition;
+using ::android::hardware::tv::tuner::V1_0::LnbTone;
+using ::android::hardware::tv::tuner::V1_0::LnbVoltage;
using ::android::hardware::tv::tuner::V1_0::PlaybackSettings;
using ::android::hardware::tv::tuner::V1_0::RecordSettings;
struct fields_t {
jfieldID tunerContext;
+ jfieldID lnbContext;
jfieldID filterContext;
jfieldID timeFilterContext;
jfieldID descramblerContext;
@@ -173,6 +177,23 @@ Return<void> LnbCallback::onDiseqcMessage(const hidl_vec<uint8_t>& /*diseqcMessa
return Void();
}
+/////////////// Lnb ///////////////////////
+
+Lnb::Lnb(sp<ILnb> sp, jobject obj) : mLnbSp(sp) {
+ JNIEnv *env = AndroidRuntime::getJNIEnv();
+ mLnbObj = env->NewWeakGlobalRef(obj);
+}
+
+Lnb::~Lnb() {
+ JNIEnv *env = AndroidRuntime::getJNIEnv();
+ env->DeleteWeakGlobalRef(mLnbObj);
+ mLnbObj = NULL;
+}
+
+sp<ILnb> Lnb::getILnb() {
+ return mLnbSp;
+}
+
/////////////// DvrCallback ///////////////////////
Return<void> DvrCallback::onRecordStatus(RecordStatus /*status*/) {
ALOGD("DvrCallback::onRecordStatus");
@@ -1026,24 +1047,29 @@ jobject JTuner::getLnbIds() {
}
jobject JTuner::openLnbById(int id) {
- sp<ILnb> lnbSp;
+ sp<ILnb> iLnbSp;
mTuner->openLnbById(id, [&](Result, const sp<ILnb>& lnb) {
- lnbSp = lnb;
+ iLnbSp = lnb;
});
- if (lnbSp == nullptr) {
+ if (iLnbSp == nullptr) {
ALOGE("Failed to open lnb");
return NULL;
}
- mLnb = lnbSp;
+ mLnb = iLnbSp;
sp<LnbCallback> lnbCb = new LnbCallback(mObject, id);
mLnb->setCallback(lnbCb);
JNIEnv *env = AndroidRuntime::getJNIEnv();
- return env->NewObject(
+ jobject lnbObj = env->NewObject(
env->FindClass("android/media/tv/tuner/Lnb"),
gFields.lnbInitID,
- mObject,
- id);
+ (jint) id);
+
+ sp<Lnb> lnbSp = new Lnb(iLnbSp, lnbObj);
+ lnbSp->incStrong(lnbObj);
+ env->SetLongField(lnbObj, gFields.lnbContext, (jlong) lnbSp.get());
+
+ return lnbObj;
}
int JTuner::tune(const FrontendSettings& settings) {
@@ -1845,6 +1871,7 @@ static void android_media_tv_Tuner_native_init(JNIEnv *env) {
env->GetMethodID(frontendClazz, "<init>", "(Landroid/media/tv/tuner/Tuner;I)V");
jclass lnbClazz = env->FindClass("android/media/tv/tuner/Lnb");
+ gFields.lnbContext = env->GetFieldID(lnbClazz, "mNativeContext", "J");
gFields.lnbInitID =
env->GetMethodID(lnbClazz, "<init>", "(I)V");
@@ -2684,20 +2711,35 @@ static int android_media_tv_Tuner_close_dvr(JNIEnv*, jobject) {
return 0;
}
-static int android_media_tv_Tuner_lnb_set_voltage(JNIEnv*, jobject, jint) {
- return 0;
+static sp<Lnb> getLnb(JNIEnv *env, jobject lnb) {
+ return (Lnb *)env->GetLongField(lnb, gFields.lnbContext);
}
-static int android_media_tv_Tuner_lnb_set_tone(JNIEnv*, jobject, jint) {
- return 0;
+static jint android_media_tv_Tuner_lnb_set_voltage(JNIEnv* env, jobject lnb, jint voltage) {
+ sp<ILnb> iLnbSp = getLnb(env, lnb)->getILnb();
+ Result r = iLnbSp->setVoltage(static_cast<LnbVoltage>(voltage));
+ return (jint) r;
}
-static int android_media_tv_Tuner_lnb_set_position(JNIEnv*, jobject, jint) {
- return 0;
+static int android_media_tv_Tuner_lnb_set_tone(JNIEnv* env, jobject lnb, jint tone) {
+ sp<ILnb> iLnbSp = getLnb(env, lnb)->getILnb();
+ Result r = iLnbSp->setTone(static_cast<LnbTone>(tone));
+ return (jint) r;
}
-static int android_media_tv_Tuner_lnb_send_diseqc_msg(JNIEnv*, jobject, jbyteArray) {
- return 0;
+static int android_media_tv_Tuner_lnb_set_position(JNIEnv* env, jobject lnb, jint position) {
+ sp<ILnb> iLnbSp = getLnb(env, lnb)->getILnb();
+ Result r = iLnbSp->setSatellitePosition(static_cast<LnbPosition>(position));
+ return (jint) r;
+}
+
+static int android_media_tv_Tuner_lnb_send_diseqc_msg(JNIEnv* env, jobject lnb, jbyteArray msg) {
+ sp<ILnb> iLnbSp = getLnb(env, lnb)->getILnb();
+ int size = env->GetArrayLength(msg);
+ std::vector<uint8_t> v(size);
+ env->GetByteArrayRegion(msg, 0, size, reinterpret_cast<jbyte*>(&v[0]));
+ Result r = iLnbSp->sendDiseqcMessage(v);
+ return (jint) r;
}
static int android_media_tv_Tuner_close_lnb(JNIEnv*, jobject) {
diff --git a/media/jni/android_media_tv_Tuner.h b/media/jni/android_media_tv_Tuner.h
index 6a67ebcd1b31..d3298a851fdd 100644
--- a/media/jni/android_media_tv_Tuner.h
+++ b/media/jni/android_media_tv_Tuner.h
@@ -75,6 +75,14 @@ struct LnbCallback : public ILnbCallback {
LnbId mId;
};
+struct Lnb : public RefBase {
+ Lnb(sp<ILnb> sp, jobject obj);
+ ~Lnb();
+ sp<ILnb> getILnb();
+ sp<ILnb> mLnbSp;
+ jweak mLnbObj;
+};
+
struct DvrCallback : public IDvrCallback {
virtual Return<void> onRecordStatus(RecordStatus status);
virtual Return<void> onPlaybackStatus(PlaybackStatus status);
diff --git a/media/tests/MediaRouter/src/com/android/mediaroutertest/RoutingSessionInfoTest.java b/media/tests/MediaRouter/src/com/android/mediaroutertest/RoutingSessionInfoTest.java
new file mode 100644
index 000000000000..31f240d87f94
--- /dev/null
+++ b/media/tests/MediaRouter/src/com/android/mediaroutertest/RoutingSessionInfoTest.java
@@ -0,0 +1,96 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.mediaroutertest;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotEquals;
+
+import android.media.RoutingSessionInfo;
+import android.support.test.filters.SmallTest;
+import android.support.test.runner.AndroidJUnit4;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+/**
+ * Tests {@link RoutingSessionInfo} and its {@link RoutingSessionInfo.Builder builder}.
+ */
+@RunWith(AndroidJUnit4.class)
+@SmallTest
+public class RoutingSessionInfoTest {
+ public static final String TEST_ID = "test_id";
+ public static final String TEST_CLIENT_PACKAGE_NAME = "com.test.client.package.name";
+ public static final String TEST_NAME = "test_name";
+
+ public static final String TEST_ROUTE_ID_0 = "test_route_type_0";
+ public static final String TEST_ROUTE_ID_2 = "test_route_type_2";
+ public static final String TEST_ROUTE_ID_4 = "test_route_type_4";
+ public static final String TEST_ROUTE_ID_6 = "test_route_type_6";
+
+ public static final String TEST_PROVIDER_ID = "test_provider_id";
+ public static final String TEST_OTHER_PROVIDER_ID = "test_other_provider_id";
+
+ // Tests if route IDs are changed properly according to provider ID.
+ @Test
+ public void testProviderId() {
+ RoutingSessionInfo sessionInfo = new RoutingSessionInfo.Builder(
+ TEST_ID, TEST_CLIENT_PACKAGE_NAME)
+ .setName(TEST_NAME)
+ .addSelectedRoute(TEST_ROUTE_ID_0)
+ .addSelectableRoute(TEST_ROUTE_ID_2)
+ .addDeselectableRoute(TEST_ROUTE_ID_4)
+ .addTransferableRoute(TEST_ROUTE_ID_6)
+ .build();
+
+ RoutingSessionInfo sessionInfoWithProviderId = new RoutingSessionInfo.Builder(sessionInfo)
+ .setProviderId(TEST_PROVIDER_ID).build();
+
+ assertNotEquals(sessionInfo.getSelectedRoutes(),
+ sessionInfoWithProviderId.getSelectedRoutes());
+ assertNotEquals(sessionInfo.getSelectableRoutes(),
+ sessionInfoWithProviderId.getSelectableRoutes());
+ assertNotEquals(sessionInfo.getDeselectableRoutes(),
+ sessionInfoWithProviderId.getDeselectableRoutes());
+ assertNotEquals(sessionInfo.getTransferableRoutes(),
+ sessionInfoWithProviderId.getTransferableRoutes());
+
+ RoutingSessionInfo sessionInfoWithOtherProviderId =
+ new RoutingSessionInfo.Builder(sessionInfoWithProviderId)
+ .setProviderId(TEST_OTHER_PROVIDER_ID).build();
+
+ assertNotEquals(sessionInfoWithOtherProviderId.getSelectedRoutes(),
+ sessionInfoWithProviderId.getSelectedRoutes());
+ assertNotEquals(sessionInfoWithOtherProviderId.getSelectableRoutes(),
+ sessionInfoWithProviderId.getSelectableRoutes());
+ assertNotEquals(sessionInfoWithOtherProviderId.getDeselectableRoutes(),
+ sessionInfoWithProviderId.getDeselectableRoutes());
+ assertNotEquals(sessionInfoWithOtherProviderId.getTransferableRoutes(),
+ sessionInfoWithProviderId.getTransferableRoutes());
+
+ RoutingSessionInfo sessionInfoWithProviderId2 =
+ new RoutingSessionInfo.Builder(sessionInfoWithProviderId).build();
+
+ assertEquals(sessionInfoWithProviderId2.getSelectedRoutes(),
+ sessionInfoWithProviderId.getSelectedRoutes());
+ assertEquals(sessionInfoWithProviderId2.getSelectableRoutes(),
+ sessionInfoWithProviderId.getSelectableRoutes());
+ assertEquals(sessionInfoWithProviderId2.getDeselectableRoutes(),
+ sessionInfoWithProviderId.getDeselectableRoutes());
+ assertEquals(sessionInfoWithProviderId2.getTransferableRoutes(),
+ sessionInfoWithProviderId.getTransferableRoutes());
+ }
+}
diff --git a/media/tests/MediaRouter/src/com/android/mediaroutertest/SampleMediaRoute2ProviderService.java b/media/tests/MediaRouter/src/com/android/mediaroutertest/SampleMediaRoute2ProviderService.java
index 0e7c7fc499b4..f05d8ad79dee 100644
--- a/media/tests/MediaRouter/src/com/android/mediaroutertest/SampleMediaRoute2ProviderService.java
+++ b/media/tests/MediaRouter/src/com/android/mediaroutertest/SampleMediaRoute2ProviderService.java
@@ -216,8 +216,7 @@ public class SampleMediaRoute2ProviderService extends MediaRoute2ProviderService
@Nullable Bundle sessionHints) {
MediaRoute2Info route = mRoutes.get(routeId);
if (route == null || TextUtils.equals(ROUTE_ID3_SESSION_CREATION_FAILED, routeId)) {
- // Tell the router that session cannot be created by passing null as sessionInfo.
- notifySessionCreationFailed(requestId);
+ notifyRequestFailed(requestId, REASON_UNKNOWN_ERROR);
return;
}
maybeDeselectRoute(routeId);
@@ -240,7 +239,7 @@ public class SampleMediaRoute2ProviderService extends MediaRoute2ProviderService
// Set control hints with given sessionHints
.setControlHints(sessionHints)
.build();
- notifySessionCreated(sessionInfo, requestId);
+ notifySessionCreated(requestId, sessionInfo);
publishRoutes();
}
diff --git a/packages/CarSystemUI/res/layout/car_fullscreen_user_switcher.xml b/packages/CarSystemUI/res/layout/car_fullscreen_user_switcher.xml
index 2fe9d21b0489..6ecab5182f13 100644
--- a/packages/CarSystemUI/res/layout/car_fullscreen_user_switcher.xml
+++ b/packages/CarSystemUI/res/layout/car_fullscreen_user_switcher.xml
@@ -16,14 +16,15 @@
-->
<FrameLayout
xmlns:android="http://schemas.android.com/apk/res/android"
+ android:id="@+id/fullscreen_user_switcher"
android:layout_width="match_parent"
- android:layout_height="match_parent"
- android:fitsSystemWindows="true">
+ android:layout_height="match_parent">
<LinearLayout
android:id="@+id/container"
android:layout_width="match_parent"
android:layout_height="match_parent"
+ android:layout_alignParentTop="true"
android:orientation="vertical">
<include
@@ -31,10 +32,11 @@
android:layout_alignParentTop="true"
android:theme="@android:style/Theme"/>
+
<FrameLayout
android:layout_width="match_parent"
android:layout_height="match_parent">
- <com.android.systemui.statusbar.car.UserGridRecyclerView
+ <com.android.systemui.car.userswitcher.UserGridRecyclerView
android:id="@+id/user_grid"
android:layout_width="match_parent"
android:layout_height="wrap_content"
diff --git a/packages/CarSystemUI/res/layout/car_qs_panel.xml b/packages/CarSystemUI/res/layout/car_qs_panel.xml
index 9c598d71bd22..0c6f322ca261 100644
--- a/packages/CarSystemUI/res/layout/car_qs_panel.xml
+++ b/packages/CarSystemUI/res/layout/car_qs_panel.xml
@@ -33,7 +33,7 @@
android:layout_width="match_parent"
android:layout_height="@dimen/car_user_switcher_container_height">
- <com.android.systemui.statusbar.car.UserGridRecyclerView
+ <com.android.systemui.car.userswitcher.UserGridRecyclerView
android:id="@+id/user_grid"
android:layout_width="match_parent"
android:layout_height="match_parent"/>
diff --git a/packages/CarSystemUI/res/layout/super_notification_shade.xml b/packages/CarSystemUI/res/layout/super_notification_shade.xml
index cb65045533f8..e36d8caa67f3 100644
--- a/packages/CarSystemUI/res/layout/super_notification_shade.xml
+++ b/packages/CarSystemUI/res/layout/super_notification_shade.xml
@@ -72,11 +72,6 @@
android:layout_marginBottom="@dimen/navigation_bar_height"
android:visibility="invisible"/>
- <include layout="@layout/headsup_container"
- android:layout_width="match_parent"
- android:layout_height="match_parent"
- android:visibility="invisible"/>
-
<include layout="@layout/status_bar_expanded"
android:layout_width="match_parent"
android:layout_height="match_parent"
diff --git a/packages/CarSystemUI/res/layout/sysui_primary_window.xml b/packages/CarSystemUI/res/layout/sysui_overlay_window.xml
index cc36e87eb480..cc36e87eb480 100644
--- a/packages/CarSystemUI/res/layout/sysui_primary_window.xml
+++ b/packages/CarSystemUI/res/layout/sysui_overlay_window.xml
diff --git a/packages/CarSystemUI/res/values/config.xml b/packages/CarSystemUI/res/values/config.xml
index 825b2813d47d..aaa65de2fa1d 100644
--- a/packages/CarSystemUI/res/values/config.xml
+++ b/packages/CarSystemUI/res/values/config.xml
@@ -58,6 +58,11 @@
to a constant alpha percent value using the initial alpha. -->
<integer name="config_finalNotificationBackgroundAlpha">100</integer>
+ <!-- Car System UI's OverlayViewsMediator-->
+ <string-array name="config_carSystemUIOverlayViewsMediators" translatable="false">
+ <item>com.android.systemui.car.userswitcher.FullscreenUserSwitcherViewMediator</item>
+ </string-array>
+
<!-- SystemUI Services: The classes of the stuff to start. -->
<string-array name="config_systemUIServiceComponents" translatable="false">
<item>com.android.systemui.util.NotificationChannels</item>
@@ -85,5 +90,6 @@
<item>com.android.systemui.navigationbar.car.CarNavigationBar</item>
<item>com.android.systemui.toast.ToastUI</item>
<item>com.android.systemui.voicerecognition.car.ConnectedDeviceVoiceRecognitionNotifier</item>
+ <item>com.android.systemui.window.SystemUIOverlayWindowManager</item>
</string-array>
</resources>
diff --git a/packages/CarSystemUI/src/com/android/systemui/CarSystemUIBinder.java b/packages/CarSystemUI/src/com/android/systemui/CarSystemUIBinder.java
index 8f9d7ed8c9b7..59fa9d09c9ee 100644
--- a/packages/CarSystemUI/src/com/android/systemui/CarSystemUIBinder.java
+++ b/packages/CarSystemUI/src/com/android/systemui/CarSystemUIBinder.java
@@ -18,6 +18,7 @@ package com.android.systemui;
import com.android.systemui.biometrics.AuthController;
import com.android.systemui.bubbles.dagger.BubbleModule;
+import com.android.systemui.car.notification.CarNotificationModule;
import com.android.systemui.globalactions.GlobalActionsComponent;
import com.android.systemui.keyguard.KeyguardViewMediator;
import com.android.systemui.keyguard.dagger.KeyguardModule;
@@ -39,6 +40,8 @@ import com.android.systemui.toast.ToastUI;
import com.android.systemui.util.leak.GarbageMonitor;
import com.android.systemui.voicerecognition.car.ConnectedDeviceVoiceRecognitionNotifier;
import com.android.systemui.volume.VolumeUI;
+import com.android.systemui.window.OverlayWindowModule;
+import com.android.systemui.window.SystemUIOverlayWindowManager;
import dagger.Binds;
import dagger.Module;
@@ -47,7 +50,8 @@ import dagger.multibindings.IntoMap;
/** Binder for car specific {@link SystemUI} modules. */
@Module(includes = {RecentsModule.class, CarStatusBarModule.class, NotificationsModule.class,
- BubbleModule.class, KeyguardModule.class})
+ BubbleModule.class, KeyguardModule.class, OverlayWindowModule.class,
+ CarNotificationModule.class})
public abstract class CarSystemUIBinder {
/** Inject into AuthController. */
@Binds
@@ -182,4 +186,10 @@ public abstract class CarSystemUIBinder {
@ClassKey(ConnectedDeviceVoiceRecognitionNotifier.class)
public abstract SystemUI bindConnectedDeviceVoiceRecognitionNotifier(
ConnectedDeviceVoiceRecognitionNotifier sysui);
+
+ /** Inject into SystemUIOverlayWindowManager. */
+ @Binds
+ @IntoMap
+ @ClassKey(SystemUIOverlayWindowManager.class)
+ public abstract SystemUI bindSystemUIPrimaryWindowManager(SystemUIOverlayWindowManager sysui);
}
diff --git a/packages/CarSystemUI/src/com/android/systemui/CarSystemUIModule.java b/packages/CarSystemUI/src/com/android/systemui/CarSystemUIModule.java
index a0d5a1bf6978..140c075552c7 100644
--- a/packages/CarSystemUI/src/com/android/systemui/CarSystemUIModule.java
+++ b/packages/CarSystemUI/src/com/android/systemui/CarSystemUIModule.java
@@ -21,6 +21,8 @@ import static com.android.systemui.Dependency.LEAK_REPORT_EMAIL_NAME;
import android.content.Context;
+import com.android.keyguard.KeyguardViewController;
+import com.android.systemui.car.CarDeviceProvisionedController;
import com.android.systemui.car.CarDeviceProvisionedControllerImpl;
import com.android.systemui.car.CarNotificationInterruptionStateProvider;
import com.android.systemui.dagger.SystemUIRootComponent;
@@ -47,6 +49,8 @@ import com.android.systemui.statusbar.phone.NotificationGroupManager;
import com.android.systemui.statusbar.phone.ShadeController;
import com.android.systemui.statusbar.phone.StatusBar;
import com.android.systemui.statusbar.phone.StatusBarKeyguardViewManager;
+import com.android.systemui.statusbar.policy.BatteryController;
+import com.android.systemui.statusbar.policy.BatteryControllerImpl;
import com.android.systemui.statusbar.policy.ConfigurationController;
import com.android.systemui.statusbar.policy.DeviceProvisionedController;
import com.android.systemui.statusbar.policy.HeadsUpManager;
@@ -104,6 +108,11 @@ abstract class CarSystemUIModule {
NotificationLockscreenUserManagerImpl notificationLockscreenUserManager);
@Binds
+ @Singleton
+ public abstract BatteryController provideBatteryController(
+ BatteryControllerImpl controllerImpl);
+
+ @Binds
abstract DockManager bindDockManager(DockManagerImpl dockManager);
@Binds
@@ -136,6 +145,14 @@ abstract class CarSystemUIModule {
CarStatusBarKeyguardViewManager keyguardViewManager);
@Binds
+ abstract KeyguardViewController bindKeyguardViewController(
+ CarStatusBarKeyguardViewManager keyguardViewManager);
+
+ @Binds
abstract DeviceProvisionedController bindDeviceProvisionedController(
CarDeviceProvisionedControllerImpl deviceProvisionedController);
+
+ @Binds
+ abstract CarDeviceProvisionedController bindCarDeviceProvisionedController(
+ CarDeviceProvisionedControllerImpl deviceProvisionedController);
}
diff --git a/packages/CarSystemUI/src/com/android/systemui/car/CarDeviceProvisionedControllerImpl.java b/packages/CarSystemUI/src/com/android/systemui/car/CarDeviceProvisionedControllerImpl.java
index 38d5211bd0d4..09e62d240a72 100644
--- a/packages/CarSystemUI/src/com/android/systemui/car/CarDeviceProvisionedControllerImpl.java
+++ b/packages/CarSystemUI/src/com/android/systemui/car/CarDeviceProvisionedControllerImpl.java
@@ -44,8 +44,9 @@ public class CarDeviceProvisionedControllerImpl extends DeviceProvisionedControl
CarSettings.Secure.KEY_SETUP_WIZARD_IN_PROGRESS);
private final ContentObserver mCarSettingsObserver = new ContentObserver(
Dependency.get(Dependency.MAIN_HANDLER)) {
+
@Override
- public void onChange(boolean selfChange, Uri uri, int userId) {
+ public void onChange(boolean selfChange, Uri uri, int flags) {
if (USER_SETUP_IN_PROGRESS_URI.equals(uri)) {
notifyUserSetupInProgressChanged();
}
diff --git a/packages/CarSystemUI/src/com/android/systemui/car/notification/CarHeadsUpNotificationSystemContainer.java b/packages/CarSystemUI/src/com/android/systemui/car/notification/CarHeadsUpNotificationSystemContainer.java
new file mode 100644
index 000000000000..689d2d537bd6
--- /dev/null
+++ b/packages/CarSystemUI/src/com/android/systemui/car/notification/CarHeadsUpNotificationSystemContainer.java
@@ -0,0 +1,118 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.car.notification;
+
+import android.content.Context;
+import android.content.res.Resources;
+import android.graphics.PixelFormat;
+import android.view.Gravity;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+import android.view.WindowManager;
+import android.widget.FrameLayout;
+
+import com.android.car.notification.R;
+import com.android.car.notification.headsup.CarHeadsUpNotificationContainer;
+import com.android.systemui.car.CarDeviceProvisionedController;
+import com.android.systemui.dagger.qualifiers.Main;
+import com.android.systemui.statusbar.car.CarStatusBar;
+
+import javax.inject.Inject;
+import javax.inject.Singleton;
+
+import dagger.Lazy;
+
+/**
+ * A controller for SysUI's HUN display.
+ */
+@Singleton
+public class CarHeadsUpNotificationSystemContainer implements CarHeadsUpNotificationContainer {
+ private final CarDeviceProvisionedController mCarDeviceProvisionedController;
+ private final Lazy<CarStatusBar> mCarStatusBarLazy;
+
+ private final ViewGroup mWindow;
+ private final FrameLayout mHeadsUpContentFrame;
+
+ private final boolean mEnableHeadsUpNotificationWhenNotificationShadeOpen;
+
+ @Inject
+ CarHeadsUpNotificationSystemContainer(Context context,
+ @Main Resources resources,
+ CarDeviceProvisionedController deviceProvisionedController,
+ WindowManager windowManager,
+ // TODO: Remove dependency on CarStatusBar
+ Lazy<CarStatusBar> carStatusBarLazy) {
+ mCarDeviceProvisionedController = deviceProvisionedController;
+ mCarStatusBarLazy = carStatusBarLazy;
+
+ WindowManager.LayoutParams lp = new WindowManager.LayoutParams(
+ ViewGroup.LayoutParams.MATCH_PARENT,
+ WindowManager.LayoutParams.WRAP_CONTENT,
+ WindowManager.LayoutParams.TYPE_KEYGUARD_DIALOG,
+ WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE
+ | WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN,
+ PixelFormat.TRANSLUCENT);
+
+ lp.gravity = Gravity.TOP;
+ lp.setTitle("HeadsUpNotification");
+
+ mWindow = (ViewGroup) LayoutInflater.from(context)
+ .inflate(R.layout.headsup_container, null, false);
+ windowManager.addView(mWindow, lp);
+ mWindow.setVisibility(View.INVISIBLE);
+ mHeadsUpContentFrame = mWindow.findViewById(R.id.headsup_content);
+
+ mEnableHeadsUpNotificationWhenNotificationShadeOpen = resources.getBoolean(
+ R.bool.config_enableHeadsUpNotificationWhenNotificationShadeOpen);
+ }
+
+ private void animateShow() {
+ if ((mEnableHeadsUpNotificationWhenNotificationShadeOpen
+ || !mCarStatusBarLazy.get().isPanelExpanded()) && isCurrentUserSetup()) {
+ mWindow.setVisibility(View.VISIBLE);
+ }
+ }
+
+ private void animateHide() {
+ mWindow.setVisibility(View.INVISIBLE);
+ }
+
+ @Override
+ public void displayNotification(View notificationView) {
+ mHeadsUpContentFrame.addView(notificationView);
+ animateShow();
+ }
+
+ @Override
+ public void removeNotification(View notificationView) {
+ mHeadsUpContentFrame.removeView(notificationView);
+ if (mHeadsUpContentFrame.getChildCount() == 0) {
+ animateHide();
+ }
+ }
+
+ @Override
+ public boolean isVisible() {
+ return mWindow.getVisibility() == View.VISIBLE;
+ }
+
+ private boolean isCurrentUserSetup() {
+ return mCarDeviceProvisionedController.isCurrentUserSetup()
+ && !mCarDeviceProvisionedController.isCurrentUserSetupInProgress();
+ }
+}
diff --git a/packages/CarSystemUI/src/com/android/systemui/car/notification/CarNotificationModule.java b/packages/CarSystemUI/src/com/android/systemui/car/notification/CarNotificationModule.java
new file mode 100644
index 000000000000..b7bc63150ea9
--- /dev/null
+++ b/packages/CarSystemUI/src/com/android/systemui/car/notification/CarNotificationModule.java
@@ -0,0 +1,84 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.car.notification;
+
+import android.content.Context;
+
+import com.android.car.notification.CarHeadsUpNotificationManager;
+import com.android.car.notification.CarNotificationListener;
+import com.android.car.notification.CarUxRestrictionManagerWrapper;
+import com.android.car.notification.NotificationClickHandlerFactory;
+import com.android.car.notification.NotificationDataManager;
+import com.android.car.notification.headsup.CarHeadsUpNotificationContainer;
+import com.android.internal.statusbar.IStatusBarService;
+
+import javax.inject.Singleton;
+
+import dagger.Binds;
+import dagger.Module;
+import dagger.Provides;
+
+/**
+ * Module for Car SysUI Notifications
+ */
+@Module
+public abstract class CarNotificationModule {
+ @Provides
+ @Singleton
+ static NotificationClickHandlerFactory provideNotificationClickHandlerFactory(
+ IStatusBarService barService) {
+ return new NotificationClickHandlerFactory(barService);
+ }
+
+ @Provides
+ @Singleton
+ static NotificationDataManager provideNotificationDataManager() {
+ return new NotificationDataManager();
+ }
+
+ @Provides
+ @Singleton
+ static CarUxRestrictionManagerWrapper provideCarUxRestrictionManagerWrapper() {
+ return new CarUxRestrictionManagerWrapper();
+ }
+
+ @Provides
+ @Singleton
+ static CarNotificationListener provideCarNotificationListener(Context context,
+ CarUxRestrictionManagerWrapper carUxRestrictionManagerWrapper,
+ CarHeadsUpNotificationManager carHeadsUpNotificationManager,
+ NotificationDataManager notificationDataManager) {
+ CarNotificationListener listener = new CarNotificationListener();
+ listener.registerAsSystemService(context, carUxRestrictionManagerWrapper,
+ carHeadsUpNotificationManager, notificationDataManager);
+ return listener;
+ }
+
+ @Provides
+ @Singleton
+ static CarHeadsUpNotificationManager provideCarHeadsUpNotificationManager(Context context,
+ NotificationClickHandlerFactory notificationClickHandlerFactory,
+ NotificationDataManager notificationDataManager,
+ CarHeadsUpNotificationContainer headsUpNotificationDisplay) {
+ return new CarHeadsUpNotificationManager(context, notificationClickHandlerFactory,
+ notificationDataManager, headsUpNotificationDisplay);
+ }
+
+ @Binds
+ abstract CarHeadsUpNotificationContainer bindsCarHeadsUpNotificationContainer(
+ CarHeadsUpNotificationSystemContainer carHeadsUpNotificationSystemContainer);
+}
diff --git a/packages/CarSystemUI/src/com/android/systemui/statusbar/car/CarTrustAgentUnlockDialogHelper.java b/packages/CarSystemUI/src/com/android/systemui/car/userswitcher/CarTrustAgentUnlockDialogHelper.java
index 07dbd667acf4..597716569e9b 100644
--- a/packages/CarSystemUI/src/com/android/systemui/statusbar/car/CarTrustAgentUnlockDialogHelper.java
+++ b/packages/CarSystemUI/src/com/android/systemui/car/userswitcher/CarTrustAgentUnlockDialogHelper.java
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2019 The Android Open Source Project
+ * Copyright (C) 2020 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-package com.android.systemui.statusbar.car;
+package com.android.systemui.car.userswitcher;
import android.app.admin.DevicePolicyManager;
import android.bluetooth.BluetoothAdapter;
@@ -56,8 +56,8 @@ class CarTrustAgentUnlockDialogHelper extends BroadcastReceiver{
private final UserManager mUserManager;
private final WindowManager.LayoutParams mParams;
/**
- * Not using Dialog because context passed from {@link FullscreenUserSwitcher} is not an
- * activity.
+ * Not using Dialog because context passed from {@link FullscreenUserSwitcherViewMediator}
+ * is not an activity.
*/
private final View mUnlockDialogLayout;
private final TextView mUnlockingText;
diff --git a/packages/CarSystemUI/src/com/android/systemui/car/userswitcher/FullScreenUserSwitcherViewController.java b/packages/CarSystemUI/src/com/android/systemui/car/userswitcher/FullScreenUserSwitcherViewController.java
new file mode 100644
index 000000000000..45ceb6d1551f
--- /dev/null
+++ b/packages/CarSystemUI/src/com/android/systemui/car/userswitcher/FullScreenUserSwitcherViewController.java
@@ -0,0 +1,124 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.car.userswitcher;
+
+import android.animation.Animator;
+import android.animation.AnimatorListenerAdapter;
+import android.content.Context;
+import android.content.res.Resources;
+import android.view.View;
+
+import androidx.recyclerview.widget.GridLayoutManager;
+
+import com.android.systemui.R;
+import com.android.systemui.dagger.qualifiers.Main;
+import com.android.systemui.window.OverlayViewController;
+import com.android.systemui.window.OverlayViewGlobalStateController;
+
+import javax.inject.Inject;
+import javax.inject.Singleton;
+
+/**
+ * Controller for {@link R.layout#car_fullscreen_user_switcher}.
+ */
+@Singleton
+public class FullScreenUserSwitcherViewController extends OverlayViewController {
+ private final Context mContext;
+ private final Resources mResources;
+ private final int mShortAnimationDuration;
+ private UserGridRecyclerView mUserGridView;
+ private UserGridRecyclerView.UserSelectionListener mUserSelectionListener;
+
+ @Inject
+ public FullScreenUserSwitcherViewController(
+ Context context,
+ @Main Resources resources,
+ OverlayViewGlobalStateController overlayViewGlobalStateController) {
+ super(R.id.fullscreen_user_switcher_stub, overlayViewGlobalStateController);
+ mContext = context;
+ mResources = resources;
+ mShortAnimationDuration = mResources.getInteger(android.R.integer.config_shortAnimTime);
+ }
+
+ @Override
+ protected void onFinishInflate() {
+ // Initialize user grid.
+ mUserGridView = getLayout().findViewById(R.id.user_grid);
+ GridLayoutManager layoutManager = new GridLayoutManager(mContext,
+ mResources.getInteger(R.integer.user_fullscreen_switcher_num_col));
+ mUserGridView.setLayoutManager(layoutManager);
+ mUserGridView.buildAdapter();
+ mUserGridView.setUserSelectionListener(mUserSelectionListener);
+ }
+
+ @Override
+ protected void showInternal() {
+ getLayout().setVisibility(View.VISIBLE);
+ }
+
+ @Override
+ protected void hideInternal() {
+ // Switching is about to happen, since it takes time, fade out the switcher gradually.
+ fadeOut();
+ }
+
+ private void fadeOut() {
+ mUserGridView.animate()
+ .alpha(0.0f)
+ .setDuration(mShortAnimationDuration)
+ .setListener(new AnimatorListenerAdapter() {
+ @Override
+ public void onAnimationEnd(Animator animation) {
+ getLayout().setVisibility(View.GONE);
+ mUserGridView.setAlpha(1.0f);
+ }
+ });
+
+ }
+
+ /**
+ * Invalidate underlying view.
+ */
+ void invalidate() {
+ if (getLayout() == null) {
+ // layout hasn't been inflated.
+ return;
+ }
+
+ getLayout().invalidate();
+ }
+
+ /**
+ * Set {@link UserGridRecyclerView.UserSelectionListener}.
+ */
+ void setUserGridSelectionListener(
+ UserGridRecyclerView.UserSelectionListener userGridSelectionListener) {
+ mUserSelectionListener = userGridSelectionListener;
+ }
+
+ /**
+ * Returns {@code true} when layout is visible.
+ */
+ boolean isVisible() {
+ if (getLayout() == null) {
+ // layout hasn't been inflated.
+ return false;
+ }
+
+ return getLayout().getVisibility() == View.VISIBLE;
+ }
+}
diff --git a/packages/CarSystemUI/src/com/android/systemui/car/userswitcher/FullscreenUserSwitcherViewMediator.java b/packages/CarSystemUI/src/com/android/systemui/car/userswitcher/FullscreenUserSwitcherViewMediator.java
new file mode 100644
index 000000000000..627729768e88
--- /dev/null
+++ b/packages/CarSystemUI/src/com/android/systemui/car/userswitcher/FullscreenUserSwitcherViewMediator.java
@@ -0,0 +1,291 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.car.userswitcher;
+
+import android.car.Car;
+import android.car.trust.CarTrustAgentEnrollmentManager;
+import android.car.userlib.CarUserManagerHelper;
+import android.content.BroadcastReceiver;
+import android.content.Context;
+import android.content.Intent;
+import android.content.IntentFilter;
+import android.content.pm.UserInfo;
+import android.content.res.Resources;
+import android.os.Handler;
+import android.os.UserHandle;
+import android.os.UserManager;
+import android.util.Log;
+
+import com.android.internal.widget.LockPatternUtils;
+import com.android.systemui.R;
+import com.android.systemui.car.CarServiceProvider;
+import com.android.systemui.dagger.qualifiers.Main;
+import com.android.systemui.keyguard.ScreenLifecycle;
+import com.android.systemui.plugins.statusbar.StatusBarStateController;
+import com.android.systemui.statusbar.StatusBarState;
+import com.android.systemui.statusbar.car.CarStatusBar;
+import com.android.systemui.statusbar.car.CarStatusBarKeyguardViewManager;
+import com.android.systemui.window.OverlayViewMediator;
+
+import javax.inject.Inject;
+import javax.inject.Singleton;
+
+/**
+ * Manages the fullscreen user switcher and it's interactions with the keyguard.
+ */
+@Singleton
+public class FullscreenUserSwitcherViewMediator implements OverlayViewMediator {
+ private static final String TAG = FullscreenUserSwitcherViewMediator.class.getSimpleName();
+
+ private final Context mContext;
+ private final UserManager mUserManager;
+ private final CarServiceProvider mCarServiceProvider;
+ private final CarTrustAgentUnlockDialogHelper mUnlockDialogHelper;
+ private final CarStatusBarKeyguardViewManager mCarStatusBarKeyguardViewManager;
+ private final Handler mMainHandler;
+ private final StatusBarStateController mStatusBarStateController;
+ private final FullScreenUserSwitcherViewController mFullScreenUserSwitcherViewController;
+ private final ScreenLifecycle mScreenLifecycle;
+ private final CarStatusBar mCarStatusBar;
+ private final boolean mIsUserSwitcherEnabled;
+ private final CarUserManagerHelper mCarUserManagerHelper;
+
+ private CarTrustAgentEnrollmentManager mEnrollmentManager;
+ private UserGridRecyclerView.UserRecord mSelectedUser;
+ private final CarTrustAgentUnlockDialogHelper.OnHideListener mOnHideListener =
+ dismissUserSwitcher -> {
+ if (dismissUserSwitcher) {
+ dismissUserSwitcher();
+ } else {
+ // Re-draw the parent view, otherwise the unlock dialog will not be removed
+ // from the screen immediately.
+ invalidateFullscreenUserSwitcherView();
+ }
+ };
+ private final BroadcastReceiver mUserUnlockReceiver = new BroadcastReceiver() {
+ @Override
+ public void onReceive(Context context, Intent intent) {
+ if (Log.isLoggable(TAG, Log.DEBUG)) {
+ Log.d(TAG, "user 0 is unlocked, SharedPreference is accessible.");
+ }
+ showDialogForInitialUser();
+ mContext.unregisterReceiver(mUserUnlockReceiver);
+ }
+ };
+
+ @Inject
+ public FullscreenUserSwitcherViewMediator(
+ Context context,
+ @Main Resources resources,
+ @Main Handler mainHandler,
+ UserManager userManager,
+ CarServiceProvider carServiceProvider,
+ CarTrustAgentUnlockDialogHelper carTrustAgentUnlockDialogHelper,
+ CarStatusBarKeyguardViewManager carStatusBarKeyguardViewManager,
+ CarStatusBar carStatusBar,
+ StatusBarStateController statusBarStateController,
+ FullScreenUserSwitcherViewController fullScreenUserSwitcherViewController,
+ ScreenLifecycle screenLifecycle) {
+ mContext = context;
+
+ mIsUserSwitcherEnabled = resources.getBoolean(R.bool.config_enableFullscreenUserSwitcher);
+
+ mMainHandler = mainHandler;
+ mUserManager = userManager;
+
+ mCarServiceProvider = carServiceProvider;
+ mCarServiceProvider.addListener(
+ car -> mEnrollmentManager = (CarTrustAgentEnrollmentManager) car.getCarManager(
+ Car.CAR_TRUST_AGENT_ENROLLMENT_SERVICE));
+
+ mUnlockDialogHelper = carTrustAgentUnlockDialogHelper;
+ mCarStatusBarKeyguardViewManager = carStatusBarKeyguardViewManager;
+ mCarStatusBar = carStatusBar;
+ mStatusBarStateController = statusBarStateController;
+ mFullScreenUserSwitcherViewController = fullScreenUserSwitcherViewController;
+ mScreenLifecycle = screenLifecycle;
+
+ mCarUserManagerHelper = new CarUserManagerHelper(mContext);
+ }
+
+ @Override
+ public void registerListeners() {
+ registerUserSwitcherShowListeners();
+ registerUserSwitcherHideListeners();
+ registerHideKeyguardListeners();
+
+ if (mUserManager.isUserUnlocked(UserHandle.USER_SYSTEM)) {
+ // User0 is unlocked, switched to the initial user
+ showDialogForInitialUser();
+ } else {
+ // listen to USER_UNLOCKED
+ mContext.registerReceiverAsUser(mUserUnlockReceiver,
+ UserHandle.getUserHandleForUid(UserHandle.USER_SYSTEM),
+ new IntentFilter(Intent.ACTION_USER_UNLOCKED),
+ /* broadcastPermission= */ null,
+ /* scheduler= */ null);
+ }
+ }
+
+ private void registerUserSwitcherShowListeners() {
+ mCarStatusBarKeyguardViewManager.addOnKeyguardCancelClickedListener(this::show);
+ }
+
+ private void registerUserSwitcherHideListeners() {
+ mStatusBarStateController.addCallback(new StatusBarStateController.StateListener() {
+ @Override
+ public void onStateChanged(int newState) {
+ if (newState == StatusBarState.FULLSCREEN_USER_SWITCHER) {
+ return;
+ }
+ hide();
+ }
+ });
+ }
+
+ private void registerHideKeyguardListeners() {
+ mStatusBarStateController.addCallback(new StatusBarStateController.StateListener() {
+ @Override
+ public void onStateChanged(int newState) {
+ if (newState != StatusBarState.FULLSCREEN_USER_SWITCHER) {
+ return;
+ }
+ dismissKeyguardWhenUserSwitcherNotDisplayed(newState);
+ }
+ });
+
+ mScreenLifecycle.addObserver(new ScreenLifecycle.Observer() {
+ @Override
+ public void onScreenTurnedOn() {
+ dismissKeyguardWhenUserSwitcherNotDisplayed(mStatusBarStateController.getState());
+ }
+ });
+
+ mContext.registerReceiver(new BroadcastReceiver() {
+ @Override
+ public void onReceive(Context context, Intent intent) {
+ if (!intent.getAction().equals(Intent.ACTION_USER_SWITCHED)) {
+ return;
+ }
+
+ // Try to dismiss the keyguard after every user switch.
+ dismissKeyguardWhenUserSwitcherNotDisplayed(mStatusBarStateController.getState());
+ }
+ }, new IntentFilter(Intent.ACTION_USER_SWITCHED));
+ }
+
+ @Override
+ public void setupOverlayContentViewControllers() {
+ mFullScreenUserSwitcherViewController.setUserGridSelectionListener(this::onUserSelected);
+ }
+
+ /**
+ * Every time user clicks on an item in the switcher, if the clicked user has no trusted
+ * device, we hide the switcher, either gradually or immediately.
+ * If the user has trusted device, we show an unlock dialog to notify user the unlock
+ * state.
+ * When the unlock dialog is dismissed by user, we hide the unlock dialog and the switcher.
+ * We dismiss the entire keyguard when we hide the switcher if user clicked on the
+ * foreground user (user we're already logged in as).
+ */
+ private void onUserSelected(UserGridRecyclerView.UserRecord record) {
+ mSelectedUser = record;
+ if (record.mInfo != null) {
+ if (hasScreenLock(record.mInfo.id) && hasTrustedDevice(record.mInfo.id)) {
+ mUnlockDialogHelper.showUnlockDialog(record.mInfo.id, mOnHideListener);
+ return;
+ }
+ if (Log.isLoggable(TAG, Log.DEBUG)) {
+ Log.d(TAG, "no trusted device enrolled for uid: " + record.mInfo.id);
+ }
+ }
+ dismissUserSwitcher();
+ }
+
+ // We automatically dismiss keyguard unless user switcher is being shown above the keyguard.
+ private void dismissKeyguardWhenUserSwitcherNotDisplayed(int state) {
+ if (!mIsUserSwitcherEnabled) {
+ return; // Not using the full screen user switcher.
+ }
+
+ if (state == StatusBarState.FULLSCREEN_USER_SWITCHER
+ && !mFullScreenUserSwitcherViewController.isVisible()) {
+ // Current execution path continues to set state after this, thus we deffer the
+ // dismissal to the next execution cycle.
+
+ // Dismiss the keyguard if switcher is not visible.
+ // TODO(b/150402329): Remove once keyguard is implemented using Overlay Window
+ // abstractions.
+ mMainHandler.post(mCarStatusBar::dismissKeyguard);
+ }
+ }
+
+ private boolean hasScreenLock(int uid) {
+ LockPatternUtils lockPatternUtils = new LockPatternUtils(mContext);
+ return lockPatternUtils.getCredentialTypeForUser(uid)
+ != LockPatternUtils.CREDENTIAL_TYPE_NONE;
+ }
+
+ private boolean hasTrustedDevice(int uid) {
+ if (mEnrollmentManager == null) { // car service not ready, so it cannot be available.
+ return false;
+ }
+ return !mEnrollmentManager.getEnrolledDeviceInfoForUser(uid).isEmpty();
+ }
+
+ private void dismissUserSwitcher() {
+ if (mSelectedUser == null) {
+ Log.e(TAG, "Request to dismiss user switcher, but no user selected");
+ return;
+ }
+ if (mSelectedUser.mType == UserGridRecyclerView.UserRecord.FOREGROUND_USER) {
+ hide();
+ mCarStatusBar.dismissKeyguard();
+ return;
+ }
+ hide();
+ }
+
+ private void showDialogForInitialUser() {
+ int initialUser = mCarUserManagerHelper.getInitialUser();
+ UserInfo initialUserInfo = mUserManager.getUserInfo(initialUser);
+ mSelectedUser = new UserGridRecyclerView.UserRecord(initialUserInfo,
+ UserGridRecyclerView.UserRecord.FOREGROUND_USER);
+
+ // If the initial user has screen lock and trusted device, display the unlock dialog on the
+ // keyguard.
+ if (hasScreenLock(initialUser) && hasTrustedDevice(initialUser)) {
+ mUnlockDialogHelper.showUnlockDialogAfterDelay(initialUser,
+ mOnHideListener);
+ } else {
+ // If no trusted device, dismiss the keyguard.
+ dismissUserSwitcher();
+ }
+ }
+
+ private void invalidateFullscreenUserSwitcherView() {
+ mFullScreenUserSwitcherViewController.invalidate();
+ }
+
+ private void hide() {
+ mFullScreenUserSwitcherViewController.stop();
+ }
+
+ private void show() {
+ mFullScreenUserSwitcherViewController.start();
+ }
+}
diff --git a/packages/CarSystemUI/src/com/android/systemui/statusbar/car/UserGridRecyclerView.java b/packages/CarSystemUI/src/com/android/systemui/car/userswitcher/UserGridRecyclerView.java
index 7dd3be4b2c11..58add179886c 100644
--- a/packages/CarSystemUI/src/com/android/systemui/statusbar/car/UserGridRecyclerView.java
+++ b/packages/CarSystemUI/src/com/android/systemui/car/userswitcher/UserGridRecyclerView.java
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2018 The Android Open Source Project
+ * Copyright (C) 2020 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-package com.android.systemui.statusbar.car;
+package com.android.systemui.car.userswitcher;
import static android.content.DialogInterface.BUTTON_NEGATIVE;
import static android.content.DialogInterface.BUTTON_POSITIVE;
@@ -45,7 +45,6 @@ import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.view.Window;
-import android.view.WindowInsets;
import android.view.WindowManager;
import android.widget.ImageView;
import android.widget.TextView;
@@ -114,8 +113,6 @@ public class UserGridRecyclerView extends RecyclerView {
/**
* Initializes the adapter that populates the grid layout
- *
- * @return the adapter
*/
public void buildAdapter() {
List<UserRecord> userRecords = createUserRecords(getUsersForUserGrid());
@@ -236,10 +233,16 @@ public class UserGridRecyclerView extends RecyclerView {
mNewUserName = mRes.getString(R.string.car_new_user);
}
+ /**
+ * Clears list of user records.
+ */
public void clearUsers() {
mUsers.clear();
}
+ /**
+ * Updates list of user records.
+ */
public void updateUsers(List<UserRecord> users) {
mUsers = users;
}
@@ -483,6 +486,10 @@ public class UserGridRecyclerView extends RecyclerView {
return mUsers.size();
}
+ /**
+ * An extension of {@link RecyclerView.ViewHolder} that also houses the user name and the
+ * user avatar.
+ */
public class UserAdapterViewHolder extends RecyclerView.ViewHolder {
public ImageView mUserAvatarImageView;
diff --git a/packages/CarSystemUI/src/com/android/systemui/statusbar/car/UserIconProvider.java b/packages/CarSystemUI/src/com/android/systemui/car/userswitcher/UserIconProvider.java
index 9018290f4955..dc5953e38ccb 100644
--- a/packages/CarSystemUI/src/com/android/systemui/statusbar/car/UserIconProvider.java
+++ b/packages/CarSystemUI/src/com/android/systemui/car/userswitcher/UserIconProvider.java
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2019 The Android Open Source Project
+ * Copyright (C) 2020 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-package com.android.systemui.statusbar.car;
+package com.android.systemui.car.userswitcher;
import android.annotation.UserIdInt;
import android.content.Context;
diff --git a/packages/CarSystemUI/src/com/android/systemui/navigationbar/car/CarNavigationBar.java b/packages/CarSystemUI/src/com/android/systemui/navigationbar/car/CarNavigationBar.java
index b2c16b3aef1b..b63162ba8090 100644
--- a/packages/CarSystemUI/src/com/android/systemui/navigationbar/car/CarNavigationBar.java
+++ b/packages/CarSystemUI/src/com/android/systemui/navigationbar/car/CarNavigationBar.java
@@ -49,7 +49,6 @@ import com.android.systemui.statusbar.NavigationBarController;
import com.android.systemui.statusbar.SuperStatusBarViewFactory;
import com.android.systemui.statusbar.phone.AutoHideController;
import com.android.systemui.statusbar.phone.BarTransitions;
-import com.android.systemui.statusbar.policy.DeviceProvisionedController;
import com.android.systemui.statusbar.policy.KeyguardStateController;
import java.io.FileDescriptor;
@@ -105,7 +104,7 @@ public class CarNavigationBar extends SystemUI implements CommandQueue.Callbacks
public CarNavigationBar(Context context,
CarNavigationBarController carNavigationBarController,
WindowManager windowManager,
- DeviceProvisionedController deviceProvisionedController,
+ CarDeviceProvisionedController deviceProvisionedController,
CommandQueue commandQueue,
AutoHideController autoHideController,
ButtonSelectionStateListener buttonSelectionStateListener,
@@ -117,8 +116,7 @@ public class CarNavigationBar extends SystemUI implements CommandQueue.Callbacks
super(context);
mCarNavigationBarController = carNavigationBarController;
mWindowManager = windowManager;
- mCarDeviceProvisionedController = (CarDeviceProvisionedController)
- deviceProvisionedController;
+ mCarDeviceProvisionedController = deviceProvisionedController;
mCommandQueue = commandQueue;
mAutoHideController = autoHideController;
mButtonSelectionStateListener = buttonSelectionStateListener;
@@ -245,6 +243,10 @@ public class CarNavigationBar extends SystemUI implements CommandQueue.Callbacks
if (mKeyguardStateControllerLazy.get().isShowing()) {
mCarNavigationBarController.showAllKeyguardButtons(isDeviceSetupForUser());
}
+
+ // Upon restarting the Navigation Bar, CarFacetButtonController should immediately apply the
+ // selection state that reflects the current task stack.
+ mButtonSelectionStateListener.onTaskStackChanged();
}
private boolean isDeviceSetupForUser() {
diff --git a/packages/CarSystemUI/src/com/android/systemui/navigationbar/car/CarNavigationBarController.java b/packages/CarSystemUI/src/com/android/systemui/navigationbar/car/CarNavigationBarController.java
index a56c4eda44da..67e9da429c36 100644
--- a/packages/CarSystemUI/src/com/android/systemui/navigationbar/car/CarNavigationBarController.java
+++ b/packages/CarSystemUI/src/com/android/systemui/navigationbar/car/CarNavigationBarController.java
@@ -71,6 +71,30 @@ public class CarNavigationBarController {
mShowRight = mContext.getResources().getBoolean(R.bool.config_enableRightNavigationBar);
}
+ /**
+ * Hides all navigation bars.
+ */
+ public void hideBars() {
+ if (mTopView != null) {
+ mTopView.setVisibility(View.GONE);
+ }
+ setBottomWindowVisibility(View.GONE);
+ setLeftWindowVisibility(View.GONE);
+ setRightWindowVisibility(View.GONE);
+ }
+
+ /**
+ * Shows all navigation bars.
+ */
+ public void showBars() {
+ if (mTopView != null) {
+ mTopView.setVisibility(View.VISIBLE);
+ }
+ setBottomWindowVisibility(View.VISIBLE);
+ setLeftWindowVisibility(View.VISIBLE);
+ setRightWindowVisibility(View.VISIBLE);
+ }
+
/** Connect to hvac service. */
public void connectToHvac() {
mHvacControllerLazy.get().connectToCarService();
diff --git a/packages/CarSystemUI/src/com/android/systemui/qs/car/CarQSFragment.java b/packages/CarSystemUI/src/com/android/systemui/qs/car/CarQSFragment.java
index f9cfafa5c471..31965c5fc022 100644
--- a/packages/CarSystemUI/src/com/android/systemui/qs/car/CarQSFragment.java
+++ b/packages/CarSystemUI/src/com/android/systemui/qs/car/CarQSFragment.java
@@ -35,9 +35,9 @@ import androidx.annotation.VisibleForTesting;
import androidx.recyclerview.widget.GridLayoutManager;
import com.android.systemui.R;
+import com.android.systemui.car.userswitcher.UserGridRecyclerView;
import com.android.systemui.plugins.qs.QS;
import com.android.systemui.qs.QSFooter;
-import com.android.systemui.statusbar.car.UserGridRecyclerView;
import java.util.ArrayList;
import java.util.List;
diff --git a/packages/CarSystemUI/src/com/android/systemui/statusbar/car/CarStatusBar.java b/packages/CarSystemUI/src/com/android/systemui/statusbar/car/CarStatusBar.java
index 0374a5cef0ae..b2e21045f2a9 100644
--- a/packages/CarSystemUI/src/com/android/systemui/statusbar/car/CarStatusBar.java
+++ b/packages/CarSystemUI/src/com/android/systemui/statusbar/car/CarStatusBar.java
@@ -43,11 +43,9 @@ import android.view.ViewTreeObserver;
import androidx.annotation.NonNull;
import androidx.recyclerview.widget.RecyclerView;
-import com.android.car.notification.CarHeadsUpNotificationManager;
import com.android.car.notification.CarNotificationListener;
import com.android.car.notification.CarNotificationView;
import com.android.car.notification.CarUxRestrictionManagerWrapper;
-import com.android.car.notification.HeadsUpEntry;
import com.android.car.notification.NotificationClickHandlerFactory;
import com.android.car.notification.NotificationDataManager;
import com.android.car.notification.NotificationViewController;
@@ -67,7 +65,6 @@ import com.android.systemui.bubbles.BubbleController;
import com.android.systemui.car.CarDeviceProvisionedController;
import com.android.systemui.car.CarDeviceProvisionedListener;
import com.android.systemui.car.CarServiceProvider;
-import com.android.systemui.car.SystemUIPrimaryWindowController;
import com.android.systemui.classifier.FalsingLog;
import com.android.systemui.colorextraction.SysuiColorExtractor;
import com.android.systemui.dagger.qualifiers.UiBackground;
@@ -95,7 +92,6 @@ import com.android.systemui.statusbar.NotificationMediaManager;
import com.android.systemui.statusbar.NotificationRemoteInputManager;
import com.android.systemui.statusbar.NotificationViewHierarchyManager;
import com.android.systemui.statusbar.PulseExpansionHandler;
-import com.android.systemui.statusbar.StatusBarState;
import com.android.systemui.statusbar.SuperStatusBarViewFactory;
import com.android.systemui.statusbar.SysuiStatusBarStateController;
import com.android.systemui.statusbar.VibratorHelper;
@@ -134,7 +130,6 @@ import com.android.systemui.statusbar.phone.StatusBarTouchableRegionManager;
import com.android.systemui.statusbar.phone.dagger.StatusBarComponent;
import com.android.systemui.statusbar.policy.BatteryController;
import com.android.systemui.statusbar.policy.ConfigurationController;
-import com.android.systemui.statusbar.policy.DeviceProvisionedController;
import com.android.systemui.statusbar.policy.ExtensionController;
import com.android.systemui.statusbar.policy.KeyguardStateController;
import com.android.systemui.statusbar.policy.NetworkController;
@@ -181,22 +176,21 @@ public class CarStatusBar extends StatusBar implements CarBatteryController.Batt
private Drawable mNotificationPanelBackground;
private final Object mQueueLock = new Object();
- private final SystemUIPrimaryWindowController mSystemUIPrimaryWindowController;
private final CarNavigationBarController mCarNavigationBarController;
private final FlingAnimationUtils.Builder mFlingAnimationUtilsBuilder;
private final Lazy<PowerManagerHelper> mPowerManagerHelperLazy;
- private final FullscreenUserSwitcher mFullscreenUserSwitcher;
private final ShadeController mShadeController;
private final CarServiceProvider mCarServiceProvider;
+ private final NotificationDataManager mNotificationDataManager;
private final CarDeviceProvisionedController mCarDeviceProvisionedController;
+ private final ScreenLifecycle mScreenLifecycle;
+ private final CarNotificationListener mCarNotificationListener;
private boolean mDeviceIsSetUpForUser = true;
private boolean mIsUserSetupInProgress = false;
private PowerManagerHelper mPowerManagerHelper;
private FlingAnimationUtils mFlingAnimationUtils;
- private NotificationDataManager mNotificationDataManager;
private NotificationClickHandlerFactory mNotificationClickHandlerFactory;
- private ScreenLifecycle mScreenLifecycle;
// The container for the notifications.
private CarNotificationView mNotificationView;
@@ -233,24 +227,8 @@ public class CarStatusBar extends StatusBar implements CarBatteryController.Batt
private boolean mIsNotificationCardSwiping;
// If notification shade is being swiped vertically to close.
private boolean mIsSwipingVerticallyToClose;
- // Whether heads-up notifications should be shown when shade is open.
- private boolean mEnableHeadsUpNotificationWhenNotificationShadeOpen;
-
- private CarUxRestrictionManagerWrapper mCarUxRestrictionManagerWrapper;
-
- private final CarPowerStateListener mCarPowerStateListener =
- (int state) -> {
- // When the car powers on, clear all notifications and mute/unread states.
- Log.d(TAG, "New car power state: " + state);
- if (state == CarPowerStateListener.ON) {
- if (mNotificationClickHandlerFactory != null) {
- mNotificationClickHandlerFactory.clearAllNotifications();
- }
- if (mNotificationDataManager != null) {
- mNotificationDataManager.clearAll();
- }
- }
- };
+
+ private final CarUxRestrictionManagerWrapper mCarUxRestrictionManagerWrapper;
public CarStatusBar(
Context context,
@@ -292,7 +270,7 @@ public class CarStatusBar extends StatusBar implements CarBatteryController.Batt
BubbleController bubbleController,
NotificationGroupManager groupManager,
VisualStabilityManager visualStabilityManager,
- DeviceProvisionedController deviceProvisionedController,
+ CarDeviceProvisionedController carDeviceProvisionedController,
NavigationBarController navigationBarController,
Lazy<AssistManager> assistManagerLazy,
ConfigurationController configurationController,
@@ -333,10 +311,11 @@ public class CarStatusBar extends StatusBar implements CarBatteryController.Batt
/* Car Settings injected components. */
CarServiceProvider carServiceProvider,
Lazy<PowerManagerHelper> powerManagerHelperLazy,
- FullscreenUserSwitcher fullscreenUserSwitcher,
- SystemUIPrimaryWindowController systemUIPrimaryWindowController,
CarNavigationBarController carNavigationBarController,
- FlingAnimationUtils.Builder flingAnimationUtilsBuilder) {
+ FlingAnimationUtils.Builder flingAnimationUtilsBuilder,
+ NotificationDataManager notificationDataManager,
+ CarUxRestrictionManagerWrapper carUxRestrictionManagerWrapper,
+ CarNotificationListener carNotificationListener) {
super(
context,
notificationsController,
@@ -377,7 +356,7 @@ public class CarStatusBar extends StatusBar implements CarBatteryController.Batt
bubbleController,
groupManager,
visualStabilityManager,
- deviceProvisionedController,
+ carDeviceProvisionedController,
navigationBarController,
assistManagerLazy,
configurationController,
@@ -418,15 +397,16 @@ public class CarStatusBar extends StatusBar implements CarBatteryController.Batt
mUserSwitcherController = userSwitcherController;
mScrimController = scrimController;
mLockscreenLockIconController = lockscreenLockIconController;
- mCarDeviceProvisionedController =
- (CarDeviceProvisionedController) deviceProvisionedController;
+ mCarDeviceProvisionedController = carDeviceProvisionedController;
mShadeController = shadeController;
mCarServiceProvider = carServiceProvider;
mPowerManagerHelperLazy = powerManagerHelperLazy;
- mFullscreenUserSwitcher = fullscreenUserSwitcher;
- mSystemUIPrimaryWindowController = systemUIPrimaryWindowController;
mCarNavigationBarController = carNavigationBarController;
mFlingAnimationUtilsBuilder = flingAnimationUtilsBuilder;
+ mScreenLifecycle = screenLifecycle;
+ mNotificationDataManager = notificationDataManager;
+ mCarUxRestrictionManagerWrapper = carUxRestrictionManagerWrapper;
+ mCarNotificationListener = carNotificationListener;
}
@Override
@@ -434,18 +414,6 @@ public class CarStatusBar extends StatusBar implements CarBatteryController.Batt
mDeviceIsSetUpForUser = mCarDeviceProvisionedController.isCurrentUserSetup();
mIsUserSetupInProgress = mCarDeviceProvisionedController.isCurrentUserSetupInProgress();
- // Need to initialize screen lifecycle before calling super.start - before switcher is
- // created.
- mScreenLifecycle = Dependency.get(ScreenLifecycle.class);
- mScreenLifecycle.addObserver(mScreenObserver);
-
- // TODO: Remove the setup of user switcher from Car Status Bar.
- mSystemUIPrimaryWindowController.attach();
- mFullscreenUserSwitcher.setStatusBar(this);
- mFullscreenUserSwitcher.setContainer(
- mSystemUIPrimaryWindowController.getBaseLayout().findViewById(
- R.id.fullscreen_user_switcher_stub));
-
// Notification bar related setup.
mInitialBackgroundAlpha = (float) mContext.getResources().getInteger(
R.integer.config_initialNotificationBackgroundAlpha) / 100;
@@ -481,7 +449,17 @@ public class CarStatusBar extends StatusBar implements CarBatteryController.Batt
mCarBatteryController.startListening();
mPowerManagerHelper = mPowerManagerHelperLazy.get();
- mPowerManagerHelper.setCarPowerStateListener(mCarPowerStateListener);
+ mPowerManagerHelper.setCarPowerStateListener(
+ state -> {
+ // When the car powers on, clear all notifications and mute/unread states.
+ Log.d(TAG, "New car power state: " + state);
+ if (state == CarPowerStateListener.ON) {
+ if (mNotificationClickHandlerFactory != null) {
+ mNotificationClickHandlerFactory.clearAllNotifications();
+ }
+ mNotificationDataManager.clearAll();
+ }
+ });
mPowerManagerHelper.connectToCarService();
mCarDeviceProvisionedController.addCallback(
@@ -616,27 +594,13 @@ public class CarStatusBar extends StatusBar implements CarBatteryController.Batt
mShadeController.animateCollapsePanels();
}
});
- CarNotificationListener carNotificationListener = new CarNotificationListener();
- mCarUxRestrictionManagerWrapper = new CarUxRestrictionManagerWrapper();
-
- mNotificationDataManager = new NotificationDataManager();
mNotificationDataManager.setOnUnseenCountUpdateListener(() -> {
- if (mNotificationDataManager != null) {
- onUseenCountUpdate(mNotificationDataManager.getUnseenNotificationCount());
- }
+ onUseenCountUpdate(mNotificationDataManager.getUnseenNotificationCount());
});
- mEnableHeadsUpNotificationWhenNotificationShadeOpen = mContext.getResources().getBoolean(
- R.bool.config_enableHeadsUpNotificationWhenNotificationShadeOpen);
- CarHeadsUpNotificationManager carHeadsUpNotificationManager =
- new CarSystemUIHeadsUpNotificationManager(mContext,
- mNotificationClickHandlerFactory, mNotificationDataManager);
mNotificationClickHandlerFactory.setNotificationDataManager(mNotificationDataManager);
- carNotificationListener.registerAsSystemService(mContext, mCarUxRestrictionManagerWrapper,
- carHeadsUpNotificationManager, mNotificationDataManager);
-
final View glassPane = mNotificationShadeWindowView.findViewById(R.id.glass_pane);
mNotificationView = mNotificationShadeWindowView.findViewById(R.id.notification_view);
mHandleBar = mNotificationShadeWindowView.findViewById(R.id.handle_bar);
@@ -739,7 +703,7 @@ public class CarStatusBar extends StatusBar implements CarBatteryController.Batt
mNotificationViewController = new NotificationViewController(
mNotificationView,
PreprocessingManager.getInstance(mContext),
- carNotificationListener,
+ mCarNotificationListener,
mCarUxRestrictionManagerWrapper,
mNotificationDataManager);
mNotificationViewController.enable();
@@ -965,49 +929,6 @@ public class CarStatusBar extends StatusBar implements CarBatteryController.Batt
}
}
- @Override
- public void setLockscreenUser(int newUserId) {
- super.setLockscreenUser(newUserId);
- // Try to dismiss the keyguard after every user switch.
- dismissKeyguardWhenUserSwitcherNotDisplayed();
- }
-
- @Override
- public void onStateChanged(int newState) {
- super.onStateChanged(newState);
-
- if (newState != StatusBarState.FULLSCREEN_USER_SWITCHER) {
- mFullscreenUserSwitcher.hide();
- } else {
- dismissKeyguardWhenUserSwitcherNotDisplayed();
- }
- }
-
- final ScreenLifecycle.Observer mScreenObserver = new ScreenLifecycle.Observer() {
- @Override
- public void onScreenTurnedOn() {
- dismissKeyguardWhenUserSwitcherNotDisplayed();
- }
- };
-
- // We automatically dismiss keyguard unless user switcher is being shown on the keyguard.
- private void dismissKeyguardWhenUserSwitcherNotDisplayed() {
- if (!mUserSwitcherController.useFullscreenUserSwitcher()) {
- return; // Not using the full screen user switcher.
- }
-
- if (mState == StatusBarState.FULLSCREEN_USER_SWITCHER
- && !mFullscreenUserSwitcher.isVisible()) {
- // Current execution path continues to set state after this, thus we deffer the
- // dismissal to the next execution cycle.
- postDismissKeyguard(); // Dismiss the keyguard if switcher is not visible.
- }
- }
-
- public void postDismissKeyguard() {
- mHandler.post(this::dismissKeyguard);
- }
-
/**
* Dismisses the keyguard and shows bouncer if authentication is necessary.
*/
@@ -1268,61 +1189,4 @@ public class CarStatusBar extends StatusBar implements CarBatteryController.Batt
return true;
}
}
-
- /**
- * SystemUi version of the notification manager that overrides methods such that the
- * notifications end up in the status bar layouts instead of a standalone window.
- */
- private class CarSystemUIHeadsUpNotificationManager extends CarHeadsUpNotificationManager {
-
- CarSystemUIHeadsUpNotificationManager(Context context,
- NotificationClickHandlerFactory clickHandlerFactory,
- NotificationDataManager notificationDataManager) {
- super(context, clickHandlerFactory, notificationDataManager);
- }
-
- @Override
- protected View createHeadsUpPanel() {
- // In SystemUi the view is already in the window so just return a reference.
- return mNotificationShadeWindowView.findViewById(R.id.notification_headsup);
- }
-
- @Override
- protected void addHeadsUpPanelToDisplay() {
- // Set the panel initial state to invisible
- mHeadsUpPanel.setVisibility(View.INVISIBLE);
- }
-
- @Override
- protected void setInternalInsetsInfo(ViewTreeObserver.InternalInsetsInfo info,
- HeadsUpEntry currentNotification, boolean panelExpanded) {
- super.setInternalInsetsInfo(info, currentNotification, mPanelExpanded);
- }
-
- @Override
- protected void setHeadsUpVisible() {
- // if the Notifications panel is showing or SUW for user is in progress then don't show
- // heads up notifications
- if ((!mEnableHeadsUpNotificationWhenNotificationShadeOpen && mPanelExpanded)
- || !isDeviceSetupForUser()) {
- return;
- }
-
- super.setHeadsUpVisible();
- if (mHeadsUpPanel.getVisibility() == View.VISIBLE) {
- mNotificationShadeWindowController.setHeadsUpShowing(true);
- mStatusBarWindowController.setForceStatusBarVisible(true);
- }
- }
-
- @Override
- protected void removeNotificationFromPanel(HeadsUpEntry currentHeadsUpNotification) {
- super.removeNotificationFromPanel(currentHeadsUpNotification);
- // If the panel ended up empty and hidden we can remove it from SystemUi
- if (mHeadsUpPanel.getVisibility() != View.VISIBLE) {
- mNotificationShadeWindowController.setHeadsUpShowing(false);
- mStatusBarWindowController.setForceStatusBarVisible(false);
- }
- }
- }
}
diff --git a/packages/CarSystemUI/src/com/android/systemui/statusbar/car/CarStatusBarKeyguardViewManager.java b/packages/CarSystemUI/src/com/android/systemui/statusbar/car/CarStatusBarKeyguardViewManager.java
index 59f9f94c4d05..e1c051f5012d 100644
--- a/packages/CarSystemUI/src/com/android/systemui/statusbar/car/CarStatusBarKeyguardViewManager.java
+++ b/packages/CarSystemUI/src/com/android/systemui/statusbar/car/CarStatusBarKeyguardViewManager.java
@@ -33,6 +33,9 @@ import com.android.systemui.statusbar.phone.StatusBarKeyguardViewManager;
import com.android.systemui.statusbar.policy.ConfigurationController;
import com.android.systemui.statusbar.policy.KeyguardStateController;
+import java.util.HashSet;
+import java.util.Set;
+
import javax.inject.Inject;
import javax.inject.Singleton;
@@ -42,7 +45,7 @@ public class CarStatusBarKeyguardViewManager extends StatusBarKeyguardViewManage
protected boolean mShouldHideNavBar;
private final CarNavigationBarController mCarNavigationBarController;
- private final FullscreenUserSwitcher mFullscreenUserSwitcher;
+ private Set<OnKeyguardCancelClickedListener> mKeygaurdCancelClickedListenerSet;
@Inject
public CarStatusBarKeyguardViewManager(Context context,
@@ -56,8 +59,7 @@ public class CarStatusBarKeyguardViewManager extends StatusBarKeyguardViewManage
NotificationShadeWindowController notificationShadeWindowController,
KeyguardStateController keyguardStateController,
NotificationMediaManager notificationMediaManager,
- CarNavigationBarController carNavigationBarController,
- FullscreenUserSwitcher fullscreenUserSwitcher) {
+ CarNavigationBarController carNavigationBarController) {
super(context, callback, lockPatternUtils, sysuiStatusBarStateController,
configurationController, keyguardUpdateMonitor, navigationModeController,
dockManager, notificationShadeWindowController, keyguardStateController,
@@ -65,7 +67,7 @@ public class CarStatusBarKeyguardViewManager extends StatusBarKeyguardViewManage
mShouldHideNavBar = context.getResources()
.getBoolean(R.bool.config_hideNavWhenKeyguardBouncerShown);
mCarNavigationBarController = carNavigationBarController;
- mFullscreenUserSwitcher = fullscreenUserSwitcher;
+ mKeygaurdCancelClickedListenerSet = new HashSet<>();
}
@Override
@@ -95,7 +97,7 @@ public class CarStatusBarKeyguardViewManager extends StatusBarKeyguardViewManage
*/
@Override
public void onCancelClicked() {
- mFullscreenUserSwitcher.show();
+ mKeygaurdCancelClickedListenerSet.forEach(OnKeyguardCancelClickedListener::onCancelClicked);
}
/**
@@ -105,4 +107,31 @@ public class CarStatusBarKeyguardViewManager extends StatusBarKeyguardViewManage
*/
@Override
public void onDensityOrFontScaleChanged() { }
+
+ /**
+ * Add listener for keyguard cancel clicked.
+ */
+ public void addOnKeyguardCancelClickedListener(
+ OnKeyguardCancelClickedListener keyguardCancelClickedListener) {
+ mKeygaurdCancelClickedListenerSet.add(keyguardCancelClickedListener);
+ }
+
+ /**
+ * Remove listener for keyguard cancel clicked.
+ */
+ public void removeOnKeyguardCancelClickedListener(
+ OnKeyguardCancelClickedListener keyguardCancelClickedListener) {
+ mKeygaurdCancelClickedListenerSet.remove(keyguardCancelClickedListener);
+ }
+
+
+ /**
+ * Defines a callback for keyguard cancel button clicked listeners.
+ */
+ public interface OnKeyguardCancelClickedListener {
+ /**
+ * Called when keyguard cancel button is clicked.
+ */
+ void onCancelClicked();
+ }
}
diff --git a/packages/CarSystemUI/src/com/android/systemui/statusbar/car/CarStatusBarModule.java b/packages/CarSystemUI/src/com/android/systemui/statusbar/car/CarStatusBarModule.java
index 07c42e17d006..4754118e7a64 100644
--- a/packages/CarSystemUI/src/com/android/systemui/statusbar/car/CarStatusBarModule.java
+++ b/packages/CarSystemUI/src/com/android/systemui/statusbar/car/CarStatusBarModule.java
@@ -23,6 +23,9 @@ import android.os.Handler;
import android.os.PowerManager;
import android.util.DisplayMetrics;
+import com.android.car.notification.CarNotificationListener;
+import com.android.car.notification.CarUxRestrictionManagerWrapper;
+import com.android.car.notification.NotificationDataManager;
import com.android.internal.logging.MetricsLogger;
import com.android.keyguard.KeyguardUpdateMonitor;
import com.android.keyguard.ViewMediatorCallback;
@@ -30,8 +33,8 @@ import com.android.systemui.InitController;
import com.android.systemui.assist.AssistManager;
import com.android.systemui.broadcast.BroadcastDispatcher;
import com.android.systemui.bubbles.BubbleController;
+import com.android.systemui.car.CarDeviceProvisionedController;
import com.android.systemui.car.CarServiceProvider;
-import com.android.systemui.car.SystemUIPrimaryWindowController;
import com.android.systemui.colorextraction.SysuiColorExtractor;
import com.android.systemui.dagger.qualifiers.UiBackground;
import com.android.systemui.keyguard.DismissCallbackRegistry;
@@ -94,7 +97,6 @@ import com.android.systemui.statusbar.phone.dagger.StatusBarComponent;
import com.android.systemui.statusbar.phone.dagger.StatusBarPhoneDependenciesModule;
import com.android.systemui.statusbar.policy.BatteryController;
import com.android.systemui.statusbar.policy.ConfigurationController;
-import com.android.systemui.statusbar.policy.DeviceProvisionedController;
import com.android.systemui.statusbar.policy.ExtensionController;
import com.android.systemui.statusbar.policy.KeyguardStateController;
import com.android.systemui.statusbar.policy.NetworkController;
@@ -165,7 +167,7 @@ public class CarStatusBarModule {
BubbleController bubbleController,
NotificationGroupManager groupManager,
VisualStabilityManager visualStabilityManager,
- DeviceProvisionedController deviceProvisionedController,
+ CarDeviceProvisionedController carDeviceProvisionedController,
NavigationBarController navigationBarController,
Lazy<AssistManager> assistManagerLazy,
ConfigurationController configurationController,
@@ -205,10 +207,11 @@ public class CarStatusBarModule {
StatusBarTouchableRegionManager statusBarTouchableRegionManager,
CarServiceProvider carServiceProvider,
Lazy<PowerManagerHelper> powerManagerHelperLazy,
- FullscreenUserSwitcher fullscreenUserSwitcher,
- SystemUIPrimaryWindowController systemUIPrimaryWindowController,
CarNavigationBarController carNavigationBarController,
- FlingAnimationUtils.Builder flingAnimationUtilsBuilder) {
+ FlingAnimationUtils.Builder flingAnimationUtilsBuilder,
+ NotificationDataManager notificationDataManager,
+ CarUxRestrictionManagerWrapper carUxRestrictionManagerWrapper,
+ CarNotificationListener carNotificationListener) {
return new CarStatusBar(
context,
notificationsController,
@@ -249,7 +252,7 @@ public class CarStatusBarModule {
bubbleController,
groupManager,
visualStabilityManager,
- deviceProvisionedController,
+ carDeviceProvisionedController,
navigationBarController,
assistManagerLazy,
configurationController,
@@ -288,9 +291,10 @@ public class CarStatusBarModule {
statusBarTouchableRegionManager,
carServiceProvider,
powerManagerHelperLazy,
- fullscreenUserSwitcher,
- systemUIPrimaryWindowController,
carNavigationBarController,
- flingAnimationUtilsBuilder);
+ flingAnimationUtilsBuilder,
+ notificationDataManager,
+ carUxRestrictionManagerWrapper,
+ carNotificationListener);
}
}
diff --git a/packages/CarSystemUI/src/com/android/systemui/statusbar/car/FullscreenUserSwitcher.java b/packages/CarSystemUI/src/com/android/systemui/statusbar/car/FullscreenUserSwitcher.java
deleted file mode 100644
index 3cd66c232717..000000000000
--- a/packages/CarSystemUI/src/com/android/systemui/statusbar/car/FullscreenUserSwitcher.java
+++ /dev/null
@@ -1,271 +0,0 @@
-/*
- * Copyright (C) 2018 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.systemui.statusbar.car;
-
-import android.animation.Animator;
-import android.animation.AnimatorListenerAdapter;
-import android.car.Car;
-import android.car.trust.CarTrustAgentEnrollmentManager;
-import android.car.userlib.CarUserManagerHelper;
-import android.content.BroadcastReceiver;
-import android.content.Context;
-import android.content.Intent;
-import android.content.IntentFilter;
-import android.content.pm.UserInfo;
-import android.content.res.Resources;
-import android.os.UserHandle;
-import android.os.UserManager;
-import android.util.Log;
-import android.view.View;
-import android.view.ViewStub;
-
-import androidx.recyclerview.widget.GridLayoutManager;
-
-import com.android.internal.widget.LockPatternUtils;
-import com.android.systemui.R;
-import com.android.systemui.car.CarServiceProvider;
-import com.android.systemui.car.SystemUIPrimaryWindowController;
-import com.android.systemui.dagger.qualifiers.Main;
-import com.android.systemui.statusbar.car.CarTrustAgentUnlockDialogHelper.OnHideListener;
-import com.android.systemui.statusbar.car.UserGridRecyclerView.UserRecord;
-
-import javax.inject.Inject;
-import javax.inject.Singleton;
-
-/**
- * Manages the fullscreen user switcher.
- */
-@Singleton
-public class FullscreenUserSwitcher {
- private static final String TAG = FullscreenUserSwitcher.class.getSimpleName();
- private final Context mContext;
- private final Resources mResources;
- private final UserManager mUserManager;
- private final CarServiceProvider mCarServiceProvider;
- private final CarTrustAgentUnlockDialogHelper mUnlockDialogHelper;
- private final SystemUIPrimaryWindowController mSystemUIPrimaryWindowController;
- private CarStatusBar mCarStatusBar;
- private final int mShortAnimDuration;
-
- private View mParent;
- private UserGridRecyclerView mUserGridView;
- private CarTrustAgentEnrollmentManager mEnrollmentManager;
- private UserGridRecyclerView.UserRecord mSelectedUser;
- private CarUserManagerHelper mCarUserManagerHelper;
- private final BroadcastReceiver mUserUnlockReceiver = new BroadcastReceiver() {
- @Override
- public void onReceive(Context context, Intent intent) {
- if (Log.isLoggable(TAG, Log.DEBUG)) {
- Log.d(TAG, "user 0 is unlocked, SharedPreference is accessible.");
- }
- showDialogForInitialUser();
- mContext.unregisterReceiver(mUserUnlockReceiver);
- }
- };
-
- @Inject
- public FullscreenUserSwitcher(
- Context context,
- @Main Resources resources,
- UserManager userManager,
- CarServiceProvider carServiceProvider,
- CarTrustAgentUnlockDialogHelper carTrustAgentUnlockDialogHelper,
- SystemUIPrimaryWindowController systemUIPrimaryWindowController) {
- mContext = context;
- mResources = resources;
- mUserManager = userManager;
- mCarServiceProvider = carServiceProvider;
- mUnlockDialogHelper = carTrustAgentUnlockDialogHelper;
- mSystemUIPrimaryWindowController = systemUIPrimaryWindowController;
-
- mShortAnimDuration = mResources.getInteger(android.R.integer.config_shortAnimTime);
- }
-
- /** Sets the status bar which gives an entry point to dismiss the keyguard. */
- // TODO: Remove this in favor of a keyguard controller.
- public void setStatusBar(CarStatusBar statusBar) {
- mCarStatusBar = statusBar;
- }
-
- /** Returns {@code true} if the user switcher already has a parent view. */
- public boolean isAttached() {
- return mParent != null;
- }
-
- /** Sets the {@link ViewStub} to show the user switcher. */
- public void setContainer(ViewStub containerStub) {
- if (isAttached()) {
- return;
- }
-
- mParent = containerStub.inflate();
-
- View container = mParent.findViewById(R.id.container);
-
- // Initialize user grid.
- mUserGridView = container.findViewById(R.id.user_grid);
- GridLayoutManager layoutManager = new GridLayoutManager(mContext,
- mResources.getInteger(R.integer.user_fullscreen_switcher_num_col));
- mUserGridView.setLayoutManager(layoutManager);
- mUserGridView.buildAdapter();
- mUserGridView.setUserSelectionListener(this::onUserSelected);
- mCarUserManagerHelper = new CarUserManagerHelper(mContext);
- mCarServiceProvider.addListener(
- car -> mEnrollmentManager = (CarTrustAgentEnrollmentManager) car.getCarManager(
- Car.CAR_TRUST_AGENT_ENROLLMENT_SERVICE));
-
- IntentFilter filter = new IntentFilter(Intent.ACTION_USER_UNLOCKED);
- if (mUserManager.isUserUnlocked(UserHandle.USER_SYSTEM)) {
- // User0 is unlocked, switched to the initial user
- showDialogForInitialUser();
- } else {
- // listen to USER_UNLOCKED
- mContext.registerReceiverAsUser(mUserUnlockReceiver,
- UserHandle.getUserHandleForUid(UserHandle.USER_SYSTEM),
- filter,
- /* broadcastPermission= */ null,
- /* scheduler */ null);
- }
- }
-
- private void showDialogForInitialUser() {
- int initialUser = mCarUserManagerHelper.getInitialUser();
- UserInfo initialUserInfo = mUserManager.getUserInfo(initialUser);
- mSelectedUser = new UserRecord(initialUserInfo, UserRecord.FOREGROUND_USER);
-
- // If the initial user has screen lock and trusted device, display the unlock dialog on the
- // keyguard.
- if (hasScreenLock(initialUser) && hasTrustedDevice(initialUser)) {
- mUnlockDialogHelper.showUnlockDialogAfterDelay(initialUser,
- mOnHideListener);
- } else {
- // If no trusted device, dismiss the keyguard.
- dismissUserSwitcher();
- }
- }
-
- /**
- * Makes user grid visible.
- */
- public void show() {
- if (!isAttached()) {
- return;
- }
- mParent.setVisibility(View.VISIBLE);
- mSystemUIPrimaryWindowController.setWindowExpanded(true);
- }
-
- /**
- * Hides the user grid.
- */
- public void hide() {
- if (!isAttached()) {
- return;
- }
- mParent.setVisibility(View.INVISIBLE);
- mSystemUIPrimaryWindowController.setWindowExpanded(false);
- }
-
- /**
- * @return {@code true} if user grid is visible, {@code false} otherwise.
- */
- public boolean isVisible() {
- if (!isAttached()) {
- return false;
- }
- return mParent.getVisibility() == View.VISIBLE;
- }
-
- /**
- * Every time user clicks on an item in the switcher, if the clicked user has no trusted device,
- * we hide the switcher, either gradually or immediately.
- *
- * If the user has trusted device, we show an unlock dialog to notify user the unlock state.
- * When the unlock dialog is dismissed by user, we hide the unlock dialog and the switcher.
- *
- * We dismiss the entire keyguard when we hide the switcher if user clicked on the foreground
- * user (user we're already logged in as).
- */
- private void onUserSelected(UserGridRecyclerView.UserRecord record) {
- mSelectedUser = record;
- if (record.mInfo != null) {
- if (hasScreenLock(record.mInfo.id) && hasTrustedDevice(record.mInfo.id)) {
- mUnlockDialogHelper.showUnlockDialog(record.mInfo.id, mOnHideListener);
- return;
- }
- if (Log.isLoggable(TAG, Log.DEBUG)) {
- Log.d(TAG, "no trusted device enrolled for uid: " + record.mInfo.id);
- }
- }
- dismissUserSwitcher();
- }
-
- private void dismissUserSwitcher() {
- if (mSelectedUser == null) {
- Log.e(TAG, "Request to dismiss user switcher, but no user selected");
- return;
- }
- if (mSelectedUser.mType == UserRecord.FOREGROUND_USER) {
- hide();
- mCarStatusBar.dismissKeyguard();
- return;
- }
- // Switching is about to happen, since it takes time, fade out the switcher gradually.
- fadeOut();
- }
-
- private void fadeOut() {
- mUserGridView.animate()
- .alpha(0.0f)
- .setDuration(mShortAnimDuration)
- .setListener(new AnimatorListenerAdapter() {
- @Override
- public void onAnimationEnd(Animator animation) {
- hide();
- mUserGridView.setAlpha(1.0f);
- }
- });
-
- }
-
- private boolean hasScreenLock(int uid) {
- LockPatternUtils lockPatternUtils = new LockPatternUtils(mContext);
- return lockPatternUtils.getCredentialTypeForUser(uid)
- != LockPatternUtils.CREDENTIAL_TYPE_NONE;
- }
-
- private boolean hasTrustedDevice(int uid) {
- if (mEnrollmentManager == null) { // car service not ready, so it cannot be available.
- return false;
- }
- return !mEnrollmentManager.getEnrolledDeviceInfoForUser(uid).isEmpty();
- }
-
- private OnHideListener mOnHideListener = new OnHideListener() {
- @Override
- public void onHide(boolean dismissUserSwitcher) {
- if (dismissUserSwitcher) {
- dismissUserSwitcher();
- } else {
- // Re-draw the parent view, otherwise the unlock dialog will not be removed from
- // the screen immediately.
- mParent.invalidate();
- }
-
- }
- };
-}
diff --git a/packages/CarSystemUI/src/com/android/systemui/window/OverlayViewController.java b/packages/CarSystemUI/src/com/android/systemui/window/OverlayViewController.java
new file mode 100644
index 000000000000..6e0db4f317ba
--- /dev/null
+++ b/packages/CarSystemUI/src/com/android/systemui/window/OverlayViewController.java
@@ -0,0 +1,123 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.window;
+
+import android.view.View;
+import android.view.ViewGroup;
+import android.view.ViewStub;
+
+/**
+ * Owns a {@link View} that is present in SystemUIOverlayWindow.
+ */
+public class OverlayViewController {
+ private final int mStubId;
+ private final OverlayViewGlobalStateController mOverlayViewGlobalStateController;
+
+ private View mLayout;
+
+ public OverlayViewController(int stubId,
+ OverlayViewGlobalStateController overlayViewGlobalStateController) {
+ mLayout = null;
+ mStubId = stubId;
+ mOverlayViewGlobalStateController = overlayViewGlobalStateController;
+ }
+
+ /**
+ * Shows content of {@link OverlayViewController}.
+ *
+ * Should be used to show view externally and in particular by {@link OverlayViewMediator}.
+ */
+ public final void start() {
+ mOverlayViewGlobalStateController.showView(/* viewController= */ this, this::show);
+ }
+
+ /**
+ * Hides content of {@link OverlayViewController}.
+ *
+ * Should be used to hide view externally and in particular by {@link OverlayViewMediator}.
+ */
+ public final void stop() {
+ mOverlayViewGlobalStateController.hideView(/* viewController= */ this, this::hide);
+ }
+
+
+ /**
+ * Inflate layout owned by controller.
+ */
+ public final void inflate(ViewGroup baseLayout) {
+ ViewStub viewStub = baseLayout.findViewById(mStubId);
+ mLayout = viewStub.inflate();
+ onFinishInflate();
+ }
+
+ /**
+ * Called once inflate finishes.
+ */
+ protected void onFinishInflate() {
+ // no-op
+ }
+
+ /**
+ * Returns [@code true} if layout owned by controller has been inflated.
+ */
+ public final boolean isInflated() {
+ return mLayout != null;
+ }
+
+ private void show() {
+ if (mLayout == null) {
+ // layout must be inflated before show() is called.
+ return;
+ }
+ showInternal();
+ }
+
+ /**
+ * Subclasses should override this method to implement reveal animations and implement logic
+ * specific to when the layout owned by the controller is shown.
+ *
+ * Should only be overridden by Superclass but not called by any {@link OverlayViewMediator}.
+ */
+ protected void showInternal() {
+ mLayout.setVisibility(View.VISIBLE);
+ }
+
+ private void hide() {
+ if (mLayout == null) {
+ // layout must be inflated before hide() is called.
+ return;
+ }
+ hideInternal();
+ }
+
+ /**
+ * Subclasses should override this method to implement conceal animations and implement logic
+ * specific to when the layout owned by the controller is hidden.
+ *
+ * Should only be overridden by Superclass but not called by any {@link OverlayViewMediator}.
+ */
+ protected void hideInternal() {
+ mLayout.setVisibility(View.GONE);
+ }
+
+ /**
+ * Provides access to layout owned by controller.
+ */
+ protected final View getLayout() {
+ return mLayout;
+ }
+}
diff --git a/packages/CarSystemUI/src/com/android/systemui/window/OverlayViewGlobalStateController.java b/packages/CarSystemUI/src/com/android/systemui/window/OverlayViewGlobalStateController.java
new file mode 100644
index 000000000000..2d4a9e6331d2
--- /dev/null
+++ b/packages/CarSystemUI/src/com/android/systemui/window/OverlayViewGlobalStateController.java
@@ -0,0 +1,112 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.window;
+
+import android.util.Log;
+
+import androidx.annotation.VisibleForTesting;
+
+import com.android.systemui.navigationbar.car.CarNavigationBarController;
+
+import java.util.HashSet;
+import java.util.Set;
+
+import javax.inject.Inject;
+import javax.inject.Singleton;
+
+/**
+ * This controller is responsible for the following:
+ * <p><ul>
+ * <li>Holds the global state for SystemUIOverlayWindow.
+ * <li>Allows {@link SystemUIOverlayWindowManager} to register {@link OverlayViewMediator}(s).
+ * <li>Enables {@link OverlayViewController)(s) to reveal/conceal themselves while respecting the
+ * global state of SystemUIOverlayWindow.
+ * </ul>
+ */
+@Singleton
+public class OverlayViewGlobalStateController {
+ private static final String TAG = OverlayViewGlobalStateController.class.getSimpleName();
+ private final SystemUIOverlayWindowController mSystemUIOverlayWindowController;
+ private final CarNavigationBarController mCarNavigationBarController;
+ @VisibleForTesting
+ Set<String> mShownSet;
+
+ @Inject
+ public OverlayViewGlobalStateController(
+ CarNavigationBarController carNavigationBarController,
+ SystemUIOverlayWindowController systemUIOverlayWindowController) {
+ mSystemUIOverlayWindowController = systemUIOverlayWindowController;
+ mSystemUIOverlayWindowController.attach();
+ mCarNavigationBarController = carNavigationBarController;
+ mShownSet = new HashSet<>();
+ }
+
+ /**
+ * Register {@link OverlayViewMediator} to use in SystemUIOverlayWindow.
+ */
+ public void registerMediator(OverlayViewMediator overlayViewMediator) {
+ Log.d(TAG, "Registering content mediator: " + overlayViewMediator.getClass().getName());
+
+ overlayViewMediator.registerListeners();
+ overlayViewMediator.setupOverlayContentViewControllers();
+ }
+
+ /**
+ * Show content in Overlay Window.
+ */
+ public void showView(OverlayViewController viewController, Runnable show) {
+ if (mShownSet.isEmpty()) {
+ mCarNavigationBarController.hideBars();
+ mSystemUIOverlayWindowController.setWindowExpanded(true);
+ }
+
+ if (!viewController.isInflated()) {
+ viewController.inflate(mSystemUIOverlayWindowController.getBaseLayout());
+ }
+
+ show.run();
+ mShownSet.add(viewController.getClass().getName());
+
+ Log.d(TAG, "Content shown: " + viewController.getClass().getName());
+ }
+
+ /**
+ * Hide content in Overlay Window.
+ */
+ public void hideView(OverlayViewController viewController, Runnable hide) {
+ if (!viewController.isInflated()) {
+ Log.d(TAG, "Content cannot be hidden since it isn't inflated: "
+ + viewController.getClass().getName());
+ return;
+ }
+ if (!mShownSet.contains(viewController.getClass().getName())) {
+ Log.d(TAG, "Content cannot be hidden since it isn't shown: "
+ + viewController.getClass().getName());
+ return;
+ }
+
+ hide.run();
+ mShownSet.remove(viewController.getClass().getName());
+
+ if (mShownSet.isEmpty()) {
+ mCarNavigationBarController.showBars();
+ mSystemUIOverlayWindowController.setWindowExpanded(false);
+ }
+
+ Log.d(TAG, "Content hidden: " + viewController.getClass().getName());
+ }
+}
diff --git a/apex/appsearch/framework/java/android/app/appsearch/IllegalSearchSpecException.java b/packages/CarSystemUI/src/com/android/systemui/window/OverlayViewMediator.java
index 0d029f029ee5..7c34fb494de6 100644
--- a/apex/appsearch/framework/java/android/app/appsearch/IllegalSearchSpecException.java
+++ b/packages/CarSystemUI/src/com/android/systemui/window/OverlayViewMediator.java
@@ -14,23 +14,21 @@
* limitations under the License.
*/
-package android.app.appsearch;
-
-import android.annotation.NonNull;
+package com.android.systemui.window;
/**
- * Indicates that a {@link android.app.appsearch.SearchResults} has logical inconsistencies such
- * as unpopulated mandatory fields or illegal combinations of parameters.
- *
- * @hide
+ * Controls when to show and hide {@link OverlayViewController}(s).
*/
-public class IllegalSearchSpecException extends IllegalArgumentException {
+public interface OverlayViewMediator {
+
+ /**
+ * Register listeners that could use ContentVisibilityAdjuster to show/hide content.
+ */
+ void registerListeners();
+
/**
- * Constructs a new {@link IllegalSearchSpecException}.
- *
- * @param message A developer-readable description of the issue with the bundle.
+ * Allows for post-inflation callbacks and listeners to be set inside required {@link
+ * OverlayViewController}(s).
*/
- public IllegalSearchSpecException(@NonNull String message) {
- super(message);
- }
+ void setupOverlayContentViewControllers();
}
diff --git a/packages/CarSystemUI/src/com/android/systemui/window/OverlayWindowModule.java b/packages/CarSystemUI/src/com/android/systemui/window/OverlayWindowModule.java
new file mode 100644
index 000000000000..b0e308966477
--- /dev/null
+++ b/packages/CarSystemUI/src/com/android/systemui/window/OverlayWindowModule.java
@@ -0,0 +1,37 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.window;
+
+import com.android.systemui.car.userswitcher.FullscreenUserSwitcherViewMediator;
+
+import dagger.Binds;
+import dagger.Module;
+import dagger.multibindings.ClassKey;
+import dagger.multibindings.IntoMap;
+
+/**
+ * Dagger injection module for {@link SystemUIOverlayWindowManager}
+ */
+@Module
+public abstract class OverlayWindowModule {
+ /** Inject into FullscreenUserSwitcherViewsMediator. */
+ @Binds
+ @IntoMap
+ @ClassKey(FullscreenUserSwitcherViewMediator.class)
+ public abstract OverlayViewMediator bindFullscreenUserSwitcherViewsMediator(
+ FullscreenUserSwitcherViewMediator overlayViewsMediator);
+}
diff --git a/packages/CarSystemUI/src/com/android/systemui/car/SystemUIPrimaryWindowController.java b/packages/CarSystemUI/src/com/android/systemui/window/SystemUIOverlayWindowController.java
index 3f55ac8ccace..9c456eecc1ac 100644
--- a/packages/CarSystemUI/src/com/android/systemui/car/SystemUIPrimaryWindowController.java
+++ b/packages/CarSystemUI/src/com/android/systemui/window/SystemUIOverlayWindowController.java
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-package com.android.systemui.car;
+package com.android.systemui.window;
import static android.view.WindowManager.LayoutParams.LAYOUT_IN_DISPLAY_CUTOUT_MODE_ALWAYS;
@@ -41,7 +41,7 @@ import javax.inject.Singleton;
* this window for the notification panel.
*/
@Singleton
-public class SystemUIPrimaryWindowController implements
+public class SystemUIOverlayWindowController implements
ConfigurationController.ConfigurationListener {
private final Context mContext;
@@ -57,7 +57,7 @@ public class SystemUIPrimaryWindowController implements
private boolean mIsAttached = false;
@Inject
- public SystemUIPrimaryWindowController(
+ public SystemUIOverlayWindowController(
Context context,
@Main Resources resources,
WindowManager windowManager,
@@ -77,7 +77,7 @@ public class SystemUIPrimaryWindowController implements
mLpChanged = new WindowManager.LayoutParams();
mBaseLayout = (ViewGroup) LayoutInflater.from(context)
- .inflate(R.layout.sysui_primary_window, /* root= */ null, false);
+ .inflate(R.layout.sysui_overlay_window, /* root= */ null, false);
configurationController.addCallback(this);
}
@@ -115,7 +115,7 @@ public class SystemUIPrimaryWindowController implements
mLp.gravity = Gravity.TOP;
mLp.setFitInsetsTypes(/* types= */ 0);
mLp.softInputMode = WindowManager.LayoutParams.SOFT_INPUT_ADJUST_RESIZE;
- mLp.setTitle("SystemUIPrimaryWindow");
+ mLp.setTitle("SystemUIOverlayWindow");
mLp.packageName = mContext.getPackageName();
mLp.layoutInDisplayCutoutMode = LAYOUT_IN_DISPLAY_CUTOUT_MODE_ALWAYS;
diff --git a/packages/CarSystemUI/src/com/android/systemui/window/SystemUIOverlayWindowManager.java b/packages/CarSystemUI/src/com/android/systemui/window/SystemUIOverlayWindowManager.java
new file mode 100644
index 000000000000..af0f17d50ee2
--- /dev/null
+++ b/packages/CarSystemUI/src/com/android/systemui/window/SystemUIOverlayWindowManager.java
@@ -0,0 +1,92 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.window;
+
+import android.content.Context;
+
+import com.android.systemui.R;
+import com.android.systemui.SystemUI;
+
+import java.lang.reflect.Constructor;
+import java.lang.reflect.InvocationTargetException;
+import java.util.Map;
+
+import javax.inject.Inject;
+import javax.inject.Provider;
+import javax.inject.Singleton;
+
+/**
+ * Registers {@link OverlayViewMediator}(s) and synchronizes their calls to hide/show {@link
+ * OverlayViewController}(s) to allow for the correct visibility of system bars.
+ */
+@Singleton
+public class SystemUIOverlayWindowManager extends SystemUI {
+ private static final String TAG = "SystemUIOverlayWindowManager";
+ private final Map<Class<?>, Provider<OverlayViewMediator>>
+ mContentMediatorCreators;
+ private final OverlayViewGlobalStateController mOverlayViewGlobalStateController;
+
+ @Inject
+ public SystemUIOverlayWindowManager(
+ Context context,
+ Map<Class<?>, Provider<OverlayViewMediator>> contentMediatorCreators,
+ OverlayViewGlobalStateController overlayViewGlobalStateController) {
+ super(context);
+ mContentMediatorCreators = contentMediatorCreators;
+ mOverlayViewGlobalStateController = overlayViewGlobalStateController;
+ }
+
+ @Override
+ public void start() {
+ String[] names = mContext.getResources().getStringArray(
+ R.array.config_carSystemUIOverlayViewsMediators);
+ startServices(names);
+ }
+
+ private void startServices(String[] services) {
+ for (String clsName : services) {
+ try {
+ OverlayViewMediator obj = resolveContentMediator(clsName);
+ if (obj == null) {
+ Constructor constructor = Class.forName(clsName).getConstructor(Context.class);
+ obj = (OverlayViewMediator) constructor.newInstance(this);
+ }
+ mOverlayViewGlobalStateController.registerMediator(obj);
+ } catch (ClassNotFoundException
+ | NoSuchMethodException
+ | IllegalAccessException
+ | InstantiationException
+ | InvocationTargetException ex) {
+ throw new RuntimeException(ex);
+ }
+ }
+ }
+
+ private OverlayViewMediator resolveContentMediator(String className) {
+ return resolve(className, mContentMediatorCreators);
+ }
+
+ private <T> T resolve(String className, Map<Class<?>, Provider<T>> creators) {
+ try {
+ Class<?> clazz = Class.forName(className);
+ Provider<T> provider = creators.get(clazz);
+ return provider == null ? null : provider.get();
+ } catch (ClassNotFoundException e) {
+ return null;
+ }
+ }
+}
diff --git a/packages/CarSystemUI/tests/res/layout/overlay_view_controller_stub.xml b/packages/CarSystemUI/tests/res/layout/overlay_view_controller_stub.xml
new file mode 100644
index 000000000000..5e5efe7614fc
--- /dev/null
+++ b/packages/CarSystemUI/tests/res/layout/overlay_view_controller_stub.xml
@@ -0,0 +1,22 @@
+<!--
+ ~ Copyright (C) 2020 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ -->
+
+<LinearLayout
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:id="@+id/overlay_view_controller_test">
+</LinearLayout> \ No newline at end of file
diff --git a/packages/CarSystemUI/tests/res/layout/overlay_view_controller_test.xml b/packages/CarSystemUI/tests/res/layout/overlay_view_controller_test.xml
new file mode 100644
index 000000000000..165193e86c96
--- /dev/null
+++ b/packages/CarSystemUI/tests/res/layout/overlay_view_controller_test.xml
@@ -0,0 +1,30 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ ~ Copyright (C) 2020 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ -->
+
+<!-- Fullscreen views in sysui should be listed here in increasing Z order. -->
+<FrameLayout
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ android:background="@android:color/transparent"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent">
+
+ <ViewStub android:id="@+id/overlay_view_controller_stub"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:layout="@layout/overlay_view_controller_stub"/>
+
+</FrameLayout> \ No newline at end of file
diff --git a/packages/CarSystemUI/tests/src/com/android/systemui/car/notification/CarHeadsUpNotificationSystemContainerTest.java b/packages/CarSystemUI/tests/src/com/android/systemui/car/notification/CarHeadsUpNotificationSystemContainerTest.java
new file mode 100644
index 000000000000..05b8e6a54099
--- /dev/null
+++ b/packages/CarSystemUI/tests/src/com/android/systemui/car/notification/CarHeadsUpNotificationSystemContainerTest.java
@@ -0,0 +1,134 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.car.notification;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import static org.mockito.Mockito.when;
+
+import android.testing.AndroidTestingRunner;
+import android.testing.TestableLooper;
+import android.testing.TestableResources;
+import android.view.View;
+import android.view.WindowManager;
+
+import androidx.test.filters.SmallTest;
+
+import com.android.systemui.R;
+import com.android.systemui.SysuiTestCase;
+import com.android.systemui.car.CarDeviceProvisionedController;
+import com.android.systemui.statusbar.car.CarStatusBar;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+
+@RunWith(AndroidTestingRunner.class)
+@TestableLooper.RunWithLooper
+@SmallTest
+public class CarHeadsUpNotificationSystemContainerTest extends SysuiTestCase {
+ private CarHeadsUpNotificationSystemContainer mDefaultController;
+ private CarHeadsUpNotificationSystemContainer mOverrideEnabledController;
+ @Mock
+ private CarDeviceProvisionedController mCarDeviceProvisionedController;
+ @Mock
+ private CarStatusBar mCarStatusBar;
+ @Mock
+ private WindowManager mWindowManager;
+
+ @Mock
+ private View mNotificationView;
+ @Mock
+ private View mNotificationView2;
+
+ @Before
+ public void setUp() {
+ MockitoAnnotations.initMocks(this);
+
+ when(mCarStatusBar.isPanelExpanded()).thenReturn(false);
+ when(mCarDeviceProvisionedController.isCurrentUserSetup()).thenReturn(true);
+ when(mCarDeviceProvisionedController.isCurrentUserSetupInProgress()).thenReturn(false);
+
+ TestableResources testableResources = mContext.getOrCreateTestableResources();
+
+ testableResources.addOverride(
+ R.bool.config_enableHeadsUpNotificationWhenNotificationShadeOpen, false);
+
+ mDefaultController = new CarHeadsUpNotificationSystemContainer(mContext,
+ testableResources.getResources(), mCarDeviceProvisionedController, mWindowManager,
+ () -> mCarStatusBar);
+
+ testableResources.addOverride(
+ R.bool.config_enableHeadsUpNotificationWhenNotificationShadeOpen, true);
+
+ mOverrideEnabledController = new CarHeadsUpNotificationSystemContainer(mContext,
+ testableResources.getResources(), mCarDeviceProvisionedController, mWindowManager,
+ () -> mCarStatusBar);
+ }
+
+ @Test
+ public void testDisplayNotification_firstNotification_isVisible() {
+ mDefaultController.displayNotification(mNotificationView);
+ assertThat(mDefaultController.isVisible()).isTrue();
+ }
+
+ @Test
+ public void testRemoveNotification_lastNotification_isInvisible() {
+ mDefaultController.displayNotification(mNotificationView);
+ mDefaultController.removeNotification(mNotificationView);
+ assertThat(mDefaultController.isVisible()).isFalse();
+ }
+
+ @Test
+ public void testRemoveNotification_nonLastNotification_isVisible() {
+ mDefaultController.displayNotification(mNotificationView);
+ mDefaultController.displayNotification(mNotificationView2);
+ mDefaultController.removeNotification(mNotificationView);
+ assertThat(mDefaultController.isVisible()).isTrue();
+ }
+
+ @Test
+ public void testDisplayNotification_userSetupInProgress_isInvisible() {
+ when(mCarDeviceProvisionedController.isCurrentUserSetupInProgress()).thenReturn(true);
+ mDefaultController.displayNotification(mNotificationView);
+ assertThat(mDefaultController.isVisible()).isFalse();
+
+ }
+
+ @Test
+ public void testDisplayNotification_userSetupIncomplete_isInvisible() {
+ when(mCarDeviceProvisionedController.isCurrentUserSetup()).thenReturn(false);
+ mDefaultController.displayNotification(mNotificationView);
+ assertThat(mDefaultController.isVisible()).isFalse();
+ }
+
+ @Test
+ public void testDisplayNotification_notificationPanelExpanded_isInvisible() {
+ when(mCarStatusBar.isPanelExpanded()).thenReturn(true);
+ mDefaultController.displayNotification(mNotificationView);
+ assertThat(mDefaultController.isVisible()).isFalse();
+ }
+
+ @Test
+ public void testDisplayNotification_notificationPanelExpandedEnabledHUNWhenOpen_isVisible() {
+ when(mCarStatusBar.isPanelExpanded()).thenReturn(true);
+ mOverrideEnabledController.displayNotification(mNotificationView);
+ assertThat(mOverrideEnabledController.isVisible()).isTrue();
+ }
+}
diff --git a/packages/CarSystemUI/tests/src/com/android/systemui/navigationbar/car/CarNavigationBarTest.java b/packages/CarSystemUI/tests/src/com/android/systemui/navigationbar/car/CarNavigationBarTest.java
new file mode 100644
index 000000000000..c04e47f557f7
--- /dev/null
+++ b/packages/CarSystemUI/tests/src/com/android/systemui/navigationbar/car/CarNavigationBarTest.java
@@ -0,0 +1,122 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.navigationbar.car;
+
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+import android.os.Handler;
+import android.test.suitebuilder.annotation.SmallTest;
+import android.testing.AndroidTestingRunner;
+import android.testing.TestableLooper;
+import android.testing.TestableResources;
+import android.view.LayoutInflater;
+import android.view.WindowManager;
+
+import com.android.systemui.R;
+import com.android.systemui.SysuiTestCase;
+import com.android.systemui.car.CarDeviceProvisionedController;
+import com.android.systemui.plugins.DarkIconDispatcher;
+import com.android.systemui.statusbar.CommandQueue;
+import com.android.systemui.statusbar.NavigationBarController;
+import com.android.systemui.statusbar.SuperStatusBarViewFactory;
+import com.android.systemui.statusbar.phone.AutoHideController;
+import com.android.systemui.statusbar.phone.StatusBarIconController;
+import com.android.systemui.statusbar.phone.StatusBarWindowView;
+import com.android.systemui.statusbar.policy.KeyguardStateController;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.ArgumentCaptor;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+
+import dagger.Lazy;
+
+@RunWith(AndroidTestingRunner.class)
+@TestableLooper.RunWithLooper
+@SmallTest
+public class CarNavigationBarTest extends SysuiTestCase {
+
+ private CarNavigationBar mCarNavigationBar;
+ private TestableResources mTestableResources;
+ private Handler mHandler;
+
+ @Mock
+ private CarNavigationBarController mCarNavigationBarController;
+ @Mock
+ private WindowManager mWindowManager;
+ @Mock
+ private CarDeviceProvisionedController mDeviceProvisionedController;
+ @Mock
+ private AutoHideController mAutoHideController;
+ @Mock
+ private ButtonSelectionStateListener mButtonSelectionStateListener;
+ @Mock
+ private Lazy<KeyguardStateController> mKeyguardStateControllerLazy;
+ @Mock
+ private KeyguardStateController mKeyguardStateController;
+ @Mock
+ private Lazy<NavigationBarController> mNavigationBarControllerLazy;
+ @Mock
+ private NavigationBarController mNavigationBarController;
+ @Mock
+ private SuperStatusBarViewFactory mSuperStatusBarViewFactory;
+ @Mock
+ private ButtonSelectionStateController mButtonSelectionStateController;
+
+ @Before
+ public void setUp() {
+ MockitoAnnotations.initMocks(this);
+ mTestableResources = mContext.getOrCreateTestableResources();
+ mTestableResources.addOverride(R.bool.config_enableBottomNavigationBar, true);
+ mHandler = Handler.getMain();
+ mCarNavigationBar = new CarNavigationBar(mContext, mCarNavigationBarController,
+ mWindowManager, mDeviceProvisionedController, new CommandQueue(mContext),
+ mAutoHideController, mButtonSelectionStateListener, mHandler,
+ mKeyguardStateControllerLazy, mNavigationBarControllerLazy,
+ mSuperStatusBarViewFactory, mButtonSelectionStateController);
+ StatusBarWindowView statusBarWindowView = (StatusBarWindowView) LayoutInflater.from(
+ mContext).inflate(R.layout.super_status_bar, /* root= */ null);
+ when(mSuperStatusBarViewFactory.getStatusBarWindowView()).thenReturn(statusBarWindowView);
+ when(mNavigationBarControllerLazy.get()).thenReturn(mNavigationBarController);
+ when(mKeyguardStateControllerLazy.get()).thenReturn(mKeyguardStateController);
+ when(mKeyguardStateController.isShowing()).thenReturn(false);
+ mDependency.injectMockDependency(WindowManager.class);
+ // Needed to inflate top navigation bar.
+ mDependency.injectMockDependency(DarkIconDispatcher.class);
+ mDependency.injectMockDependency(StatusBarIconController.class);
+ }
+
+ @Test
+ public void restartNavbars_refreshesTaskChanged() {
+ ArgumentCaptor<CarDeviceProvisionedController.DeviceProvisionedListener>
+ deviceProvisionedCallbackCaptor = ArgumentCaptor.forClass(
+ CarDeviceProvisionedController.DeviceProvisionedListener.class);
+ when(mDeviceProvisionedController.isCurrentUserSetup()).thenReturn(true);
+ mCarNavigationBar.start();
+ // switching the currentUserSetup value to force restart the navbars.
+ when(mDeviceProvisionedController.isCurrentUserSetup()).thenReturn(false);
+ verify(mDeviceProvisionedController).addCallback(deviceProvisionedCallbackCaptor.capture());
+
+ deviceProvisionedCallbackCaptor.getValue().onUserSwitched();
+ waitForIdleSync(mHandler);
+
+ verify(mButtonSelectionStateListener).onTaskStackChanged();
+ }
+}
diff --git a/packages/CarSystemUI/tests/src/com/android/systemui/window/OverlayViewControllerTest.java b/packages/CarSystemUI/tests/src/com/android/systemui/window/OverlayViewControllerTest.java
new file mode 100644
index 000000000000..3be962627f62
--- /dev/null
+++ b/packages/CarSystemUI/tests/src/com/android/systemui/window/OverlayViewControllerTest.java
@@ -0,0 +1,158 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.window;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.Mockito.verify;
+
+import android.testing.AndroidTestingRunner;
+import android.testing.TestableLooper;
+import android.view.LayoutInflater;
+import android.view.ViewGroup;
+
+import androidx.test.filters.SmallTest;
+
+import com.android.systemui.SysuiTestCase;
+import com.android.systemui.tests.R;
+
+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;
+
+@RunWith(AndroidTestingRunner.class)
+@TestableLooper.RunWithLooper
+@SmallTest
+public class OverlayViewControllerTest extends SysuiTestCase {
+ private MockOverlayViewController mOverlayViewController;
+ private ViewGroup mBaseLayout;
+
+ @Mock
+ private OverlayViewGlobalStateController mOverlayViewGlobalStateController;
+
+ @Captor
+ private ArgumentCaptor<Runnable> mRunnableArgumentCaptor;
+
+ @Before
+ public void setUp() {
+ MockitoAnnotations.initMocks(/* testClass= */ this);
+
+ mOverlayViewController = new MockOverlayViewController(R.id.overlay_view_controller_stub,
+ mOverlayViewGlobalStateController);
+
+ mBaseLayout = (ViewGroup) LayoutInflater.from(mContext).inflate(
+ R.layout.overlay_view_controller_test, /* root= */ null);
+ }
+
+ @Test
+ public void inflate_layoutInitialized() {
+ mOverlayViewController.inflate(mBaseLayout);
+
+ assertThat(mOverlayViewController.getLayout().getId()).isEqualTo(
+ R.id.overlay_view_controller_test);
+ }
+
+ @Test
+ public void inflate_onFinishInflateCalled() {
+ mOverlayViewController.inflate(mBaseLayout);
+
+ assertThat(mOverlayViewController.mOnFinishInflateCalled).isTrue();
+ }
+
+ @Test
+ public void start_viewInflated_viewShown() {
+ mOverlayViewController.inflate(mBaseLayout);
+
+ mOverlayViewController.start();
+
+ verify(mOverlayViewGlobalStateController).showView(eq(mOverlayViewController),
+ mRunnableArgumentCaptor.capture());
+
+ mRunnableArgumentCaptor.getValue().run();
+
+ assertThat(mOverlayViewController.mShowInternalCalled).isTrue();
+ }
+
+ @Test
+ public void stop_viewInflated_viewHidden() {
+ mOverlayViewController.inflate(mBaseLayout);
+
+ mOverlayViewController.stop();
+
+ verify(mOverlayViewGlobalStateController).hideView(eq(mOverlayViewController),
+ mRunnableArgumentCaptor.capture());
+
+ mRunnableArgumentCaptor.getValue().run();
+
+ assertThat(mOverlayViewController.mHideInternalCalled).isTrue();
+ }
+
+ @Test
+ public void start_viewNotInflated_viewNotShown() {
+ mOverlayViewController.start();
+
+ verify(mOverlayViewGlobalStateController).showView(eq(mOverlayViewController),
+ mRunnableArgumentCaptor.capture());
+
+ mRunnableArgumentCaptor.getValue().run();
+
+ assertThat(mOverlayViewController.mShowInternalCalled).isFalse();
+ }
+
+ @Test
+ public void stop_viewNotInflated_viewNotHidden() {
+ mOverlayViewController.stop();
+
+ verify(mOverlayViewGlobalStateController).hideView(eq(mOverlayViewController),
+ mRunnableArgumentCaptor.capture());
+
+ mRunnableArgumentCaptor.getValue().run();
+
+ assertThat(mOverlayViewController.mHideInternalCalled).isFalse();
+ }
+
+ private static class MockOverlayViewController extends OverlayViewController {
+ boolean mOnFinishInflateCalled = false;
+ boolean mShowInternalCalled = false;
+ boolean mHideInternalCalled = false;
+
+ MockOverlayViewController(int stubId,
+ OverlayViewGlobalStateController overlayViewGlobalStateController) {
+ super(stubId, overlayViewGlobalStateController);
+ }
+
+ @Override
+ protected void onFinishInflate() {
+ mOnFinishInflateCalled = true;
+ }
+
+ @Override
+ protected void showInternal() {
+ mShowInternalCalled = true;
+ }
+
+ @Override
+ protected void hideInternal() {
+ mHideInternalCalled = true;
+ }
+ }
+}
diff --git a/packages/CarSystemUI/tests/src/com/android/systemui/window/OverlayViewGlobalStateControllerTest.java b/packages/CarSystemUI/tests/src/com/android/systemui/window/OverlayViewGlobalStateControllerTest.java
new file mode 100644
index 000000000000..03354d1aa9d7
--- /dev/null
+++ b/packages/CarSystemUI/tests/src/com/android/systemui/window/OverlayViewGlobalStateControllerTest.java
@@ -0,0 +1,250 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.window;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+import android.testing.AndroidTestingRunner;
+import android.testing.TestableLooper;
+import android.view.ViewGroup;
+import android.widget.FrameLayout;
+
+import androidx.test.filters.SmallTest;
+
+import com.android.systemui.SysuiTestCase;
+import com.android.systemui.navigationbar.car.CarNavigationBarController;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+
+@RunWith(AndroidTestingRunner.class)
+@TestableLooper.RunWithLooper
+@SmallTest
+public class OverlayViewGlobalStateControllerTest extends SysuiTestCase {
+ private static final String MOCK_OVERLAY_VIEW_CONTROLLER_NAME = "OverlayViewController";
+
+ private OverlayViewGlobalStateController mOverlayViewGlobalStateController;
+ private ViewGroup mBaseLayout;
+
+ @Mock
+ private CarNavigationBarController mCarNavigationBarController;
+ @Mock
+ private SystemUIOverlayWindowController mSystemUIOverlayWindowController;
+ @Mock
+ private OverlayViewMediator mOverlayViewMediator;
+ @Mock
+ private OverlayViewController mOverlayViewController;
+ @Mock
+ private Runnable mRunnable;
+
+ @Before
+ public void setUp() {
+ MockitoAnnotations.initMocks(/* testClass= */ this);
+
+ mOverlayViewGlobalStateController = new OverlayViewGlobalStateController(
+ mCarNavigationBarController, mSystemUIOverlayWindowController);
+
+ verify(mSystemUIOverlayWindowController).attach();
+
+ mBaseLayout = new FrameLayout(mContext);
+
+ when(mSystemUIOverlayWindowController.getBaseLayout()).thenReturn(mBaseLayout);
+ }
+
+ @Test
+ public void registerMediator_overlayViewMediatorListenersRegistered() {
+ mOverlayViewGlobalStateController.registerMediator(mOverlayViewMediator);
+
+ verify(mOverlayViewMediator).registerListeners();
+ }
+
+ @Test
+ public void registerMediator_overlayViewMediatorViewControllerSetup() {
+ mOverlayViewGlobalStateController.registerMediator(mOverlayViewMediator);
+
+ verify(mOverlayViewMediator).setupOverlayContentViewControllers();
+ }
+
+ @Test
+ public void showView_nothingAlreadyShown_navigationBarsHidden() {
+ mOverlayViewGlobalStateController.showView(mOverlayViewController, mRunnable);
+
+ verify(mCarNavigationBarController).hideBars();
+ }
+
+ @Test
+ public void showView_nothingAlreadyShown_windowIsExpanded() {
+ mOverlayViewGlobalStateController.showView(mOverlayViewController, mRunnable);
+
+ verify(mSystemUIOverlayWindowController).setWindowExpanded(true);
+ }
+
+ @Test
+ public void showView_somethingAlreadyShown_navigationBarsHidden() {
+ mOverlayViewGlobalStateController.mShownSet.add(MOCK_OVERLAY_VIEW_CONTROLLER_NAME);
+
+ mOverlayViewGlobalStateController.showView(mOverlayViewController, mRunnable);
+
+ verify(mCarNavigationBarController, never()).hideBars();
+ }
+
+ @Test
+ public void showView_somethingAlreadyShown_windowIsExpanded() {
+ mOverlayViewGlobalStateController.mShownSet.add(MOCK_OVERLAY_VIEW_CONTROLLER_NAME);
+
+ mOverlayViewGlobalStateController.showView(mOverlayViewController, mRunnable);
+
+ verify(mSystemUIOverlayWindowController, never()).setWindowExpanded(true);
+ }
+
+ @Test
+ public void showView_viewControllerNotInflated_inflateViewController() {
+ when(mOverlayViewController.isInflated()).thenReturn(false);
+
+ mOverlayViewGlobalStateController.showView(mOverlayViewController, mRunnable);
+
+ verify(mOverlayViewController).inflate(mBaseLayout);
+ }
+
+ @Test
+ public void showView_viewControllerInflated_inflateViewControllerNotCalled() {
+ when(mOverlayViewController.isInflated()).thenReturn(true);
+
+ mOverlayViewGlobalStateController.showView(mOverlayViewController, mRunnable);
+
+ verify(mOverlayViewController, never()).inflate(mBaseLayout);
+ }
+
+ @Test
+ public void showView_showRunnableCalled() {
+ mOverlayViewGlobalStateController.showView(mOverlayViewController, mRunnable);
+
+ verify(mRunnable).run();
+ }
+
+ @Test
+ public void showView_overlayViewControllerAddedToShownSet() {
+ mOverlayViewGlobalStateController.showView(mOverlayViewController, mRunnable);
+
+ assertThat(mOverlayViewGlobalStateController.mShownSet.contains(
+ mOverlayViewController.getClass().getName())).isTrue();
+ }
+
+ @Test
+ public void hideView_viewControllerNotInflated_hideRunnableNotCalled() {
+ when(mOverlayViewController.isInflated()).thenReturn(false);
+
+ mOverlayViewGlobalStateController.hideView(mOverlayViewController, mRunnable);
+
+ verify(mRunnable, never()).run();
+ }
+
+ @Test
+ public void hideView_nothingShown_hideRunnableNotCalled() {
+ when(mOverlayViewController.isInflated()).thenReturn(true);
+ mOverlayViewGlobalStateController.mShownSet.clear();
+
+ mOverlayViewGlobalStateController.hideView(mOverlayViewController, mRunnable);
+
+ verify(mRunnable, never()).run();
+ }
+
+ @Test
+ public void hideView_viewControllerNotShown_hideRunnableNotCalled() {
+ when(mOverlayViewController.isInflated()).thenReturn(true);
+ mOverlayViewGlobalStateController.mShownSet.add(MOCK_OVERLAY_VIEW_CONTROLLER_NAME);
+
+ mOverlayViewGlobalStateController.hideView(mOverlayViewController, mRunnable);
+
+ verify(mRunnable, never()).run();
+ }
+
+ @Test
+ public void hideView_viewControllerShown_hideRunnableCalled() {
+ when(mOverlayViewController.isInflated()).thenReturn(true);
+ mOverlayViewGlobalStateController.mShownSet.add(
+ mOverlayViewController.getClass().getName());
+
+ mOverlayViewGlobalStateController.hideView(mOverlayViewController, mRunnable);
+
+ verify(mRunnable).run();
+ }
+
+ @Test
+ public void hideView_viewControllerOnlyShown_nothingShown() {
+ when(mOverlayViewController.isInflated()).thenReturn(true);
+ mOverlayViewGlobalStateController.mShownSet.add(
+ mOverlayViewController.getClass().getName());
+
+ mOverlayViewGlobalStateController.hideView(mOverlayViewController, mRunnable);
+
+ assertThat(mOverlayViewGlobalStateController.mShownSet.isEmpty()).isTrue();
+ }
+
+ @Test
+ public void hideView_viewControllerNotOnlyShown_navigationBarNotShown() {
+ when(mOverlayViewController.isInflated()).thenReturn(true);
+ mOverlayViewGlobalStateController.mShownSet.add(
+ mOverlayViewController.getClass().getName());
+ mOverlayViewGlobalStateController.mShownSet.add(MOCK_OVERLAY_VIEW_CONTROLLER_NAME);
+
+ mOverlayViewGlobalStateController.hideView(mOverlayViewController, mRunnable);
+
+ verify(mCarNavigationBarController, never()).showBars();
+ }
+
+ @Test
+ public void hideView_viewControllerNotOnlyShown_windowNotCollapsed() {
+ when(mOverlayViewController.isInflated()).thenReturn(true);
+ mOverlayViewGlobalStateController.mShownSet.add(
+ mOverlayViewController.getClass().getName());
+ mOverlayViewGlobalStateController.mShownSet.add(MOCK_OVERLAY_VIEW_CONTROLLER_NAME);
+
+ mOverlayViewGlobalStateController.hideView(mOverlayViewController, mRunnable);
+
+ verify(mSystemUIOverlayWindowController, never()).setWindowExpanded(false);
+ }
+
+ @Test
+ public void hideView_viewControllerOnlyShown_navigationBarShown() {
+ when(mOverlayViewController.isInflated()).thenReturn(true);
+ mOverlayViewGlobalStateController.mShownSet.add(
+ mOverlayViewController.getClass().getName());
+
+ mOverlayViewGlobalStateController.hideView(mOverlayViewController, mRunnable);
+
+ verify(mCarNavigationBarController).showBars();
+ }
+
+ @Test
+ public void hideView_viewControllerOnlyShown_windowCollapsed() {
+ when(mOverlayViewController.isInflated()).thenReturn(true);
+ mOverlayViewGlobalStateController.mShownSet.add(
+ mOverlayViewController.getClass().getName());
+
+ mOverlayViewGlobalStateController.hideView(mOverlayViewController, mRunnable);
+
+ verify(mSystemUIOverlayWindowController).setWindowExpanded(false);
+ }
+}
diff --git a/packages/DynamicSystemInstallationService/src/com/android/dynsystem/DynamicSystemInstallationService.java b/packages/DynamicSystemInstallationService/src/com/android/dynsystem/DynamicSystemInstallationService.java
index f36f97ddf610..f80e934cf37c 100644
--- a/packages/DynamicSystemInstallationService/src/com/android/dynsystem/DynamicSystemInstallationService.java
+++ b/packages/DynamicSystemInstallationService/src/com/android/dynsystem/DynamicSystemInstallationService.java
@@ -139,6 +139,7 @@ public class DynamicSystemInstallationService extends Service
private long mCurrentPartitionInstalledSize;
private boolean mJustCancelledByUser;
+ private boolean mKeepNotification;
// This is for testing only now
private boolean mEnableWhenCompleted;
@@ -173,8 +174,11 @@ public class DynamicSystemInstallationService extends Service
if (cache != null) {
cache.flush();
}
- // Cancel the persistent notification.
- mNM.cancel(NOTIFICATION_ID);
+
+ if (!mKeepNotification) {
+ // Cancel the persistent notification.
+ mNM.cancel(NOTIFICATION_ID);
+ }
}
@Override
@@ -227,9 +231,6 @@ public class DynamicSystemInstallationService extends Service
return;
}
- // if it's not successful, reset the task and stop self.
- resetTaskAndStop();
-
switch (result) {
case RESULT_CANCELLED:
postStatus(STATUS_NOT_STARTED, CAUSE_INSTALL_CANCELLED, null);
@@ -248,6 +249,9 @@ public class DynamicSystemInstallationService extends Service
postStatus(STATUS_NOT_STARTED, CAUSE_ERROR_EXCEPTION, detail);
break;
}
+
+ // if it's not successful, reset the task and stop self.
+ resetTaskAndStop();
}
private void executeInstallCommand(Intent intent) {
@@ -392,10 +396,10 @@ public class DynamicSystemInstallationService extends Service
private void resetTaskAndStop() {
mInstallTask = null;
- stopForeground(true);
-
- // stop self, but this service is not destroyed yet if it's still bound
- stopSelf();
+ new Handler().postDelayed(() -> {
+ stopForeground(STOP_FOREGROUND_DETACH);
+ stopSelf();
+ }, 50);
}
private void prepareNotification() {
@@ -503,6 +507,7 @@ public class DynamicSystemInstallationService extends Service
private void postStatus(int status, int cause, Throwable detail) {
String statusString;
String causeString;
+ mKeepNotification = false;
switch (status) {
case STATUS_NOT_STARTED:
@@ -531,12 +536,15 @@ public class DynamicSystemInstallationService extends Service
break;
case CAUSE_ERROR_IO:
causeString = "ERROR_IO";
+ mKeepNotification = true;
break;
case CAUSE_ERROR_INVALID_URL:
causeString = "ERROR_INVALID_URL";
+ mKeepNotification = true;
break;
case CAUSE_ERROR_EXCEPTION:
causeString = "ERROR_EXCEPTION";
+ mKeepNotification = true;
break;
default:
causeString = "CAUSE_NOT_SPECIFIED";
diff --git a/packages/SettingsLib/Android.bp b/packages/SettingsLib/Android.bp
index 3f42ad40eb8e..4ea104705da0 100644
--- a/packages/SettingsLib/Android.bp
+++ b/packages/SettingsLib/Android.bp
@@ -2,6 +2,30 @@ android_library {
name: "SettingsLib",
+ defaults: [
+ "SettingsLibDependenciesWithoutWifiTracker",
+ ],
+
+ // TODO(b/149540986): revert this change.
+ static_libs: [
+ // All other dependent components should be put in
+ // "SettingsLibDependenciesWithoutWifiTracker".
+ "WifiTrackerLib",
+ ],
+
+ // ANDROIDMK TRANSLATION ERROR: unsupported assignment to LOCAL_SHARED_JAVA_LIBRARIES
+ // LOCAL_SHARED_JAVA_LIBRARIES := androidx.lifecycle_lifecycle-common
+
+ resource_dirs: ["res"],
+
+ srcs: ["src/**/*.java", "src/**/*.kt"],
+
+ min_sdk_version: "21",
+
+}
+
+java_defaults {
+ name: "SettingsLibDependenciesWithoutWifiTracker",
static_libs: [
"androidx.annotation_annotation",
"androidx.legacy_legacy-support-v4",
@@ -25,20 +49,9 @@ android_library {
"SettingsLibProgressBar",
"SettingsLibAdaptiveIcon",
"SettingsLibRadioButtonPreference",
- "WifiTrackerLib",
"SettingsLibDisplayDensityUtils",
"SettingsLibSchedulesProvider",
],
-
- // ANDROIDMK TRANSLATION ERROR: unsupported assignment to LOCAL_SHARED_JAVA_LIBRARIES
- // LOCAL_SHARED_JAVA_LIBRARIES := androidx.lifecycle_lifecycle-common
-
- resource_dirs: ["res"],
-
- srcs: ["src/**/*.java", "src/**/*.kt"],
-
- min_sdk_version: "21",
-
}
// NOTE: Keep this module in sync with ./common.mk
diff --git a/packages/SettingsLib/HelpUtils/src/com/android/settingslib/HelpUtils.java b/packages/SettingsLib/HelpUtils/src/com/android/settingslib/HelpUtils.java
index a77683d7b8c2..541a2468db45 100644
--- a/packages/SettingsLib/HelpUtils/src/com/android/settingslib/HelpUtils.java
+++ b/packages/SettingsLib/HelpUtils/src/com/android/settingslib/HelpUtils.java
@@ -24,7 +24,6 @@ import android.content.Intent;
import android.content.pm.PackageInfo;
import android.content.pm.PackageManager.NameNotFoundException;
import android.content.res.Resources;
-import android.content.res.TypedArray;
import android.net.Uri;
import android.provider.Settings.Global;
import android.text.TextUtils;
@@ -63,7 +62,6 @@ public class HelpUtils {
// Constants for help intents.
private static final String EXTRA_CONTEXT = "EXTRA_CONTEXT";
private static final String EXTRA_THEME = "EXTRA_THEME";
- private static final String EXTRA_PRIMARY_COLOR = "EXTRA_PRIMARY_COLOR";
private static final String EXTRA_BACKUP_URI = "EXTRA_BACKUP_URI";
/**
@@ -216,10 +214,7 @@ public class HelpUtils {
intent.putExtra(feedbackIntentExtraKey, packageNameKey);
intent.putExtra(feedbackIntentNameKey, packageNameValue);
}
- intent.putExtra(EXTRA_THEME, 0 /* Light theme */);
- TypedArray array = context.obtainStyledAttributes(new int[]{android.R.attr.colorPrimary});
- intent.putExtra(EXTRA_PRIMARY_COLOR, array.getColor(0, 0));
- array.recycle();
+ intent.putExtra(EXTRA_THEME, 3 /* System Default theme */);
}
/**
diff --git a/packages/SettingsLib/SchedulesProvider/src/com/android/settingslib/schedulesprovider/ScheduleInfo.java b/packages/SettingsLib/SchedulesProvider/src/com/android/settingslib/schedulesprovider/ScheduleInfo.java
index 26bcd54930b6..bd9dc4ff1e3c 100644
--- a/packages/SettingsLib/SchedulesProvider/src/com/android/settingslib/schedulesprovider/ScheduleInfo.java
+++ b/packages/SettingsLib/SchedulesProvider/src/com/android/settingslib/schedulesprovider/ScheduleInfo.java
@@ -16,6 +16,8 @@
package com.android.settingslib.schedulesprovider;
+import android.app.PendingIntent;
+import android.content.Context;
import android.content.Intent;
import android.os.Parcel;
import android.os.Parcelable;
@@ -25,25 +27,25 @@ import androidx.annotation.NonNull;
/**
* Schedule data item containing the schedule title text, the summary text which is displayed on the
- * summary of the Settings preference and an {@link Intent} which Settings will launch when the
- * user clicks on the preference.
+ * summary of the Settings preference and a {@link PendingIntent} which Settings will launch
+ * when the user clicks on the preference.
*/
public class ScheduleInfo implements Parcelable {
private static final String TAG = "ScheduleInfo";
private final String mTitle;
private final String mSummary;
- private final Intent mIntent;
+ private final PendingIntent mPendingIntent;
public ScheduleInfo(Builder builder) {
mTitle = builder.mTitle;
mSummary = builder.mSummary;
- mIntent = builder.mIntent;
+ mPendingIntent = builder.mPendingIntent;
}
private ScheduleInfo(Parcel in) {
mTitle = in.readString();
mSummary = in.readString();
- mIntent = in.readParcelable(Intent.class.getClassLoader());
+ mPendingIntent = in.readParcelable(PendingIntent.class.getClassLoader());
}
/**
@@ -61,11 +63,11 @@ public class ScheduleInfo implements Parcelable {
}
/**
- * Returns an {@link Intent} which Settings will launch when the user clicks on a schedule
- * preference.
+ * Returns a {@link PendingIntent} which Settings will launch when the user clicks on a
+ * schedule preference.
*/
- public Intent getIntent() {
- return mIntent;
+ public PendingIntent getPendingIntent() {
+ return mPendingIntent;
}
/**
@@ -74,14 +76,15 @@ public class ScheduleInfo implements Parcelable {
* @return {@code true} if all member variables are valid.
*/
public boolean isValid() {
- return !TextUtils.isEmpty(mTitle) && !TextUtils.isEmpty(mSummary) && (mIntent != null);
+ return !TextUtils.isEmpty(mTitle) && !TextUtils.isEmpty(mSummary)
+ && (mPendingIntent != null);
}
@Override
public void writeToParcel(Parcel dest, int flags) {
dest.writeString(mTitle);
dest.writeString(mSummary);
- dest.writeParcelable(mIntent, flags);
+ dest.writeParcelable(mPendingIntent, flags);
}
@Override
@@ -104,7 +107,7 @@ public class ScheduleInfo implements Parcelable {
@NonNull
@Override
public String toString() {
- return "title: " + mTitle + ", summary: " + mSummary + ", intent: " + mIntent;
+ return "title: " + mTitle + ", summary: " + mSummary + ", pendingIntent: " + mPendingIntent;
}
/**
@@ -113,7 +116,7 @@ public class ScheduleInfo implements Parcelable {
public static class Builder {
private String mTitle;
private String mSummary;
- private Intent mIntent;
+ private PendingIntent mPendingIntent;
/**
* Sets the title.
@@ -138,13 +141,15 @@ public class ScheduleInfo implements Parcelable {
}
/**
- * Sets the {@link Intent}.
+ * Sets the {@link PendingIntent}.
+ * <p>The {@link PendingIntent} should be created with
+ * {@link PendingIntent#getActivity(Context, int, Intent, int)}.
*
- * @param intent The action when user clicks the preference.
+ * @param pendingIntent The pending intent to send when the user clicks the preference.
* @return This instance.
*/
- public Builder setIntent(@NonNull Intent intent) {
- mIntent = intent;
+ public Builder setPendingIntent(@NonNull PendingIntent pendingIntent) {
+ mPendingIntent = pendingIntent;
return this;
}
diff --git a/packages/SettingsLib/res/values-as/strings.xml b/packages/SettingsLib/res/values-as/strings.xml
index ce967a38fde4..48af12a42fb6 100644
--- a/packages/SettingsLib/res/values-as/strings.xml
+++ b/packages/SettingsLib/res/values-as/strings.xml
@@ -357,8 +357,7 @@
<string name="enable_gpu_debug_layers" msgid="4986675516188740397">"জিপিইউ ডিবাগ স্তৰবোৰ সক্ষম কৰক"</string>
<string name="enable_gpu_debug_layers_summary" msgid="4921521407377170481">"ডিবাগ এপসমূহৰ বাবে জিপিইউ ডিবাগ তৰপ ল\'ড কৰিবলৈ অনুমতি দিয়ক"</string>
<string name="enable_verbose_vendor_logging" msgid="1196698788267682072">"বিক্ৰেতাৰ ভাৰ্ব’ছ লগিং সক্ষম কৰক"</string>
- <!-- no translation found for enable_verbose_vendor_logging_summary (5426292185780393708) -->
- <skip />
+ <string name="enable_verbose_vendor_logging_summary" msgid="5426292185780393708">"বাগ ৰিপ’ৰ্টসমূহত অতিৰিক্ত ডিভাইচ নিৰ্দিষ্ট বিক্ৰেতাৰ লগসমূহ অন্তৰ্ভুক্ত কৰক, য’ত ব্যক্তিগত তথ্য থাকিব পাৰে, যি অধিক বেটাৰী আৰু/অথবা ষ্ট’ৰেজ ব্যৱহাৰ কৰিব পাৰে।"</string>
<string name="window_animation_scale_title" msgid="5236381298376812508">"ৱিণ্ড\' এনিমেশ্বন স্কেল"</string>
<string name="transition_animation_scale_title" msgid="1278477690695439337">"ট্ৰাঞ্জিশ্বন এনিমেশ্বন স্কেল"</string>
<string name="animator_duration_scale_title" msgid="7082913931326085176">"এনিমেটৰ কালদৈৰ্ঘ্য স্কেল"</string>
diff --git a/packages/SettingsLib/res/values-bn/strings.xml b/packages/SettingsLib/res/values-bn/strings.xml
index 6c459fc88ce7..c06100ebd9f0 100644
--- a/packages/SettingsLib/res/values-bn/strings.xml
+++ b/packages/SettingsLib/res/values-bn/strings.xml
@@ -357,8 +357,7 @@
<string name="enable_gpu_debug_layers" msgid="4986675516188740397">"GPU ডিবাগ স্তর চালু করুন"</string>
<string name="enable_gpu_debug_layers_summary" msgid="4921521407377170481">"ডিবাগ অ্যাপের জন্য GPU ডিবাগ স্তর লোড হতে দিন"</string>
<string name="enable_verbose_vendor_logging" msgid="1196698788267682072">"ভারবোস ভেন্ডর লগ-ইন চালু করুন"</string>
- <!-- no translation found for enable_verbose_vendor_logging_summary (5426292185780393708) -->
- <skip />
+ <string name="enable_verbose_vendor_logging_summary" msgid="5426292185780393708">"সমস্যা সংক্রান্ত রিপোর্টগুলিতে অতিরিক্ত ডিভাইস-নির্দিষ্ট ভেন্ডরের লগগুলি অন্তর্ভুক্ত করুন, যার মধ্যে ব্যক্তিগত তথ্য থাকতে পারে, আরও বেশি ব্যাটারি ব্যবহার করতে পারে, এবং/অথবা আরও স্টোরেজ ব্যবহার করতে পারে।"</string>
<string name="window_animation_scale_title" msgid="5236381298376812508">"উইন্ডো অ্যানিমেশন স্কেল"</string>
<string name="transition_animation_scale_title" msgid="1278477690695439337">"ট্র্যানজিশন অ্যানিমেশন স্কেল"</string>
<string name="animator_duration_scale_title" msgid="7082913931326085176">"অ্যানিমেটর সময়কাল স্কেল"</string>
diff --git a/packages/SettingsLib/res/values-de/strings.xml b/packages/SettingsLib/res/values-de/strings.xml
index b38868612959..721163bb5515 100644
--- a/packages/SettingsLib/res/values-de/strings.xml
+++ b/packages/SettingsLib/res/values-de/strings.xml
@@ -357,8 +357,7 @@
<string name="enable_gpu_debug_layers" msgid="4986675516188740397">"GPU-Debug-Ebenen zulassen"</string>
<string name="enable_gpu_debug_layers_summary" msgid="4921521407377170481">"Debug-Apps das Laden von GPU-Debug-Ebenen erlauben"</string>
<string name="enable_verbose_vendor_logging" msgid="1196698788267682072">"Ausführliche Protokollierung aktivieren"</string>
- <!-- no translation found for enable_verbose_vendor_logging_summary (5426292185780393708) -->
- <skip />
+ <string name="enable_verbose_vendor_logging_summary" msgid="5426292185780393708">"Schließt zusätzliche gerätespezifische Anbieterprotokolle in Fehlerberichten ein, die private Informationen enthalten, den Akkuverbrauch erhöhen und/oder zusätzlichen Speicher benötigen können."</string>
<string name="window_animation_scale_title" msgid="5236381298376812508">"Fensteranimationsfaktor"</string>
<string name="transition_animation_scale_title" msgid="1278477690695439337">"Übergangsanimationsfaktor"</string>
<string name="animator_duration_scale_title" msgid="7082913931326085176">"Animationsdauerfaktor"</string>
diff --git a/packages/SettingsLib/res/values-eu/strings.xml b/packages/SettingsLib/res/values-eu/strings.xml
index 95ed7f043928..e035a81414b0 100644
--- a/packages/SettingsLib/res/values-eu/strings.xml
+++ b/packages/SettingsLib/res/values-eu/strings.xml
@@ -357,8 +357,7 @@
<string name="enable_gpu_debug_layers" msgid="4986675516188740397">"Gaitu GPUaren arazketa-geruzak"</string>
<string name="enable_gpu_debug_layers_summary" msgid="4921521407377170481">"Eman GPUaren arazketa-geruzak kargatzeko baimena arazketa-aplikazioei"</string>
<string name="enable_verbose_vendor_logging" msgid="1196698788267682072">"Gaitu saltzaileen erregistro xehatuak"</string>
- <!-- no translation found for enable_verbose_vendor_logging_summary (5426292185780393708) -->
- <skip />
+ <string name="enable_verbose_vendor_logging_summary" msgid="5426292185780393708">"Sartu gailuaren berariazko saltzaileen erregistro gehigarriak akatsen txostenetan; baliteke haiek informazio pribatua izatea, bateria gehiago erabiltzea edo biltegiratzeko toki gehiago hartzea."</string>
<string name="window_animation_scale_title" msgid="5236381298376812508">"Leihoen animazio-eskala"</string>
<string name="transition_animation_scale_title" msgid="1278477690695439337">"Trantsizioen animazio-eskala"</string>
<string name="animator_duration_scale_title" msgid="7082913931326085176">"Animatzailearen iraupena"</string>
diff --git a/packages/SettingsLib/res/values-fr-rCA/strings.xml b/packages/SettingsLib/res/values-fr-rCA/strings.xml
index 8ee44ac5de6f..e1ff83ffdd4c 100644
--- a/packages/SettingsLib/res/values-fr-rCA/strings.xml
+++ b/packages/SettingsLib/res/values-fr-rCA/strings.xml
@@ -357,8 +357,7 @@
<string name="enable_gpu_debug_layers" msgid="4986675516188740397">"Activer couches débogage GPU"</string>
<string name="enable_gpu_debug_layers_summary" msgid="4921521407377170481">"Autoriser couches débogage GPU pour applis de débogage"</string>
<string name="enable_verbose_vendor_logging" msgid="1196698788267682072">"Activer le journal détaillé des fournisseurs"</string>
- <!-- no translation found for enable_verbose_vendor_logging_summary (5426292185780393708) -->
- <skip />
+ <string name="enable_verbose_vendor_logging_summary" msgid="5426292185780393708">"Incluez les journaux supplémentaires du fournisseur propres à l\'appareil dans les rapports de bogue. Ils peuvent contenir des données personnelles, épuiser la pile plus rapidement et/ou utiliser plus d\'espace de stockage."</string>
<string name="window_animation_scale_title" msgid="5236381298376812508">"Échelle animation fenêtres"</string>
<string name="transition_animation_scale_title" msgid="1278477690695439337">"Échelle animination transitions"</string>
<string name="animator_duration_scale_title" msgid="7082913931326085176">"Échelle durée animation"</string>
diff --git a/packages/SettingsLib/res/values-gu/strings.xml b/packages/SettingsLib/res/values-gu/strings.xml
index 00c7b370dd42..b81eba383d90 100644
--- a/packages/SettingsLib/res/values-gu/strings.xml
+++ b/packages/SettingsLib/res/values-gu/strings.xml
@@ -357,8 +357,7 @@
<string name="enable_gpu_debug_layers" msgid="4986675516188740397">"GPU ડિબગ સ્તરોને સક્ષમ કરો"</string>
<string name="enable_gpu_debug_layers_summary" msgid="4921521407377170481">"ડિબગ ઍપ માટે GPU ડિબગ સ્તરો લોડ કરવાની મંજૂરી આપો"</string>
<string name="enable_verbose_vendor_logging" msgid="1196698788267682072">"વર્બોઝ વેન્ડર લૉગિંગ ચાલુ કરો"</string>
- <!-- no translation found for enable_verbose_vendor_logging_summary (5426292185780393708) -->
- <skip />
+ <string name="enable_verbose_vendor_logging_summary" msgid="5426292185780393708">"ખામીની જાણકારીમાં ડિવાઇસથી જોડાયેલા ચોક્કસ વેન્ડર લૉગ શામેલ કરો, જેમાં ખાનગી માહિતી શામેલ હોઈ શકે છે, તે વધુ બૅટરીનો ઉપયોગ કરી શકે છે અને/અથવા વધુ સ્ટોરેજનો ઉપયોગ કરી શકે છે."</string>
<string name="window_animation_scale_title" msgid="5236381298376812508">"વિંડો એનિમેશન સ્કેલ"</string>
<string name="transition_animation_scale_title" msgid="1278477690695439337">"સંક્રમણ એનિમેશન સ્કેલ"</string>
<string name="animator_duration_scale_title" msgid="7082913931326085176">"એનિમેટર અવધિ સ્કેલ"</string>
diff --git a/packages/SettingsLib/res/values-hi/strings.xml b/packages/SettingsLib/res/values-hi/strings.xml
index b38223429a2c..414b87653073 100644
--- a/packages/SettingsLib/res/values-hi/strings.xml
+++ b/packages/SettingsLib/res/values-hi/strings.xml
@@ -358,8 +358,7 @@
<string name="track_frame_time" msgid="522674651937771106">"प्रोफ़ाइल HWUI रेंडरिंग"</string>
<string name="enable_gpu_debug_layers" msgid="4986675516188740397">"जीपीयू डीबग लेयर चालू करें"</string>
<string name="enable_gpu_debug_layers_summary" msgid="4921521407377170481">"डीबग ऐप के लिए जीपीयू डीबग लेयर लोड करने दें"</string>
- <!-- no translation found for enable_verbose_vendor_logging (1196698788267682072) -->
- <skip />
+ <string name="enable_verbose_vendor_logging" msgid="1196698788267682072">"वर्बोस वेंडर लॉगिंग चालू करें"</string>
<string name="enable_verbose_vendor_logging_summary" msgid="5426292185780393708">"गड़बड़ियों की रिपोर्ट में खास डिवाइस से जुड़े वेंडर लॉग शामिल करें. इन लॉग में निजी जानकारी, बैटरी का ज़्यादा इस्तेमाल, और/या डिवाइस की मेमोरी ज़्यादा इस्तेमाल करने की जानकारी हो सकती है."</string>
<string name="window_animation_scale_title" msgid="5236381298376812508">"विंडो एनिमेशन स्‍केल"</string>
<string name="transition_animation_scale_title" msgid="1278477690695439337">"ट्रांज़िशन एनिमेशन स्‍केल"</string>
@@ -508,9 +507,7 @@
<string name="zen_mode_duration_always_prompt_title" msgid="3212996860498119555">"हर बार पूछें"</string>
<string name="zen_mode_forever" msgid="3339224497605461291">"जब तक आप इसे बंद नहीं करते"</string>
<string name="time_unit_just_now" msgid="3006134267292728099">"अभी-अभी"</string>
- <!-- no translation found for media_transfer_this_device_name (2716555073132169240) -->
- <skip />
+ <string name="media_transfer_this_device_name" msgid="2716555073132169240">"फ़ोन का स्पीकर"</string>
<string name="profile_connect_timeout_subtext" msgid="4043408193005851761">"कनेक्ट करने में समस्या हो रही है. डिवाइस को बंद करके चालू करें"</string>
- <!-- no translation found for media_transfer_wired_device_name (4447880899964056007) -->
- <skip />
+ <string name="media_transfer_wired_device_name" msgid="4447880899964056007">"वायर वाला ऑडियो डिवाइस"</string>
</resources>
diff --git a/packages/SettingsLib/res/values-is/strings.xml b/packages/SettingsLib/res/values-is/strings.xml
index 7a7ba4c70e34..002709c52658 100644
--- a/packages/SettingsLib/res/values-is/strings.xml
+++ b/packages/SettingsLib/res/values-is/strings.xml
@@ -357,8 +357,7 @@
<string name="enable_gpu_debug_layers" msgid="4986675516188740397">"Virkja villuleit skják."</string>
<string name="enable_gpu_debug_layers_summary" msgid="4921521407377170481">"Leyfa villuleit skjákorts fyrir villuleit forrita"</string>
<string name="enable_verbose_vendor_logging" msgid="1196698788267682072">"Nákvæm skráning söluaðila"</string>
- <!-- no translation found for enable_verbose_vendor_logging_summary (5426292185780393708) -->
- <skip />
+ <string name="enable_verbose_vendor_logging_summary" msgid="5426292185780393708">"Taka með viðbótarannála söluaðila fyrir tiltekin tæki í villutilkynningum, sem gætu innihaldið viðkvæmar upplýsingar, notað meiri rafhlöðuorku og/eða þurft meira geymslupláss."</string>
<string name="window_animation_scale_title" msgid="5236381298376812508">"Kvarði gluggahreyfinga"</string>
<string name="transition_animation_scale_title" msgid="1278477690695439337">"Lengd hreyfiumbreytinga"</string>
<string name="animator_duration_scale_title" msgid="7082913931326085176">"Tímalengd hreyfiáhrifa"</string>
diff --git a/packages/SettingsLib/res/values-iw/strings.xml b/packages/SettingsLib/res/values-iw/strings.xml
index 49929d4a2fe0..975ccdcecd87 100644
--- a/packages/SettingsLib/res/values-iw/strings.xml
+++ b/packages/SettingsLib/res/values-iw/strings.xml
@@ -357,7 +357,7 @@
<string name="enable_gpu_debug_layers" msgid="4986675516188740397">"‏הפעלת שכבות לניפוי באגים ב-GPU"</string>
<string name="enable_gpu_debug_layers_summary" msgid="4921521407377170481">"‏טעינת שכבות לניפוי באגים ב-GPU לאפליקציות ניפוי באגים"</string>
<string name="enable_verbose_vendor_logging" msgid="1196698788267682072">"הפעלת רישום ספקים מפורט ביומן"</string>
- <string name="enable_verbose_vendor_logging_summary" msgid="5426292185780393708">"הכללת יומני ספקים נוספים, ספציפיים למכשירים, בדוחות על באגים, שעשויים להכיל מידע פרטי, לצרוך יותר מהסוללה ו/או להשתמש ביותר אחסון."</string>
+ <string name="enable_verbose_vendor_logging_summary" msgid="5426292185780393708">"הוספת רישומי יומן של יצרנים למכשירים ספציפיים בדוחות על באגים. דוחות אלה עשויים להכיל מידע פרטי, להגביר את צריכת הסוללה ולצרוך שטח אחסון גדול יותר."</string>
<string name="window_animation_scale_title" msgid="5236381298376812508">"קנה מידה לאנימציה של חלון"</string>
<string name="transition_animation_scale_title" msgid="1278477690695439337">"קנה מידה לאנימציית מעבר"</string>
<string name="animator_duration_scale_title" msgid="7082913931326085176">"קנה מידה למשך זמן אנימציה"</string>
diff --git a/packages/SettingsLib/res/values-km/strings.xml b/packages/SettingsLib/res/values-km/strings.xml
index 337bb8b6b70f..0ceda1859583 100644
--- a/packages/SettingsLib/res/values-km/strings.xml
+++ b/packages/SettingsLib/res/values-km/strings.xml
@@ -357,7 +357,7 @@
<string name="enable_gpu_debug_layers" msgid="4986675516188740397">"បើក​ស្រទាប់​ជួសជុល GPU"</string>
<string name="enable_gpu_debug_layers_summary" msgid="4921521407377170481">"អនុញ្ញាតឱ្យ​ផ្ទុក​ស្រទាប់​ជួស​ជុល GPU សម្រាប់​កម្មវិធី​ជួសជុល"</string>
<string name="enable_verbose_vendor_logging" msgid="1196698788267682072">"បើកកំណត់ហេតុរៀបរាប់អំពីអ្នកលក់"</string>
- <string name="enable_verbose_vendor_logging_summary" msgid="5426292185780393708">"រួមមានកំណត់​ហេតុបន្ថែមអំពី​អ្នកលក់ឧបករណ៍ជាក់លាក់​នៅក្នុងរបាយការណ៍​អំពីបញ្ហា ដែលអាច​មានព័ត៌មាន​ឯកជន ប្រើប្រាស់​ថ្មច្រើនជាងមុន និង/ឬប្រើប្រាស់​ទំហំផ្ទុកច្រើនជាងមុន។"</string>
+ <string name="enable_verbose_vendor_logging_summary" msgid="5426292185780393708">"រួមមានកំណត់​ហេតុបន្ថែមអំពី​អ្នកផ្គត់ផ្គង់សម្រាប់ឧបករណ៍ជាក់លាក់​នៅក្នុងរបាយការណ៍​អំពីបញ្ហា ដែលអាច​មានព័ត៌មាន​ឯកជន ប្រើប្រាស់​ថ្មច្រើនជាងមុន និង/ឬប្រើប្រាស់​ទំហំផ្ទុកច្រើនជាងមុន។"</string>
<string name="window_animation_scale_title" msgid="5236381298376812508">"មាត្រដ្ឋាន​ចលនា​វិនដូ"</string>
<string name="transition_animation_scale_title" msgid="1278477690695439337">"មាត្រដ្ឋាន​ដំណើរ​ផ្លាស់ប្ដូរ​ចលនា"</string>
<string name="animator_duration_scale_title" msgid="7082913931326085176">"មាត្រដ្ឋាន​រយៈពេល​នៃ​កម្មវិធី​ចលនា"</string>
diff --git a/packages/SettingsLib/res/values-kn/strings.xml b/packages/SettingsLib/res/values-kn/strings.xml
index 926c98a605db..d23aeff01b00 100644
--- a/packages/SettingsLib/res/values-kn/strings.xml
+++ b/packages/SettingsLib/res/values-kn/strings.xml
@@ -357,8 +357,7 @@
<string name="enable_gpu_debug_layers" msgid="4986675516188740397">"GPU ಡೀಬಗ್ ಲೇಯರ್‌ಗಳನ್ನು ಸಕ್ರಿಯಗೊಳಿಸಿ"</string>
<string name="enable_gpu_debug_layers_summary" msgid="4921521407377170481">"ಡೀಬಗ್ ಅಪ್ಲಿಕೇಶನ್‌ಗಳಿಗಾಗಿ GPU ಡೀಬಗ್ ಲೇಯರ್‌ಗಳನ್ನು ಲೋಡ್ ಮಾಡುವುದನ್ನು ಅನುಮತಿಸಿ"</string>
<string name="enable_verbose_vendor_logging" msgid="1196698788267682072">"ವೆರ್‌ಬೋಸ್ ವೆಂಡರ್ ಲಾಗಿಂಗ್‌ ಆನ್"</string>
- <!-- no translation found for enable_verbose_vendor_logging_summary (5426292185780393708) -->
- <skip />
+ <string name="enable_verbose_vendor_logging_summary" msgid="5426292185780393708">"ಬಗ್ ವರದಿಗಳಲ್ಲಿ ಹೆಚ್ಚುವರಿ ಸಾಧನ ನಿರ್ದಿಷ್ಟ ವೆಂಡರ್ ಲಾಗ್‌ಗಳು ಒಳಗೊಂಡಿದೆ, ಇದು ಖಾಸಗಿ ಮಾಹಿತಿ, ಹೆಚ್ಚಿನ ಬ್ಯಾಟರಿ ಬಳಕೆ ಮತ್ತು/ಅಥವಾ ಹೆಚ್ಚಿನ ಸಂಗ್ರಹಣೆಯ ಬಳಕೆಯನ್ನು ಒಳಗೊಂಡಿರಬಹುದು."</string>
<string name="window_animation_scale_title" msgid="5236381298376812508">"Window ಅನಿಮೇಶನ್ ಸ್ಕೇಲ್‌"</string>
<string name="transition_animation_scale_title" msgid="1278477690695439337">"ಪರಿವರ್ತನೆ ಅನಿಮೇಶನ್ ಸ್ಕೇಲ್‌"</string>
<string name="animator_duration_scale_title" msgid="7082913931326085176">"ಅನಿಮೇಟರ್ ಅವಧಿಯ ಪ್ರಮಾಣ"</string>
diff --git a/packages/SettingsLib/res/values-ml/strings.xml b/packages/SettingsLib/res/values-ml/strings.xml
index a360fcde9844..06ee21941d12 100644
--- a/packages/SettingsLib/res/values-ml/strings.xml
+++ b/packages/SettingsLib/res/values-ml/strings.xml
@@ -357,8 +357,7 @@
<string name="enable_gpu_debug_layers" msgid="4986675516188740397">"GPU ഡീബഗ് ലെയറുകൾ പ്രവർത്തനക്ഷമമാക്കൂ"</string>
<string name="enable_gpu_debug_layers_summary" msgid="4921521407377170481">"ഡീബഗ് ആപ്പുകൾക്കായി GPU ഡീബഗ് ലെയറുകൾ ലോഡ് ചെയ്യാൻ അനുവദിക്കുക"</string>
<string name="enable_verbose_vendor_logging" msgid="1196698788267682072">"വെർബോസ് വെണ്ടർ ലോഗ് ചെയ്യൽ പ്രവർത്തനക്ഷമമാക്കൂ"</string>
- <!-- no translation found for enable_verbose_vendor_logging_summary (5426292185780393708) -->
- <skip />
+ <string name="enable_verbose_vendor_logging_summary" msgid="5426292185780393708">"ബഗ് റിപ്പോർട്ടുകളിൽ ഉപകരണ-നിർദ്ദിഷ്ട വെണ്ടർ അധിക ലോഗുകൾ ഉൾപ്പെടുത്തുക, അതിൽ സ്വകാര്യ വിവരങ്ങൾ അടങ്ങിയിരിക്കാം, കൂടുതൽ ബാറ്ററി ഉപയോഗിക്കാം കൂടാതെ/അല്ലെങ്കിൽ കൂടുതൽ സ്‌റ്റോറേജ് ഇടം ഉപയോഗിക്കാം."</string>
<string name="window_animation_scale_title" msgid="5236381298376812508">"വിൻഡോ ആനിമേഷൻ സ്‌കെയിൽ"</string>
<string name="transition_animation_scale_title" msgid="1278477690695439337">"സംക്രമണ ആനിമേഷൻ സ്‌കെയിൽ"</string>
<string name="animator_duration_scale_title" msgid="7082913931326085176">"ആനിമേറ്റർ ദൈർഘ്യ സ്‌കെയിൽ"</string>
diff --git a/packages/SettingsLib/res/values-mr/strings.xml b/packages/SettingsLib/res/values-mr/strings.xml
index afb88de651f5..543152a744de 100644
--- a/packages/SettingsLib/res/values-mr/strings.xml
+++ b/packages/SettingsLib/res/values-mr/strings.xml
@@ -357,8 +357,7 @@
<string name="enable_gpu_debug_layers" msgid="4986675516188740397">"GPU डीबग स्तर सुरू करा"</string>
<string name="enable_gpu_debug_layers_summary" msgid="4921521407377170481">"डीबग अ‍ॅप्ससाठी GPU डीबग स्तर लोड करण्याची अनुमती द्या"</string>
<string name="enable_verbose_vendor_logging" msgid="1196698788267682072">"व्हर्बोझ विक्रेता लॉगिंग सुरू करा"</string>
- <!-- no translation found for enable_verbose_vendor_logging_summary (5426292185780393708) -->
- <skip />
+ <string name="enable_verbose_vendor_logging_summary" msgid="5426292185780393708">"बग रिपोर्टमध्ये अतिरिक्त डिव्हाइस-विशिष्ट विक्रेता लॉगचा समावेश करा ज्यामध्ये खाजगी माहिती असू शकते, अधिक बॅटरी आणि/किंवा अधिक स्टोरेज वापरले जाईल."</string>
<string name="window_animation_scale_title" msgid="5236381298376812508">"विंडो ॲनिमेशन स्केल"</string>
<string name="transition_animation_scale_title" msgid="1278477690695439337">"ट्रांझिशन ॲनिमेशन स्केल"</string>
<string name="animator_duration_scale_title" msgid="7082913931326085176">"ॲनिमेटर कालावधी स्केल"</string>
diff --git a/packages/SettingsLib/res/values-ne/strings.xml b/packages/SettingsLib/res/values-ne/strings.xml
index e78e8fa29fc6..89d66ab92333 100644
--- a/packages/SettingsLib/res/values-ne/strings.xml
+++ b/packages/SettingsLib/res/values-ne/strings.xml
@@ -357,8 +357,7 @@
<string name="enable_gpu_debug_layers" msgid="4986675516188740397">"GPU का डिबग तहहरूलाई सक्षम पार्नुहोस्"</string>
<string name="enable_gpu_debug_layers_summary" msgid="4921521407377170481">"डिबगसम्बन्धी अनुप्रयोगहरूका लागि GPU का डिबग तहहरूलाई लोड गर्न दिनुहोस्"</string>
<string name="enable_verbose_vendor_logging" msgid="1196698788267682072">"भर्वस भेन्डर लगिङ सक्षम पार्नु…"</string>
- <!-- no translation found for enable_verbose_vendor_logging_summary (5426292185780393708) -->
- <skip />
+ <string name="enable_verbose_vendor_logging_summary" msgid="5426292185780393708">"बग रिपोर्टहरूमा यन्त्र विशेष विक्रेताका अतिरिक्त लगहरू समावेश गर्नुहोस्। यी लगमा निजी जानकारी समावेश हुन सक्छन्, यिनले ब्याट्रीको खपत बढाउन र/वा थप भण्डारण प्रयोग गर्न सक्छन्।"</string>
<string name="window_animation_scale_title" msgid="5236381298376812508">"विन्डो सजीविकरण स्केल"</string>
<string name="transition_animation_scale_title" msgid="1278477690695439337">"संक्रमण सजीविकरण मापन"</string>
<string name="animator_duration_scale_title" msgid="7082913931326085176">"सजीविकरण अवधि मापन"</string>
diff --git a/packages/SettingsLib/res/values-or/strings.xml b/packages/SettingsLib/res/values-or/strings.xml
index 65c44cbdb88a..b475846de6e9 100644
--- a/packages/SettingsLib/res/values-or/strings.xml
+++ b/packages/SettingsLib/res/values-or/strings.xml
@@ -357,8 +357,7 @@
<string name="enable_gpu_debug_layers" msgid="4986675516188740397">"GPU ଡିବଗ୍‌ ଲେୟର୍‌ ସକ୍ଷମ କରନ୍ତୁ"</string>
<string name="enable_gpu_debug_layers_summary" msgid="4921521407377170481">"ଡିବଗ୍‌ ଆପ୍‌ଗୁଡ଼ିକ ପାଇଁ GPU ଡିବଗ୍‌ ଲେୟର୍‌ ଲୋଡ୍ କରିବାର ଅନୁମତି ଦିଅନ୍ତୁ"</string>
<string name="enable_verbose_vendor_logging" msgid="1196698788267682072">"ଭର୍ବୋସ ଭେଣ୍ଡର୍ ଲଗିଂ ସକ୍ଷମ କରନ୍ତୁ"</string>
- <!-- no translation found for enable_verbose_vendor_logging_summary (5426292185780393708) -->
- <skip />
+ <string name="enable_verbose_vendor_logging_summary" msgid="5426292185780393708">"ବଗ୍ ରିପୋର୍ଟଗୁଡ଼ିକରେ ଅତିରିକ୍ତ ଡିଭାଇସ୍-ନିର୍ଦ୍ଦିଷ୍ଟ ଲଗଗୁଡ଼ିକ ସାମିଲ କରନ୍ତୁ, ଯେଉଁଥିରେ ବ୍ୟକ୍ତିଗତ ସୂଚନା ଥାଇପାରେ, ଯାହା ଅଧିକ ବ୍ୟାଟେରୀ ଏବଂ/କିମ୍ବା ଅଧିକ ଷ୍ଟୋରେଜ୍ ବ୍ୟବହାର କରିପାରେ।"</string>
<string name="window_animation_scale_title" msgid="5236381298376812508">"ୱିଣ୍ଡୋ ଆନିମେସନ୍‌ ସ୍କେଲ୍‌"</string>
<string name="transition_animation_scale_title" msgid="1278477690695439337">"ଟ୍ରାଞ୍ଜିସନ୍‌ ଆନିମେସନ୍‌ ସ୍କେଲ୍‌"</string>
<string name="animator_duration_scale_title" msgid="7082913931326085176">"ଆନିମେଟର୍‌ ଅବଧି ସ୍କେଲ୍‌"</string>
diff --git a/packages/SettingsLib/res/values-pa/strings.xml b/packages/SettingsLib/res/values-pa/strings.xml
index ed020e8fb963..6cd3d84683d9 100644
--- a/packages/SettingsLib/res/values-pa/strings.xml
+++ b/packages/SettingsLib/res/values-pa/strings.xml
@@ -357,8 +357,7 @@
<string name="enable_gpu_debug_layers" msgid="4986675516188740397">"GPU ਡੀਬੱਗ ਲੇਅਰਾਂ ਚਾਲੂ ਕਰੋ"</string>
<string name="enable_gpu_debug_layers_summary" msgid="4921521407377170481">"ਡੀਬੱਗ ਐਪਾਂ ਲਈ GPU ਡੀਬੱਗ ਲੇਅਰਾਂ ਨੂੰ ਲੋਡ ਹੋਣ ਦਿਓ"</string>
<string name="enable_verbose_vendor_logging" msgid="1196698788267682072">"ਵਰਬੋਸ ਵਿਕਰੇਤਾ ਲੌਗਿੰਗ ਚਾਲੂ ਕਰੋ"</string>
- <!-- no translation found for enable_verbose_vendor_logging_summary (5426292185780393708) -->
- <skip />
+ <string name="enable_verbose_vendor_logging_summary" msgid="5426292185780393708">"ਬੱਗ ਰਿਪੋਰਟਾਂ ਵਿੱਚ ਵਧੀਕ ਡੀਵਾਈਸ ਨਾਲ ਸੰਬੰਧਿਤ ਵਿਕਰੇਤਾ ਲੌਗ ਸ਼ਾਮਲ ਕਰੋ, ਜਿਨ੍ਹਾਂ ਵਿੱਚ ਨਿੱਜੀ ਜਾਣਕਾਰੀ, ਬੈਟਰੀ ਦੀ ਵਧੇਰੇ ਵਰਤੋਂ, ਅਤੇ/ਜਾਂ ਵਧੇਰੀ ਸਟੋਰੇਜ ਸ਼ਾਮਲ ਹੋ ਸਕਦੀ ਹੈ।"</string>
<string name="window_animation_scale_title" msgid="5236381298376812508">"ਵਿੰਡੋ ਐਨੀਮੇਸ਼ਨ ਸਕੇਲ"</string>
<string name="transition_animation_scale_title" msgid="1278477690695439337">"ਟ੍ਰਾਂਜਿਸ਼ਨ ਐਨੀਮੇਸ਼ਨ ਸਕੇਲ"</string>
<string name="animator_duration_scale_title" msgid="7082913931326085176">"ਐਨੀਮੇਟਰ ਮਿਆਦ ਸਕੇਲ"</string>
diff --git a/packages/SettingsLib/res/values-ta/strings.xml b/packages/SettingsLib/res/values-ta/strings.xml
index 18ab23dc7750..ce4d72def1a0 100644
--- a/packages/SettingsLib/res/values-ta/strings.xml
+++ b/packages/SettingsLib/res/values-ta/strings.xml
@@ -255,8 +255,7 @@
<string name="bluetooth_show_devices_without_names" msgid="923584526471885819">"பெயர்கள் இல்லாத புளூடூத் சாதனங்களைக் காட்டு"</string>
<string name="bluetooth_disable_absolute_volume" msgid="1452342324349203434">"அப்சல்யூட் ஒலியளவு அம்சத்தை முடக்கு"</string>
<string name="bluetooth_enable_gabeldorsche" msgid="9131730396242883416">"Gabeldorscheவை இயக்கு"</string>
- <!-- no translation found for enhanced_connectivity (7201127377781666804) -->
- <skip />
+ <string name="enhanced_connectivity" msgid="7201127377781666804">"மேம்படுத்தப்பட்ட இணைப்புநிலை"</string>
<string name="bluetooth_select_avrcp_version_string" msgid="1710571610177659127">"புளூடூத் AVRCP பதிப்பு"</string>
<string name="bluetooth_select_avrcp_version_dialog_title" msgid="7846922290083709633">"புளூடூத் AVRCP பதிப்பைத் தேர்ந்தெடு"</string>
<string name="bluetooth_select_map_version_string" msgid="526308145174175327">"புளூடூத்தின் MAP பதிப்பு"</string>
@@ -310,8 +309,7 @@
<string name="bluetooth_show_devices_without_names_summary" msgid="780964354377854507">"பெயர்கள் இல்லாத புளூடூத் சாதனங்கள் (MAC முகவரிகள் மட்டும்) காட்டப்படும்"</string>
<string name="bluetooth_disable_absolute_volume_summary" msgid="2006309932135547681">"மிகவும் அதிகமான ஒலியளவு அல்லது கட்டுப்பாடு இழப்பு போன்ற தொலைநிலைச் சாதனங்களில் ஏற்படும் ஒலி தொடர்பான சிக்கல்கள் இருக்கும் சமயங்களில், புளூடூத் அப்சல்யூட் ஒலியளவு அம்சத்தை முடக்கும்."</string>
<string name="bluetooth_enable_gabeldorsche_summary" msgid="2054730331770712629">"புளூடூத்தின் Gabeldorsche அம்சங்களை இயக்கும்."</string>
- <!-- no translation found for enhanced_connectivity_summary (1576414159820676330) -->
- <skip />
+ <string name="enhanced_connectivity_summary" msgid="1576414159820676330">"மேம்படுத்தப்பட்ட இணைப்புநிலை அம்சத்தை இயக்கும்."</string>
<string name="enable_terminal_title" msgid="3834790541986303654">"அக முனையம்"</string>
<string name="enable_terminal_summary" msgid="2481074834856064500">"அக ஷெல் அணுகலை வழங்கும் இறுதிப் ஆப்ஸை இயக்கு"</string>
<string name="hdcp_checking_title" msgid="3155692785074095986">"HDCP சரிபார்ப்பு"</string>
@@ -358,8 +356,7 @@
<string name="track_frame_time" msgid="522674651937771106">"சுயவிவர HWUI ரெண்டரிங்"</string>
<string name="enable_gpu_debug_layers" msgid="4986675516188740397">"GPU பிழைத்திருத்த லேயர்களை இயக்கு"</string>
<string name="enable_gpu_debug_layers_summary" msgid="4921521407377170481">"பிழைத்திருத்த ஆப்ஸிற்கு, GPU பிழைத்திருத்த லேயர்களை ஏற்றுவதற்கு அனுமதி"</string>
- <!-- no translation found for enable_verbose_vendor_logging (1196698788267682072) -->
- <skip />
+ <string name="enable_verbose_vendor_logging" msgid="1196698788267682072">"வெர்போஸ் வெண்டார் பதிவை இயக்கு"</string>
<!-- no translation found for enable_verbose_vendor_logging_summary (5426292185780393708) -->
<skip />
<string name="window_animation_scale_title" msgid="5236381298376812508">"சாளர அனிமேஷன் வேகம்"</string>
@@ -509,9 +506,7 @@
<string name="zen_mode_duration_always_prompt_title" msgid="3212996860498119555">"ஒவ்வொரு முறையும் கேள்"</string>
<string name="zen_mode_forever" msgid="3339224497605461291">"ஆஃப் செய்யும் வரை"</string>
<string name="time_unit_just_now" msgid="3006134267292728099">"சற்றுமுன்"</string>
- <!-- no translation found for media_transfer_this_device_name (2716555073132169240) -->
- <skip />
+ <string name="media_transfer_this_device_name" msgid="2716555073132169240">"மொபைல் ஸ்பீக்கர்"</string>
<string name="profile_connect_timeout_subtext" msgid="4043408193005851761">"இணைப்பதில் சிக்கல். சாதனத்தை ஆஃப் செய்து மீண்டும் ஆன் செய்யவும்"</string>
- <!-- no translation found for media_transfer_wired_device_name (4447880899964056007) -->
- <skip />
+ <string name="media_transfer_wired_device_name" msgid="4447880899964056007">"வயருடன்கூடிய ஆடியோ சாதனம்"</string>
</resources>
diff --git a/packages/SettingsLib/res/values-te/strings.xml b/packages/SettingsLib/res/values-te/strings.xml
index 74739ee7a4fa..2508d742ce22 100644
--- a/packages/SettingsLib/res/values-te/strings.xml
+++ b/packages/SettingsLib/res/values-te/strings.xml
@@ -357,8 +357,7 @@
<string name="enable_gpu_debug_layers" msgid="4986675516188740397">"GPU డీబగ్ లేయర్‌లను ప్రారంభించండి"</string>
<string name="enable_gpu_debug_layers_summary" msgid="4921521407377170481">"డీబగ్ యాప్‌ల కోసం GPU డీబగ్ లేయర్‌లను లోడ్ చేయడాన్ని అనుమతించండి"</string>
<string name="enable_verbose_vendor_logging" msgid="1196698788267682072">"వివరణాత్మక విక్రేత లాగింగ్‌ను ఎనేబుల్ చేయండి"</string>
- <!-- no translation found for enable_verbose_vendor_logging_summary (5426292185780393708) -->
- <skip />
+ <string name="enable_verbose_vendor_logging_summary" msgid="5426292185780393708">"బగ్ నివేదికలలో అదనపు పరికర-నిర్దిష్ట వెండార్ లాగ్‌లను చేర్చండి, అవి ప్రైవేట్ సమాచారాన్ని కలిగి ఉండవచ్చు, మరింత బ్యాటరీని, మరియు/లేదా మరింత స్టోరేజ్‌ను ఉపయోగించవచ్చు."</string>
<string name="window_animation_scale_title" msgid="5236381298376812508">"విండో యానిమేషన్ ప్రమాణం"</string>
<string name="transition_animation_scale_title" msgid="1278477690695439337">"పరివర్తన యానిమేషన్ ప్రమాణం"</string>
<string name="animator_duration_scale_title" msgid="7082913931326085176">"యానిమేటర్ వ్యవధి ప్రమాణం"</string>
diff --git a/packages/SettingsLib/res/values-ur/strings.xml b/packages/SettingsLib/res/values-ur/strings.xml
index 10bce1bbda02..56f4f0697cd8 100644
--- a/packages/SettingsLib/res/values-ur/strings.xml
+++ b/packages/SettingsLib/res/values-ur/strings.xml
@@ -357,8 +357,7 @@
<string name="enable_gpu_debug_layers" msgid="4986675516188740397">"‏GPU ڈیبگ پرتیں فعال کریں"</string>
<string name="enable_gpu_debug_layers_summary" msgid="4921521407377170481">"‏ڈیبگ ایپس کیلئے GPU ڈیبگ پرتوں کو لوڈ کرنے دیں"</string>
<string name="enable_verbose_vendor_logging" msgid="1196698788267682072">"وربوس وینڈر لاگنگ فعال کریں"</string>
- <!-- no translation found for enable_verbose_vendor_logging_summary (5426292185780393708) -->
- <skip />
+ <string name="enable_verbose_vendor_logging_summary" msgid="5426292185780393708">"اضافی آلہ کے مخصوص وینڈر لاگز کو بگ رپورٹس میں شامل کریں، جن میں نجی معلومات، بیٹری کا زیادہ استعمال اور/یا اسٹوریج کا زیادہ استعمال شامل ہوسکتے ہیں۔"</string>
<string name="window_animation_scale_title" msgid="5236381298376812508">"ونڈو اینیمیشن اسکیل"</string>
<string name="transition_animation_scale_title" msgid="1278477690695439337">"ٹرانزیشن اینیمیشن اسکیل"</string>
<string name="animator_duration_scale_title" msgid="7082913931326085176">"اینیمیٹر دورانیے کا اسکیل"</string>
diff --git a/packages/SettingsLib/res/values-zh-rCN/strings.xml b/packages/SettingsLib/res/values-zh-rCN/strings.xml
index b2b9dc706df7..b83469b07d26 100644
--- a/packages/SettingsLib/res/values-zh-rCN/strings.xml
+++ b/packages/SettingsLib/res/values-zh-rCN/strings.xml
@@ -357,8 +357,7 @@
<string name="enable_gpu_debug_layers" msgid="4986675516188740397">"启用 GPU 调试层"</string>
<string name="enable_gpu_debug_layers_summary" msgid="4921521407377170481">"允许为调试应用加载 GPU 调试层"</string>
<string name="enable_verbose_vendor_logging" msgid="1196698788267682072">"启用详细供应商日志记录"</string>
- <!-- no translation found for enable_verbose_vendor_logging_summary (5426292185780393708) -->
- <skip />
+ <string name="enable_verbose_vendor_logging_summary" msgid="5426292185780393708">"在错误报告中包含其他设备特定的供应商日志,这些日志可能会含有隐私信息、消耗更多电量和/或使用更多存储空间。"</string>
<string name="window_animation_scale_title" msgid="5236381298376812508">"窗口动画缩放"</string>
<string name="transition_animation_scale_title" msgid="1278477690695439337">"过渡动画缩放"</string>
<string name="animator_duration_scale_title" msgid="7082913931326085176">"Animator 时长缩放"</string>
diff --git a/packages/SettingsLib/src/com/android/settingslib/bluetooth/A2dpProfile.java b/packages/SettingsLib/src/com/android/settingslib/bluetooth/A2dpProfile.java
index c9c847ff7194..18eb1879d7cf 100644
--- a/packages/SettingsLib/src/com/android/settingslib/bluetooth/A2dpProfile.java
+++ b/packages/SettingsLib/src/com/android/settingslib/bluetooth/A2dpProfile.java
@@ -218,24 +218,32 @@ public class A2dpProfile implements LocalBluetoothProfile {
}
public boolean supportsHighQualityAudio(BluetoothDevice device) {
- int support = mService.supportsOptionalCodecs(device);
+ BluetoothDevice bluetoothDevice = (device == null) ? device : mService.getActiveDevice();
+ if (bluetoothDevice == null) {
+ return false;
+ }
+ int support = mService.isOptionalCodecsSupported(bluetoothDevice);
return support == BluetoothA2dp.OPTIONAL_CODECS_SUPPORTED;
}
public boolean isHighQualityAudioEnabled(BluetoothDevice device) {
- int enabled = mService.getOptionalCodecsEnabled(device);
+ BluetoothDevice bluetoothDevice = (device == null) ? device : mService.getActiveDevice();
+ if (bluetoothDevice == null) {
+ return false;
+ }
+ int enabled = mService.isOptionalCodecsEnabled(bluetoothDevice);
if (enabled != BluetoothA2dp.OPTIONAL_CODECS_PREF_UNKNOWN) {
return enabled == BluetoothA2dp.OPTIONAL_CODECS_PREF_ENABLED;
- } else if (getConnectionStatus(device) != BluetoothProfile.STATE_CONNECTED &&
- supportsHighQualityAudio(device)) {
+ } else if (getConnectionStatus(bluetoothDevice) != BluetoothProfile.STATE_CONNECTED
+ && supportsHighQualityAudio(bluetoothDevice)) {
// Since we don't have a stored preference and the device isn't connected, just return
// true since the default behavior when the device gets connected in the future would be
// to have optional codecs enabled.
return true;
}
BluetoothCodecConfig codecConfig = null;
- if (mService.getCodecStatus(device) != null) {
- codecConfig = mService.getCodecStatus(device).getCodecConfig();
+ if (mService.getCodecStatus(bluetoothDevice) != null) {
+ codecConfig = mService.getCodecStatus(bluetoothDevice).getCodecConfig();
}
if (codecConfig != null) {
return !codecConfig.isMandatoryCodec();
@@ -245,23 +253,28 @@ public class A2dpProfile implements LocalBluetoothProfile {
}
public void setHighQualityAudioEnabled(BluetoothDevice device, boolean enabled) {
+ BluetoothDevice bluetoothDevice = (device == null) ? device : mService.getActiveDevice();
+ if (bluetoothDevice == null) {
+ return;
+ }
int prefValue = enabled
? BluetoothA2dp.OPTIONAL_CODECS_PREF_ENABLED
: BluetoothA2dp.OPTIONAL_CODECS_PREF_DISABLED;
- mService.setOptionalCodecsEnabled(device, prefValue);
- if (getConnectionStatus(device) != BluetoothProfile.STATE_CONNECTED) {
+ mService.setOptionalCodecsEnabled(bluetoothDevice, prefValue);
+ if (getConnectionStatus(bluetoothDevice) != BluetoothProfile.STATE_CONNECTED) {
return;
}
if (enabled) {
- mService.enableOptionalCodecs(device);
+ mService.enableOptionalCodecs(bluetoothDevice);
} else {
- mService.disableOptionalCodecs(device);
+ mService.disableOptionalCodecs(bluetoothDevice);
}
}
public String getHighQualityAudioOptionLabel(BluetoothDevice device) {
+ BluetoothDevice bluetoothDevice = (device == null) ? device : mService.getActiveDevice();
int unknownCodecId = R.string.bluetooth_profile_a2dp_high_quality_unknown_codec;
- if (!supportsHighQualityAudio(device)
+ if (bluetoothDevice == null || !supportsHighQualityAudio(device)
|| getConnectionStatus(device) != BluetoothProfile.STATE_CONNECTED) {
return mContext.getString(unknownCodecId);
}
diff --git a/packages/SettingsLib/src/com/android/settingslib/media/InfoMediaManager.java b/packages/SettingsLib/src/com/android/settingslib/media/InfoMediaManager.java
index 3ae9e1ed78c3..eb0ddfb492cb 100644
--- a/packages/SettingsLib/src/com/android/settingslib/media/InfoMediaManager.java
+++ b/packages/SettingsLib/src/com/android/settingslib/media/InfoMediaManager.java
@@ -24,6 +24,7 @@ import static android.media.MediaRoute2Info.TYPE_REMOTE_TV;
import static android.media.MediaRoute2Info.TYPE_UNKNOWN;
import static android.media.MediaRoute2Info.TYPE_WIRED_HEADPHONES;
import static android.media.MediaRoute2Info.TYPE_WIRED_HEADSET;
+import static android.media.MediaRoute2ProviderService.REASON_UNKNOWN_ERROR;
import android.app.Notification;
import android.bluetooth.BluetoothAdapter;
@@ -50,6 +51,7 @@ import java.util.concurrent.Executors;
public class InfoMediaManager extends MediaManager {
private static final String TAG = "InfoMediaManager";
+ private static final boolean DEBUG = false;
@VisibleForTesting
final RouterManagerCallback mMediaRouterCallback = new RouterManagerCallback();
@@ -311,6 +313,21 @@ public class InfoMediaManager extends MediaManager {
return -1;
}
+ CharSequence getSessionName() {
+ if (TextUtils.isEmpty(mPackageName)) {
+ Log.w(TAG, "Unable to get session name. The package name is null or empty!");
+ return null;
+ }
+
+ final RoutingSessionInfo info = getRoutingSessionInfo();
+ if (info != null) {
+ return info.getName();
+ }
+
+ Log.w(TAG, "Unable to get session name for package: " + mPackageName);
+ return null;
+ }
+
private void refreshDevices() {
mMediaDevices.clear();
mCurrentConnectedDevice = null;
@@ -324,6 +341,9 @@ public class InfoMediaManager extends MediaManager {
private void buildAllRoutes() {
for (MediaRoute2Info route : mRouterManager.getAllRoutes()) {
+ if (DEBUG) {
+ Log.d(TAG, "buildAllRoutes() route : " + route.getName());
+ }
if (route.isSystemRoute()) {
addMediaDevice(route);
}
@@ -332,6 +352,9 @@ public class InfoMediaManager extends MediaManager {
private void buildAvailableRoutes() {
for (MediaRoute2Info route : mRouterManager.getAvailableRoutes(mPackageName)) {
+ if (DEBUG) {
+ Log.d(TAG, "buildAvailableRoutes() route : " + route.getName());
+ }
addMediaDevice(route);
}
}
@@ -348,7 +371,8 @@ public class InfoMediaManager extends MediaManager {
mediaDevice = new InfoMediaDevice(mContext, mRouterManager, route,
mPackageName);
if (!TextUtils.isEmpty(mPackageName)
- && TextUtils.equals(route.getClientPackageName(), mPackageName)) {
+ && TextUtils.equals(route.getClientPackageName(), mPackageName)
+ && mCurrentConnectedDevice == null) {
mCurrentConnectedDevice = mediaDevice;
}
break;
@@ -394,12 +418,41 @@ public class InfoMediaManager extends MediaManager {
@Override
public void onRoutesChanged(List<MediaRoute2Info> routes) {
- refreshDevices();
+ mMediaDevices.clear();
+ mCurrentConnectedDevice = null;
+ if (TextUtils.isEmpty(mPackageName)) {
+ buildAllRoutes();
+ } else {
+ buildAvailableRoutes();
+ }
+
+ final String id = mCurrentConnectedDevice != null
+ ? mCurrentConnectedDevice.getId()
+ : null;
+ dispatchConnectedDeviceChanged(id);
}
@Override
public void onRoutesRemoved(List<MediaRoute2Info> routes) {
refreshDevices();
}
+
+ @Override
+ public void onTransferred(RoutingSessionInfo oldSession, RoutingSessionInfo newSession) {
+ if (DEBUG) {
+ Log.d(TAG, "onTransferred() oldSession : " + oldSession.getName()
+ + ", newSession : " + newSession.getName());
+ }
+ }
+
+ @Override
+ public void onTransferFailed(RoutingSessionInfo session, MediaRoute2Info route) {
+ dispatchOnRequestFailed(REASON_UNKNOWN_ERROR);
+ }
+
+ @Override
+ public void onRequestFailed(int reason) {
+ dispatchOnRequestFailed(reason);
+ }
}
}
diff --git a/packages/SettingsLib/src/com/android/settingslib/media/LocalMediaManager.java b/packages/SettingsLib/src/com/android/settingslib/media/LocalMediaManager.java
index c70811f1f20e..90f55dd6f38d 100644
--- a/packages/SettingsLib/src/com/android/settingslib/media/LocalMediaManager.java
+++ b/packages/SettingsLib/src/com/android/settingslib/media/LocalMediaManager.java
@@ -142,20 +142,11 @@ public class LocalMediaManager implements BluetoothCallback {
mCurrentConnectedDevice.disconnect();
}
- boolean isConnected = false;
if (TextUtils.isEmpty(mPackageName)) {
- isConnected = mInfoMediaManager.connectDeviceWithoutPackageName(device);
+ mInfoMediaManager.connectDeviceWithoutPackageName(device);
} else {
- isConnected = device.connect();
+ device.connect();
}
- if (isConnected) {
- mCurrentConnectedDevice = device;
- }
-
- final int state = isConnected
- ? MediaDeviceState.STATE_CONNECTED
- : MediaDeviceState.STATE_DISCONNECTED;
- dispatchSelectedDeviceStateChanged(device, state);
}
void dispatchSelectedDeviceStateChanged(MediaDevice device, @MediaDeviceState int state) {
@@ -186,6 +177,12 @@ public class LocalMediaManager implements BluetoothCallback {
}
}
+ void dispatchOnRequestFailed(int reason) {
+ for (DeviceCallback callback : getCallbacks()) {
+ callback.onRequestFailed(reason);
+ }
+ }
+
/**
* Stop scan MediaDevice
*/
@@ -324,11 +321,20 @@ public class LocalMediaManager implements BluetoothCallback {
return mInfoMediaManager.getSessionVolume();
}
+ /**
+ * Gets the user-visible name of the {@link android.media.RoutingSessionInfo}.
+ *
+ * @return current name of the session, and return {@code null} if not found.
+ */
+ public CharSequence getSessionName() {
+ return mInfoMediaManager.getSessionName();
+ }
+
private MediaDevice updateCurrentConnectedDevice() {
MediaDevice phoneMediaDevice = null;
for (MediaDevice device : mMediaDevices) {
if (device instanceof BluetoothMediaDevice) {
- if (isConnected(((BluetoothMediaDevice) device).getCachedDevice())) {
+ if (isActiveDevice(((BluetoothMediaDevice) device).getCachedDevice())) {
return device;
}
} else if (device instanceof PhoneMediaDevice) {
@@ -338,7 +344,7 @@ public class LocalMediaManager implements BluetoothCallback {
return mMediaDevices.contains(phoneMediaDevice) ? phoneMediaDevice : null;
}
- private boolean isConnected(CachedBluetoothDevice device) {
+ private boolean isActiveDevice(CachedBluetoothDevice device) {
return device.isActiveDevice(BluetoothProfile.A2DP)
|| device.isActiveDevice(BluetoothProfile.HEARING_AID);
}
@@ -414,20 +420,28 @@ public class LocalMediaManager implements BluetoothCallback {
@Override
public void onConnectedDeviceChanged(String id) {
- final MediaDevice connectDevice = getMediaDeviceById(mMediaDevices, id);
+ MediaDevice connectDevice = getMediaDeviceById(mMediaDevices, id);
+ connectDevice = connectDevice != null
+ ? connectDevice : updateCurrentConnectedDevice();
if (connectDevice == mCurrentConnectedDevice) {
Log.d(TAG, "onConnectedDeviceChanged() this device all ready connected!");
return;
}
mCurrentConnectedDevice = connectDevice;
- dispatchDeviceAttributesChanged();
+ dispatchSelectedDeviceStateChanged(mCurrentConnectedDevice,
+ MediaDeviceState.STATE_CONNECTED);
}
@Override
public void onDeviceAttributesChanged() {
dispatchDeviceAttributesChanged();
}
+
+ @Override
+ public void onRequestFailed(int reason) {
+ dispatchOnRequestFailed(reason);
+ }
}
@@ -458,6 +472,18 @@ public class LocalMediaManager implements BluetoothCallback {
* Callback for notifying the device attributes is changed.
*/
default void onDeviceAttributesChanged() {};
+
+ /**
+ * Callback for notifying that transferring is failed.
+ *
+ * @param reason the reason that the request has failed. Can be one of followings:
+ * {@link android.media.MediaRoute2ProviderService#REASON_UNKNOWN_ERROR},
+ * {@link android.media.MediaRoute2ProviderService#REASON_REJECTED},
+ * {@link android.media.MediaRoute2ProviderService#REASON_NETWORK_ERROR},
+ * {@link android.media.MediaRoute2ProviderService#REASON_ROUTE_NOT_AVAILABLE},
+ * {@link android.media.MediaRoute2ProviderService#REASON_INVALID_COMMAND},
+ */
+ default void onRequestFailed(int reason){};
}
/**
diff --git a/packages/SettingsLib/src/com/android/settingslib/media/MediaManager.java b/packages/SettingsLib/src/com/android/settingslib/media/MediaManager.java
index 73551f60c462..e8cbab8197b2 100644
--- a/packages/SettingsLib/src/com/android/settingslib/media/MediaManager.java
+++ b/packages/SettingsLib/src/com/android/settingslib/media/MediaManager.java
@@ -110,6 +110,12 @@ public abstract class MediaManager {
}
}
+ protected void dispatchOnRequestFailed(int reason) {
+ for (MediaDeviceCallback callback : getCallbacks()) {
+ callback.onRequestFailed(reason);
+ }
+ }
+
private Collection<MediaDeviceCallback> getCallbacks() {
return new CopyOnWriteArrayList<>(mCallbacks);
}
@@ -158,5 +164,17 @@ public abstract class MediaManager {
* (e.g: device name, connection state, subtitle) is changed.
*/
void onDeviceAttributesChanged();
+
+ /**
+ * Callback for notifying that transferring is failed.
+ *
+ * @param reason the reason that the request has failed. Can be one of followings:
+ * {@link android.media.MediaRoute2ProviderService#REASON_UNKNOWN_ERROR},
+ * {@link android.media.MediaRoute2ProviderService#REASON_REJECTED},
+ * {@link android.media.MediaRoute2ProviderService#REASON_NETWORK_ERROR},
+ * {@link android.media.MediaRoute2ProviderService#REASON_ROUTE_NOT_AVAILABLE},
+ * {@link android.media.MediaRoute2ProviderService#REASON_INVALID_COMMAND},
+ */
+ void onRequestFailed(int reason);
}
}
diff --git a/packages/SettingsLib/src/com/android/settingslib/wifi/WifiEntryPreference.java b/packages/SettingsLib/src/com/android/settingslib/wifi/WifiEntryPreference.java
index 4ebb1029ff04..6a7000eb92c8 100644
--- a/packages/SettingsLib/src/com/android/settingslib/wifi/WifiEntryPreference.java
+++ b/packages/SettingsLib/src/com/android/settingslib/wifi/WifiEntryPreference.java
@@ -43,10 +43,6 @@ public class WifiEntryPreference extends Preference implements WifiEntry.WifiEnt
R.attr.state_encrypted
};
- private static final int[] STATE_METERED = {
- R.attr.state_metered
- };
-
private static final int[] FRICTION_ATTRS = {
R.attr.wifi_friction
};
@@ -201,8 +197,6 @@ public class WifiEntryPreference extends Preference implements WifiEntry.WifiEnt
if ((mWifiEntry.getSecurity() != WifiEntry.SECURITY_NONE)
&& (mWifiEntry.getSecurity() != WifiEntry.SECURITY_OWE)) {
mFrictionSld.setState(STATE_SECURED);
- } else if (mWifiEntry.isMetered()) {
- mFrictionSld.setState(STATE_METERED);
}
frictionImageView.setImageDrawable(mFrictionSld.getCurrent());
}
diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/bluetooth/A2dpProfileTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/bluetooth/A2dpProfileTest.java
index 414c39bc0ce9..9afdd43ce73c 100644
--- a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/bluetooth/A2dpProfileTest.java
+++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/bluetooth/A2dpProfileTest.java
@@ -69,30 +69,31 @@ public class A2dpProfileTest {
mProfile = new A2dpProfile(mContext, mDeviceManager, mProfileManager);
mServiceListener = mShadowBluetoothAdapter.getServiceListener();
mServiceListener.onServiceConnected(BluetoothProfile.A2DP, mBluetoothA2dp);
+ when(mBluetoothA2dp.getActiveDevice()).thenReturn(mDevice);
}
@Test
public void supportsHighQualityAudio() {
- when(mBluetoothA2dp.supportsOptionalCodecs(any())).thenReturn(
+ when(mBluetoothA2dp.isOptionalCodecsSupported(mDevice)).thenReturn(
BluetoothA2dp.OPTIONAL_CODECS_SUPPORTED);
assertThat(mProfile.supportsHighQualityAudio(mDevice)).isTrue();
- when(mBluetoothA2dp.supportsOptionalCodecs(any())).thenReturn(
+ when(mBluetoothA2dp.isOptionalCodecsSupported(mDevice)).thenReturn(
BluetoothA2dp.OPTIONAL_CODECS_NOT_SUPPORTED);
assertThat(mProfile.supportsHighQualityAudio(mDevice)).isFalse();
- when(mBluetoothA2dp.supportsOptionalCodecs(any())).thenReturn(
+ when(mBluetoothA2dp.isOptionalCodecsSupported(mDevice)).thenReturn(
BluetoothA2dp.OPTIONAL_CODECS_SUPPORT_UNKNOWN);
assertThat(mProfile.supportsHighQualityAudio(mDevice)).isFalse();
}
@Test
public void isHighQualityAudioEnabled() {
- when(mBluetoothA2dp.getOptionalCodecsEnabled(any())).thenReturn(
+ when(mBluetoothA2dp.isOptionalCodecsEnabled(mDevice)).thenReturn(
BluetoothA2dp.OPTIONAL_CODECS_PREF_ENABLED);
assertThat(mProfile.isHighQualityAudioEnabled(mDevice)).isTrue();
- when(mBluetoothA2dp.getOptionalCodecsEnabled(any())).thenReturn(
+ when(mBluetoothA2dp.isOptionalCodecsEnabled(mDevice)).thenReturn(
BluetoothA2dp.OPTIONAL_CODECS_PREF_DISABLED);
assertThat(mProfile.isHighQualityAudioEnabled(mDevice)).isFalse();
@@ -100,16 +101,16 @@ public class A2dpProfileTest {
// then isHighQualityAudioEnabled() should return true or false based on whether optional
// codecs are supported. If the device is connected then we should ask it directly, but if
// the device isn't connected then rely on the stored pref about such support.
- when(mBluetoothA2dp.getOptionalCodecsEnabled(any())).thenReturn(
+ when(mBluetoothA2dp.isOptionalCodecsEnabled(mDevice)).thenReturn(
BluetoothA2dp.OPTIONAL_CODECS_PREF_UNKNOWN);
when(mBluetoothA2dp.getConnectionState(any())).thenReturn(
BluetoothProfile.STATE_DISCONNECTED);
- when(mBluetoothA2dp.supportsOptionalCodecs(any())).thenReturn(
+ when(mBluetoothA2dp.isOptionalCodecsSupported(mDevice)).thenReturn(
BluetoothA2dp.OPTIONAL_CODECS_NOT_SUPPORTED);
assertThat(mProfile.isHighQualityAudioEnabled(mDevice)).isFalse();
- when(mBluetoothA2dp.supportsOptionalCodecs(any())).thenReturn(
+ when(mBluetoothA2dp.isOptionalCodecsSupported(mDevice)).thenReturn(
BluetoothA2dp.OPTIONAL_CODECS_SUPPORTED);
assertThat(mProfile.isHighQualityAudioEnabled(mDevice)).isTrue();
@@ -151,14 +152,14 @@ public class A2dpProfileTest {
// Most tests want to simulate optional codecs being supported by the device, so do that
// by default here.
- when(mBluetoothA2dp.supportsOptionalCodecs(any())).thenReturn(
+ when(mBluetoothA2dp.isOptionalCodecsSupported(any())).thenReturn(
BluetoothA2dp.OPTIONAL_CODECS_SUPPORTED);
}
@Test
public void getLableCodecsNotSupported() {
setupLabelTest();
- when(mBluetoothA2dp.supportsOptionalCodecs(any())).thenReturn(
+ when(mBluetoothA2dp.isOptionalCodecsSupported(any())).thenReturn(
BluetoothA2dp.OPTIONAL_CODECS_NOT_SUPPORTED);
assertThat(mProfile.getHighQualityAudioOptionLabel(mDevice)).isEqualTo(UNKNOWN_CODEC_LABEL);
}
diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/media/InfoMediaManagerTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/media/InfoMediaManagerTest.java
index edb121b762a7..7f93f697152c 100644
--- a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/media/InfoMediaManagerTest.java
+++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/media/InfoMediaManagerTest.java
@@ -16,6 +16,9 @@
package com.android.settingslib.media;
+import static android.media.MediaRoute2ProviderService.REASON_NETWORK_ERROR;
+import static android.media.MediaRoute2ProviderService.REASON_UNKNOWN_ERROR;
+
import static com.google.common.truth.Truth.assertThat;
import static org.mockito.Mockito.mock;
@@ -54,6 +57,8 @@ public class InfoMediaManagerTest {
private MediaRouter2Manager mRouterManager;
@Mock
private LocalBluetoothManager mLocalBluetoothManager;
+ @Mock
+ private MediaManager.MediaDeviceCallback mCallback;
private InfoMediaManager mInfoMediaManager;
private Context mContext;
@@ -144,6 +149,8 @@ public class InfoMediaManagerTest {
@Test
public void onRoutesChanged_getAvailableRoutes_shouldAddMediaDevice() {
final MediaRoute2Info info = mock(MediaRoute2Info.class);
+ mInfoMediaManager.registerCallback(mCallback);
+
when(info.getId()).thenReturn(TEST_ID);
when(info.getClientPackageName()).thenReturn(TEST_PACKAGE_NAME);
@@ -160,11 +167,14 @@ public class InfoMediaManagerTest {
assertThat(infoDevice.getId()).isEqualTo(TEST_ID);
assertThat(mInfoMediaManager.getCurrentConnectedDevice()).isEqualTo(infoDevice);
assertThat(mInfoMediaManager.mMediaDevices).hasSize(routes.size());
+ verify(mCallback).onConnectedDeviceChanged(TEST_ID);
}
@Test
public void onRoutesChanged_buildAllRoutes_shouldAddMediaDevice() {
final MediaRoute2Info info = mock(MediaRoute2Info.class);
+ mInfoMediaManager.registerCallback(mCallback);
+
when(info.getId()).thenReturn(TEST_ID);
when(info.getClientPackageName()).thenReturn(TEST_PACKAGE_NAME);
when(info.isSystemRoute()).thenReturn(true);
@@ -182,6 +192,7 @@ public class InfoMediaManagerTest {
final MediaDevice infoDevice = mInfoMediaManager.mMediaDevices.get(0);
assertThat(infoDevice.getId()).isEqualTo(TEST_ID);
assertThat(mInfoMediaManager.mMediaDevices).hasSize(routes.size());
+ verify(mCallback).onConnectedDeviceChanged(null);
}
@Test
@@ -460,4 +471,55 @@ public class InfoMediaManagerTest {
assertThat(mInfoMediaManager.releaseSession()).isTrue();
}
+
+ @Test
+ public void getSessionName_packageNameIsNull_returnNull() {
+ mInfoMediaManager.mPackageName = null;
+
+ assertThat(mInfoMediaManager.getSessionName()).isNull();
+ }
+
+ @Test
+ public void getSessionName_notContainPackageName_returnNull() {
+ final List<RoutingSessionInfo> routingSessionInfos = new ArrayList<>();
+ final RoutingSessionInfo info = mock(RoutingSessionInfo.class);
+ routingSessionInfos.add(info);
+
+ mShadowRouter2Manager.setRoutingSessions(routingSessionInfos);
+ when(info.getClientPackageName()).thenReturn("com.fake.packagename");
+ when(info.getName()).thenReturn(TEST_NAME);
+
+ assertThat(mInfoMediaManager.getSessionName()).isNull();
+ }
+
+ @Test
+ public void getSessionName_containPackageName_returnName() {
+ final List<RoutingSessionInfo> routingSessionInfos = new ArrayList<>();
+ final RoutingSessionInfo info = mock(RoutingSessionInfo.class);
+ routingSessionInfos.add(info);
+
+ mShadowRouter2Manager.setRoutingSessions(routingSessionInfos);
+ when(info.getClientPackageName()).thenReturn(TEST_PACKAGE_NAME);
+ when(info.getName()).thenReturn(TEST_NAME);
+
+ assertThat(mInfoMediaManager.getSessionName()).isEqualTo(TEST_NAME);
+ }
+
+ @Test
+ public void onTransferFailed_shouldDispatchOnRequestFailed() {
+ mInfoMediaManager.registerCallback(mCallback);
+
+ mInfoMediaManager.mMediaRouterCallback.onTransferFailed(null, null);
+
+ verify(mCallback).onRequestFailed(REASON_UNKNOWN_ERROR);
+ }
+
+ @Test
+ public void onRequestFailed_shouldDispatchOnRequestFailed() {
+ mInfoMediaManager.registerCallback(mCallback);
+
+ mInfoMediaManager.mMediaRouterCallback.onRequestFailed(REASON_NETWORK_ERROR);
+
+ verify(mCallback).onRequestFailed(REASON_NETWORK_ERROR);
+ }
}
diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/media/LocalMediaManagerTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/media/LocalMediaManagerTest.java
index 3611dfefbb7f..1e888da6468e 100644
--- a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/media/LocalMediaManagerTest.java
+++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/media/LocalMediaManagerTest.java
@@ -477,4 +477,13 @@ public class LocalMediaManagerTest {
assertThat(mLocalMediaManager.mMediaDevices).hasSize(3);
verify(mCallback).onDeviceListUpdate(any());
}
+
+ @Test
+ public void onRequestFailed_shouldDispatchOnRequestFailed() {
+ mLocalMediaManager.registerCallback(mCallback);
+
+ mLocalMediaManager.mMediaDeviceCallback.onRequestFailed(1);
+
+ verify(mCallback).onRequestFailed(1);
+ }
}
diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/media/MediaManagerTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/media/MediaManagerTest.java
index ead2be4d7b26..a50965ab2619 100644
--- a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/media/MediaManagerTest.java
+++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/media/MediaManagerTest.java
@@ -136,4 +136,14 @@ public class MediaManagerTest {
assertThat(device).isNull();
}
+
+ @Test
+ public void dispatchOnRequestFailed_registerCallback_shouldDispatchCallback() {
+ mMediaManager.registerCallback(mCallback);
+
+ mMediaManager.dispatchOnRequestFailed(1);
+
+ verify(mCallback).onRequestFailed(1);
+ }
+
}
diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/schedulesprovider/ScheduleInfoTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/schedulesprovider/ScheduleInfoTest.java
index 5ec89eddda6e..b4b910d21da8 100644
--- a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/schedulesprovider/ScheduleInfoTest.java
+++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/schedulesprovider/ScheduleInfoTest.java
@@ -17,11 +17,14 @@ package com.android.settingslib.schedulesprovider;
import static com.google.common.truth.Truth.assertThat;
+import android.app.PendingIntent;
+import android.content.Context;
import android.content.Intent;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.robolectric.RobolectricTestRunner;
+import org.robolectric.RuntimeEnvironment;
@RunWith(RobolectricTestRunner.class)
public class ScheduleInfoTest {
@@ -29,10 +32,12 @@ public class ScheduleInfoTest {
private static final String TEST_SUMMARY = "Night Light summary";
private static final String TEST_EMPTY_SUMMARY = "";
+ private final Context mContext = RuntimeEnvironment.application;
+
@Test
public void builder_usedValidArguments_isValid() {
- final Intent intent = createTestIntent();
- final ScheduleInfo info = createTestScheduleInfo(TEST_TITLE, TEST_SUMMARY, intent);
+ final PendingIntent pendingIntent = createTestPendingIntent(mContext);
+ final ScheduleInfo info = createTestScheduleInfo(TEST_TITLE, TEST_SUMMARY, pendingIntent);
assertThat(info).isNotNull();
assertThat(info.isValid()).isTrue();
@@ -40,15 +45,16 @@ public class ScheduleInfoTest {
@Test
public void builder_useEmptySummary_isInvalid() {
- final Intent intent = createTestIntent();
- final ScheduleInfo info = createTestScheduleInfo(TEST_TITLE, TEST_EMPTY_SUMMARY, intent);
+ final PendingIntent pendingIntent = createTestPendingIntent(mContext);
+ final ScheduleInfo info = createTestScheduleInfo(TEST_TITLE, TEST_EMPTY_SUMMARY,
+ pendingIntent);
assertThat(info).isNotNull();
assertThat(info.isValid()).isFalse();
}
@Test
- public void builder_intentIsNull_isInvalid() {
+ public void builder_pendingIntentIsNull_isInvalid() {
final ScheduleInfo info = new ScheduleInfo.Builder()
.setTitle(TEST_TITLE)
.setSummary(TEST_SUMMARY)
@@ -60,39 +66,40 @@ public class ScheduleInfoTest {
@Test
public void getTitle_setValidTitle_shouldReturnSameCorrectTitle() {
- final Intent intent = createTestIntent();
- final ScheduleInfo info = createTestScheduleInfo(TEST_TITLE, TEST_SUMMARY, intent);
+ final PendingIntent pendingIntent = createTestPendingIntent(mContext);
+ final ScheduleInfo info = createTestScheduleInfo(TEST_TITLE, TEST_SUMMARY, pendingIntent);
assertThat(info.getTitle()).isEqualTo(TEST_TITLE);
}
@Test
public void getSummary_setValidSummary_shouldReturnSameCorrectSummary() {
- final Intent intent = createTestIntent();
- final ScheduleInfo info = createTestScheduleInfo(TEST_TITLE, TEST_SUMMARY, intent);
+ final PendingIntent pendingIntent = createTestPendingIntent(mContext);
+ final ScheduleInfo info = createTestScheduleInfo(TEST_TITLE, TEST_SUMMARY, pendingIntent);
assertThat(info.getSummary()).isEqualTo(TEST_SUMMARY);
}
@Test
- public void getIntent_setValidIntent_shouldReturnSameCorrectIntent() {
- final Intent intent = createTestIntent();
- final ScheduleInfo info = createTestScheduleInfo(TEST_TITLE, TEST_SUMMARY, intent);
+ public void getPendingIntent_setValidPendingIntent_shouldReturnSameCorrectIntent() {
+ final PendingIntent pendingIntent = createTestPendingIntent(mContext);
+ final ScheduleInfo info = createTestScheduleInfo(TEST_TITLE, TEST_SUMMARY, pendingIntent);
- assertThat(info.getIntent()).isEqualTo(intent);
+ assertThat(info.getPendingIntent()).isEqualTo(pendingIntent);
}
- private static Intent createTestIntent() {
- return new Intent("android.settings.NIGHT_DISPLAY_SETTINGS").addCategory(
+ private static PendingIntent createTestPendingIntent(Context context) {
+ final Intent intent = new Intent("android.settings.NIGHT_DISPLAY_SETTINGS").addCategory(
Intent.CATEGORY_DEFAULT);
+ return PendingIntent.getActivity(context, 0 /* requestCode */, intent, 0 /* flags */);
}
private static ScheduleInfo createTestScheduleInfo(String title, String summary,
- Intent intent) {
+ PendingIntent pendingIntent) {
return new ScheduleInfo.Builder()
.setTitle(title)
.setSummary(summary)
- .setIntent(intent)
+ .setPendingIntent(pendingIntent)
.build();
}
}
diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/schedulesprovider/SchedulesProviderTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/schedulesprovider/SchedulesProviderTest.java
index eb2e8e055378..6b92082b1103 100644
--- a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/schedulesprovider/SchedulesProviderTest.java
+++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/schedulesprovider/SchedulesProviderTest.java
@@ -19,6 +19,8 @@ import static com.google.common.truth.Truth.assertThat;
import static org.robolectric.Shadows.shadowOf;
+import android.app.PendingIntent;
+import android.content.Context;
import android.content.Intent;
import android.os.Bundle;
@@ -27,6 +29,7 @@ import org.junit.Test;
import org.junit.runner.RunWith;
import org.robolectric.Robolectric;
import org.robolectric.RobolectricTestRunner;
+import org.robolectric.RuntimeEnvironment;
import java.util.ArrayList;
@@ -35,13 +38,16 @@ public class SchedulesProviderTest {
private static final String INVALID_PACKAGE = "com.android.sunny";
private static final String VALID_PACKAGE = "com.android.settings";
private static final String INVALID_METHOD = "queryTestData";
+
+ private final Context mContext = RuntimeEnvironment.application;
+
private TestSchedulesProvider mProvider;
@Before
public void setUp() {
mProvider = Robolectric.setupContentProvider(TestSchedulesProvider.class);
shadowOf(mProvider).setCallingPackage(VALID_PACKAGE);
- mProvider.setScheduleInfos(TestSchedulesProvider.createOneValidScheduleInfo());
+ mProvider.setScheduleInfos(TestSchedulesProvider.createOneValidScheduleInfo(mContext));
}
@Test
@@ -76,7 +82,7 @@ public class SchedulesProviderTest {
@Test
public void call_addTwoValidData_returnScheduleInfoData() {
- mProvider.setScheduleInfos(TestSchedulesProvider.createTwoValidScheduleInfos());
+ mProvider.setScheduleInfos(TestSchedulesProvider.createTwoValidScheduleInfos(mContext));
final Bundle bundle = mProvider.call(SchedulesProvider.METHOD_GENERATE_SCHEDULE_INFO_LIST,
null /* arg */, null /* extras */);
@@ -89,7 +95,8 @@ public class SchedulesProviderTest {
@Test
public void call_addTwoValidDataAndOneInvalidData_returnTwoScheduleInfoData() {
- mProvider.setScheduleInfos(TestSchedulesProvider.createTwoValidAndOneInvalidScheduleInfo());
+ mProvider.setScheduleInfos(
+ TestSchedulesProvider.createTwoValidAndOneInvalidScheduleInfo(mContext));
final Bundle bundle = mProvider.call(SchedulesProvider.METHOD_GENERATE_SCHEDULE_INFO_LIST,
null /* arg */, null /* extras */);
@@ -112,55 +119,56 @@ public class SchedulesProviderTest {
mScheduleInfos = scheduleInfos;
}
- private static ArrayList<ScheduleInfo> createOneValidScheduleInfo() {
+ private static ArrayList<ScheduleInfo> createOneValidScheduleInfo(Context context) {
final ArrayList<ScheduleInfo> scheduleInfos = new ArrayList<>();
- final Intent intent = new Intent("android.settings.NIGHT_DISPLAY_SETTINGS").addCategory(
- Intent.CATEGORY_DEFAULT);
- final ScheduleInfo info = new ScheduleInfo.Builder().setTitle(
- "Night Light").setSummary("This a sunny test").setIntent(intent).build();
+
+ final ScheduleInfo info = new ScheduleInfo.Builder().setTitle("Night Light").setSummary(
+ "This a sunny test").setPendingIntent(createTestPendingIntent(context,
+ "android.settings.NIGHT_DISPLAY_SETTINGS")).build();
scheduleInfos.add(info);
return scheduleInfos;
}
- private static ArrayList<ScheduleInfo> createTwoValidScheduleInfos() {
+ private static ArrayList<ScheduleInfo> createTwoValidScheduleInfos(Context context) {
final ArrayList<ScheduleInfo> scheduleInfos = new ArrayList<>();
- Intent intent = new Intent("android.settings.NIGHT_DISPLAY_SETTINGS").addCategory(
- Intent.CATEGORY_DEFAULT);
- ScheduleInfo info = new ScheduleInfo.Builder().setTitle(
- "Night Light").setSummary("This a sunny test").setIntent(intent).build();
+ ScheduleInfo info = new ScheduleInfo.Builder().setTitle("Night Light").setSummary(
+ "This a sunny test").setPendingIntent(createTestPendingIntent(context,
+ "android.settings.NIGHT_DISPLAY_SETTINGS")).build();
scheduleInfos.add(info);
- intent = new Intent("android.settings.DISPLAY_SETTINGS").addCategory(
- Intent.CATEGORY_DEFAULT);
info = new ScheduleInfo.Builder().setTitle("Display").setSummary(
- "Display summary").setIntent(intent).build();
+ "Display summary").setPendingIntent(
+ createTestPendingIntent(context, "android.settings.DISPLAY_SETTINGS")).build();
scheduleInfos.add(info);
return scheduleInfos;
}
- private static ArrayList<ScheduleInfo> createTwoValidAndOneInvalidScheduleInfo() {
+ private static ArrayList<ScheduleInfo> createTwoValidAndOneInvalidScheduleInfo(
+ Context context) {
final ArrayList<ScheduleInfo> scheduleInfos = new ArrayList<>();
- Intent intent = new Intent("android.settings.NIGHT_DISPLAY_SETTINGS").addCategory(
- Intent.CATEGORY_DEFAULT);
- ScheduleInfo info = new ScheduleInfo.Builder().setTitle(
- "Night Light").setSummary("This a sunny test").setIntent(intent).build();
+ ScheduleInfo info = new ScheduleInfo.Builder().setTitle("Night Light").setSummary(
+ "This a sunny test").setPendingIntent(createTestPendingIntent(context,
+ "android.settings.NIGHT_DISPLAY_SETTINGS")).build();
scheduleInfos.add(info);
- intent = new Intent("android.settings.DISPLAY_SETTINGS").addCategory(
- Intent.CATEGORY_DEFAULT);
info = new ScheduleInfo.Builder().setTitle("Display").setSummary(
- "Display summary").setIntent(intent).build();
+ "Display summary").setPendingIntent(
+ createTestPendingIntent(context, "android.settings.DISPLAY_SETTINGS")).build();
scheduleInfos.add(info);
- intent = new Intent("android.settings.DISPLAY_SETTINGS").addCategory(
- Intent.CATEGORY_DEFAULT);
- info = new ScheduleInfo.Builder().setTitle("").setSummary("Display summary").setIntent(
- intent).build();
+ info = new ScheduleInfo.Builder().setTitle("").setSummary(
+ "Display summary").setPendingIntent(
+ createTestPendingIntent(context, "android.settings.DISPLAY_SETTINGS")).build();
scheduleInfos.add(info);
return scheduleInfos;
}
+
+ private static PendingIntent createTestPendingIntent(Context context, String action) {
+ final Intent intent = new Intent(action).addCategory(Intent.CATEGORY_DEFAULT);
+ return PendingIntent.getActivity(context, 0 /* requestCode */, intent, 0 /* flags */);
+ }
}
}
diff --git a/packages/SettingsProvider/res/values-ta/strings.xml b/packages/SettingsProvider/res/values-ta/strings.xml
index fa6b8cd9c456..54d2242dced9 100644
--- a/packages/SettingsProvider/res/values-ta/strings.xml
+++ b/packages/SettingsProvider/res/values-ta/strings.xml
@@ -20,8 +20,6 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_label" msgid="4567566098528588863">"அமைப்புகளின் சேமிப்பிடம்"</string>
- <!-- no translation found for wifi_softap_config_change (5688373762357941645) -->
- <skip />
- <!-- no translation found for wifi_softap_config_change_summary (8946397286141531087) -->
- <skip />
+ <string name="wifi_softap_config_change" msgid="5688373762357941645">"ஹாட்ஸ்பாட் அமைப்புகள் மாற்றப்பட்டன"</string>
+ <string name="wifi_softap_config_change_summary" msgid="8946397286141531087">"விவரங்களைப் பார்க்க, தட்டவும்"</string>
</resources>
diff --git a/packages/SettingsProvider/src/android/provider/settings/backup/SecureSettings.java b/packages/SettingsProvider/src/android/provider/settings/backup/SecureSettings.java
index 2431381f3033..8fa98c85fc33 100644
--- a/packages/SettingsProvider/src/android/provider/settings/backup/SecureSettings.java
+++ b/packages/SettingsProvider/src/android/provider/settings/backup/SecureSettings.java
@@ -162,5 +162,6 @@ public class SecureSettings {
Settings.Secure.AWARE_TAP_PAUSE_TOUCH_COUNT,
Settings.Secure.PEOPLE_STRIP,
Settings.Secure.ACCESSIBILITY_MAGNIFICATION_MODE,
+ Settings.Secure.ACCESSIBILITY_BUTTON_LONG_PRESS_TARGETS,
};
}
diff --git a/packages/SettingsProvider/src/android/provider/settings/validators/SecureSettingsValidators.java b/packages/SettingsProvider/src/android/provider/settings/validators/SecureSettingsValidators.java
index 5553469b0420..75c5f9581820 100644
--- a/packages/SettingsProvider/src/android/provider/settings/validators/SecureSettingsValidators.java
+++ b/packages/SettingsProvider/src/android/provider/settings/validators/SecureSettingsValidators.java
@@ -245,5 +245,8 @@ public class SecureSettingsValidators {
new InclusiveIntegerRangeValidator(
Secure.ACCESSIBILITY_MAGNIFICATION_MODE_FULLSCREEN,
Secure.ACCESSIBILITY_MAGNIFICATION_MODE_WINDOW));
+ VALIDATORS.put(
+ Secure.ACCESSIBILITY_BUTTON_LONG_PRESS_TARGETS,
+ ACCESSIBILITY_SHORTCUT_TARGET_LIST_VALIDATOR);
}
}
diff --git a/packages/SettingsProvider/src/com/android/providers/settings/SettingsProtoDumpUtil.java b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProtoDumpUtil.java
index d6776879254d..af74121a11c9 100644
--- a/packages/SettingsProvider/src/com/android/providers/settings/SettingsProtoDumpUtil.java
+++ b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProtoDumpUtil.java
@@ -52,6 +52,8 @@ class SettingsProtoDumpUtil {
ConfigSettingsProto.APP_COMPAT_SETTINGS);
namespaceToFieldMap.put(DeviceConfig.NAMESPACE_AUTOFILL,
ConfigSettingsProto.AUTOFILL_SETTINGS);
+ namespaceToFieldMap.put(DeviceConfig.NAMESPACE_BLOBSTORE,
+ ConfigSettingsProto.BLOBSTORE_SETTINGS);
namespaceToFieldMap.put(DeviceConfig.NAMESPACE_CONNECTIVITY,
ConfigSettingsProto.CONNECTIVITY_SETTINGS);
namespaceToFieldMap.put(DeviceConfig.NAMESPACE_CONTENT_CAPTURE,
@@ -1811,6 +1813,9 @@ class SettingsProtoDumpUtil {
dumpSetting(s, p,
Settings.Secure.ACCESSIBILITY_MAGNIFICATION_MODE,
SecureSettingsProto.Accessibility.ACCESSIBILITY_MAGNIFICATION_MODE);
+ dumpSetting(s, p,
+ Settings.Secure.ACCESSIBILITY_BUTTON_LONG_PRESS_TARGETS,
+ SecureSettingsProto.Accessibility.BUTTON_LONG_PRESS_TARGETS);
p.end(accessibilityToken);
final long adaptiveSleepToken = p.start(SecureSettingsProto.ADAPTIVE_SLEEP);
diff --git a/packages/Shell/AndroidManifest.xml b/packages/Shell/AndroidManifest.xml
index e13e49f420ef..181e0c0790db 100644
--- a/packages/Shell/AndroidManifest.xml
+++ b/packages/Shell/AndroidManifest.xml
@@ -204,7 +204,6 @@
<!-- Permission needed to run network tests in CTS -->
<uses-permission android:name="android.permission.MANAGE_TEST_NETWORKS" />
- <uses-permission android:name="android.permission.NETWORK_STACK" />
<!-- Permission needed to test tcp keepalive offload. -->
<uses-permission android:name="android.permission.PACKET_KEEPALIVE_OFFLOAD" />
diff --git a/packages/SystemUI/Android.bp b/packages/SystemUI/Android.bp
index e0662309f571..0eadcc741747 100644
--- a/packages/SystemUI/Android.bp
+++ b/packages/SystemUI/Android.bp
@@ -46,6 +46,7 @@ android_library {
"SystemUIPluginLib",
"SystemUISharedLib",
"SettingsLib",
+ "androidx.viewpager2_viewpager2",
"androidx.legacy_legacy-support-v4",
"androidx.recyclerview_recyclerview",
"androidx.preference_preference",
@@ -106,6 +107,7 @@ android_library {
"SystemUIPluginLib",
"SystemUISharedLib",
"SettingsLib",
+ "androidx.viewpager2_viewpager2",
"androidx.legacy_legacy-support-v4",
"androidx.recyclerview_recyclerview",
"androidx.preference_preference",
diff --git a/packages/SystemUI/AndroidManifest.xml b/packages/SystemUI/AndroidManifest.xml
index 617ed4e58e77..30b461d1fe45 100644
--- a/packages/SystemUI/AndroidManifest.xml
+++ b/packages/SystemUI/AndroidManifest.xml
@@ -180,6 +180,8 @@
<!-- Adding Controls to SystemUI -->
<uses-permission android:name="android.permission.BIND_CONTROLS" />
+ <!-- Check foreground controls applications -->
+ <uses-permission android:name="android.permission.PACKAGE_USAGE_STATS" />
<!-- Quick Settings tile: Night Mode / Dark Theme -->
<uses-permission android:name="android.permission.MODIFY_DAY_NIGHT_MODE" />
@@ -686,6 +688,25 @@
android:visibleToInstantApps="true">
</activity>
+ <receiver android:name=".controls.management.ControlsRequestReceiver">
+ <intent-filter>
+ <action android:name="android.service.controls.action.ADD_CONTROL" />
+ </intent-filter>
+ </receiver>
+
+ <!-- started from ControlsFavoritingActivity -->
+ <activity
+ android:name=".controls.management.ControlsRequestDialog"
+ android:exported="true"
+ android:theme="@style/Theme.ControlsRequestDialog"
+ android:finishOnCloseSystemDialogs="true"
+ android:showForAllUsers="true"
+ android:clearTaskOnLaunch="true"
+ android:launchMode="singleTask"
+ android:configChanges="screenSize|smallestScreenSize|screenLayout|orientation|keyboard|keyboardHidden"
+ android:excludeFromRecents="true"
+ android:visibleToInstantApps="true"/>
+
<!-- Doze with notifications, run in main sysui process for every user -->
<service
android:name=".doze.DozeService"
diff --git a/packages/SystemUI/res/drawable/control_spinner_background.xml b/packages/SystemUI/res/drawable/control_spinner_background.xml
new file mode 100644
index 000000000000..999a77c71bb2
--- /dev/null
+++ b/packages/SystemUI/res/drawable/control_spinner_background.xml
@@ -0,0 +1,35 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2020 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+
+<layer-list xmlns:android="http://schemas.android.com/apk/res/android"
+ android:paddingMode="stack"
+ android:paddingStart="0dp"
+ android:paddingEnd="40dp"
+ android:paddingLeft="0dp"
+ android:paddingRight="0dp">
+ <item
+ android:gravity="end|fill_vertical"
+ android:width="40dp"
+ android:drawable="@*android:drawable/control_background_40dp_material" />
+
+ <item
+ android:drawable="@drawable/ic_ksh_key_down"
+ android:gravity="end|bottom"
+ android:paddingBottom="6dp"
+ android:width="24dp"
+ android:height="24dp"
+ android:end="12dp" />
+</layer-list>
diff --git a/packages/SystemUI/res/drawable/dismiss_circle_background.xml b/packages/SystemUI/res/drawable/dismiss_circle_background.xml
new file mode 100644
index 000000000000..e311c520d3d6
--- /dev/null
+++ b/packages/SystemUI/res/drawable/dismiss_circle_background.xml
@@ -0,0 +1,28 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ ~ Copyright (C) 2020 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ -->
+
+<shape
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ android:shape="oval">
+
+ <stroke
+ android:width="1dp"
+ android:color="#66FFFFFF" />
+
+ <solid android:color="#B3000000" />
+
+</shape> \ No newline at end of file
diff --git a/packages/SystemUI/res/drawable/dismiss_target_x.xml b/packages/SystemUI/res/drawable/dismiss_target_x.xml
new file mode 100644
index 000000000000..3672efffe139
--- /dev/null
+++ b/packages/SystemUI/res/drawable/dismiss_target_x.xml
@@ -0,0 +1,28 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ ~ Copyright (C) 2020 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ -->
+
+<!-- 'X' icon. -->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="24.0dp"
+ android:height="24.0dp"
+ android:viewportWidth="24.0"
+ android:viewportHeight="24.0">
+ <path
+ android:pathData="M19.000000,6.400000l-1.400000,-1.400000 -5.600000,5.600000 -5.600000,-5.600000 -1.400000,1.400000 5.600000,5.600000 -5.600000,5.600000 1.400000,1.400000 5.600000,-5.600000 5.600000,5.600000 1.400000,-1.400000 -5.600000,-5.600000z"
+ android:fillColor="#FFFFFFFF"
+ android:strokeColor="#FF000000"/>
+</vector> \ No newline at end of file
diff --git a/packages/SystemUI/res/layout-land-television/volume_dialog.xml b/packages/SystemUI/res/layout-land-television/volume_dialog.xml
new file mode 100644
index 000000000000..e0d158d757b3
--- /dev/null
+++ b/packages/SystemUI/res/layout-land-television/volume_dialog.xml
@@ -0,0 +1,101 @@
+<!--
+ ~ Copyright (C) 2020 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License
+ -->
+<FrameLayout
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:sysui="http://schemas.android.com/apk/res-auto"
+ android:id="@+id/volume_dialog_container"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:background="@android:color/transparent"
+ android:theme="@style/qs_theme">
+
+ <FrameLayout
+ android:id="@+id/volume_dialog"
+ android:minWidth="@dimen/volume_dialog_panel_width"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_gravity="right"
+ android:background="@android:color/transparent"
+ android:paddingRight="@dimen/volume_dialog_panel_transparent_padding_right"
+ android:paddingTop="@dimen/volume_dialog_panel_transparent_padding"
+ android:paddingBottom="@dimen/volume_dialog_panel_transparent_padding"
+ android:paddingLeft="@dimen/volume_dialog_panel_transparent_padding"
+ android:clipToPadding="false">
+
+ <LinearLayout
+ android:id="@+id/main"
+ android:layout_width="wrap_content"
+ android:minWidth="@dimen/volume_dialog_panel_width"
+ android:layout_height="wrap_content"
+ android:layout_marginTop="68dp"
+ android:layout_gravity="right"
+ android:orientation="vertical"
+ android:translationZ="@dimen/volume_dialog_elevation"
+ android:clipChildren="false"
+ android:clipToPadding="false"
+ android:background="@drawable/rounded_bg_full">
+
+ <LinearLayout
+ android:id="@+id/volume_dialog_rows"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:minWidth="@dimen/volume_dialog_panel_width"
+ android:gravity="center"
+ android:orientation="horizontal"
+ android:paddingRight="@dimen/volume_dialog_stream_padding"
+ android:paddingLeft="@dimen/volume_dialog_stream_padding">
+ <!-- volume rows added and removed here! :-) -->
+ </LinearLayout>
+
+ </LinearLayout>
+
+ <FrameLayout
+ android:id="@+id/odi_captions"
+ android:layout_width="@dimen/volume_dialog_caption_size"
+ android:layout_height="@dimen/volume_dialog_caption_size"
+ android:layout_marginRight="68dp"
+ android:layout_gravity="right"
+ android:clipToPadding="false"
+ android:translationZ="@dimen/volume_dialog_elevation"
+ android:background="@drawable/rounded_bg_full">
+
+ <com.android.systemui.volume.CaptionsToggleImageButton
+ android:id="@+id/odi_captions_icon"
+ android:src="@drawable/ic_volume_odi_captions_disabled"
+ style="@style/VolumeButtons"
+ android:background="@drawable/rounded_ripple"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:tint="@color/caption_tint_color_selector"
+ android:layout_gravity="center"
+ android:soundEffectsEnabled="false"
+ sysui:optedOut="false"/>
+
+ </FrameLayout>
+
+ <ViewStub
+ android:id="@+id/odi_captions_tooltip_stub"
+ android:inflatedId="@+id/odi_captions_tooltip_view"
+ android:layout="@layout/volume_tool_tip_view"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_marginRight="@dimen/volume_tool_tip_right_margin"
+ android:layout_marginTop="@dimen/volume_tool_tip_top_margin"
+ android:layout_gravity="right"/>
+
+ </FrameLayout>
+
+</FrameLayout> \ No newline at end of file
diff --git a/packages/SystemUI/res/layout-land-television/volume_dialog_row.xml b/packages/SystemUI/res/layout-land-television/volume_dialog_row.xml
new file mode 100644
index 000000000000..08209ab09169
--- /dev/null
+++ b/packages/SystemUI/res/layout-land-television/volume_dialog_row.xml
@@ -0,0 +1,69 @@
+<!--
+ Copyright (C) 2015 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+<FrameLayout
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ android:tag="row"
+ android:layout_width="@dimen/volume_dialog_row_width"
+ android:layout_height="wrap_content"
+ android:background="@android:color/transparent"
+ android:clipChildren="false"
+ android:clipToPadding="false"
+ android:theme="@style/qs_theme">
+
+ <LinearLayout
+ android:layout_width="wrap_content"
+ android:layout_height="match_parent"
+ android:background="@android:color/transparent"
+ android:gravity="center"
+ android:layout_gravity="center"
+ android:orientation="horizontal" >
+ <com.android.keyguard.AlphaOptimizedImageButton
+ android:id="@+id/volume_row_icon"
+ style="@style/VolumeButtons"
+ android:layout_width="@dimen/volume_dialog_tap_target_size"
+ android:layout_height="@dimen/volume_dialog_tap_target_size"
+ android:background="@drawable/ripple_drawable_20dp"
+ android:tint="@color/accent_tint_color_selector"
+ android:soundEffectsEnabled="false" />
+ <TextView
+ android:id="@+id/volume_row_header"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:ellipsize="end"
+ android:maxLength="10"
+ android:maxLines="1"
+ android:visibility="gone"
+ android:textColor="?android:attr/colorControlNormal"
+ android:textAppearance="@style/TextAppearance.Volume.Header" />
+ <FrameLayout
+ android:id="@+id/volume_row_slider_frame"
+ android:layout_height="match_parent"
+ android:layoutDirection="ltr"
+ android:layout_width="@dimen/volume_dialog_row_width">
+ <SeekBar
+ android:id="@+id/volume_row_slider"
+ android:clickable="false"
+ android:layout_width="@dimen/volume_dialog_row_width"
+ android:layout_height="match_parent"
+ android:layoutDirection="ltr"
+ android:layout_gravity="center"
+ android:rotation="0" />
+ </FrameLayout>
+ </LinearLayout>
+
+ <include layout="@layout/volume_dnd_icon"/>
+
+</FrameLayout>
diff --git a/packages/SystemUI/res/layout/controls_base_item.xml b/packages/SystemUI/res/layout/controls_base_item.xml
index c571b9bbf908..374e3b120e4b 100644
--- a/packages/SystemUI/res/layout/controls_base_item.xml
+++ b/packages/SystemUI/res/layout/controls_base_item.xml
@@ -31,6 +31,7 @@
android:id="@+id/icon"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
+ android:paddingTop="@dimen/control_padding_adjustment"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
@@ -39,6 +40,7 @@
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textAppearance="@style/TextAppearance.Control.Status"
+ android:paddingTop="@dimen/control_padding_adjustment"
android:paddingStart="@dimen/control_status_padding"
app:layout_constraintBottom_toBottomOf="@+id/icon"
app:layout_constraintStart_toEndOf="@+id/icon" />
@@ -48,6 +50,7 @@
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textAppearance="@style/TextAppearance.Control.Status"
+ android:paddingTop="@dimen/control_padding_adjustment"
android:paddingStart="@dimen/control_status_padding"
app:layout_constraintBottom_toBottomOf="@+id/icon"
app:layout_constraintStart_toEndOf="@+id/status" />
@@ -57,15 +60,19 @@
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textAppearance="@style/TextAppearance.Control.Title"
+ android:paddingLeft="@dimen/control_padding_adjustment"
+ android:paddingRight="@dimen/control_padding_adjustment"
app:layout_constraintBottom_toTopOf="@+id/subtitle"
- app:layout_constraintStart_toStartOf="parent"
- app:layout_constraintTop_toBottomOf="@+id/icon"/>
+ app:layout_constraintStart_toStartOf="parent" />
<TextView
android:id="@+id/subtitle"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textAppearance="@style/TextAppearance.Control.Subtitle"
+ android:paddingLeft="@dimen/control_padding_adjustment"
+ android:paddingRight="@dimen/control_padding_adjustment"
+ android:paddingBottom="@dimen/control_padding_adjustment"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintStart_toStartOf="parent"/>
diff --git a/packages/SystemUI/res/layout/controls_dialog.xml b/packages/SystemUI/res/layout/controls_dialog.xml
new file mode 100644
index 000000000000..3effaf5fac5b
--- /dev/null
+++ b/packages/SystemUI/res/layout/controls_dialog.xml
@@ -0,0 +1,34 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Copyright (C) 2020 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+<FrameLayout
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:padding="@dimen/controls_dialog_padding"
+ android:layout_margin="@dimen/controls_dialog_padding"
+ >
+
+ <include
+ android:id="@+id/control"
+ layout="@layout/controls_base_item"
+ android:layout_width="@dimen/controls_dialog_control_width"
+ android:layout_height="@dimen/control_height"
+ android:layout_gravity="center_horizontal"
+ android:layout_marginTop="@dimen/controls_dialog_padding"
+ android:layout_marginBottom="@dimen/controls_dialog_padding"
+ />
+</FrameLayout> \ No newline at end of file
diff --git a/packages/SystemUI/res/layout/controls_dialog_pin.xml b/packages/SystemUI/res/layout/controls_dialog_pin.xml
new file mode 100644
index 000000000000..b77d6fa6a956
--- /dev/null
+++ b/packages/SystemUI/res/layout/controls_dialog_pin.xml
@@ -0,0 +1,36 @@
+<!--
+ ~ Copyright (C) 2020 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ -->
+
+<LinearLayout
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:orientation="vertical"
+ android:paddingLeft="?android:attr/dialogPreferredPadding"
+ android:paddingRight="?android:attr/dialogPreferredPadding">
+ <EditText
+ android:id="@+id/controls_pin_input"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:hint="@string/controls_pin_instructions"
+ android:inputType="numberPassword" />
+ <CheckBox
+ android:id="@+id/controls_pin_use_alpha"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:layout_marginTop="5dp"
+ android:text="@string/controls_pin_use_alphanumeric" />
+</LinearLayout>
diff --git a/packages/SystemUI/res/layout/controls_management.xml b/packages/SystemUI/res/layout/controls_management.xml
index 6533c18a41a9..34a966ceea75 100644
--- a/packages/SystemUI/res/layout/controls_management.xml
+++ b/packages/SystemUI/res/layout/controls_management.xml
@@ -25,13 +25,40 @@
android:paddingStart="@dimen/controls_management_side_padding"
android:paddingEnd="@dimen/controls_management_side_padding" >
- <TextView
- android:id="@+id/title"
+ <LinearLayout
+ android:orientation="horizontal"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
- android:textAppearance="?android:attr/textAppearanceLarge"
- android:textSize="@dimen/controls_title_size"
- android:textAlignment="center" />
+ android:gravity="center_vertical">
+
+ <FrameLayout
+ android:id="@+id/icon_frame"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:gravity="start|center_vertical"
+ android:minWidth="56dp"
+ android:visibility="gone"
+ android:paddingTop="@dimen/controls_app_icon_frame_top_padding"
+ android:paddingBottom="@dimen/controls_app_icon_frame_bottom_padding"
+ android:paddingEnd="@dimen/controls_app_icon_frame_side_padding"
+ android:paddingStart="@dimen/controls_app_icon_frame_side_padding" >
+
+ <ImageView
+ android:id="@android:id/icon"
+ android:layout_width="@dimen/controls_app_icon_size"
+ android:layout_height="@dimen/controls_app_icon_size" />
+ </FrameLayout>
+
+ <TextView
+ android:id="@+id/title"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:textAppearance="?android:attr/textAppearanceLarge"
+ android:textSize="@dimen/controls_title_size"
+ android:textAlignment="center" />
+
+ </LinearLayout>
+
<TextView
android:id="@+id/subtitle"
@@ -41,19 +68,11 @@
android:textAppearance="?android:attr/textAppearanceSmall"
android:textAlignment="center" />
- <androidx.core.widget.NestedScrollView
+ <ViewStub
+ android:id="@+id/stub"
android:layout_width="match_parent"
android:layout_height="0dp"
- android:layout_weight="1"
- android:orientation="vertical"
- android:layout_marginTop="@dimen/controls_management_list_margin">
-
- <ViewStub
- android:id="@+id/stub"
- android:layout_width="match_parent"
- android:layout_height="match_parent"/>
-
- </androidx.core.widget.NestedScrollView>
+ android:layout_weight="1"/>
<FrameLayout
android:layout_width="match_parent"
diff --git a/packages/SystemUI/res/layout/controls_management_apps.xml b/packages/SystemUI/res/layout/controls_management_apps.xml
index 2bab433d21f3..42d73f3cc9ce 100644
--- a/packages/SystemUI/res/layout/controls_management_apps.xml
+++ b/packages/SystemUI/res/layout/controls_management_apps.xml
@@ -14,12 +14,18 @@
~ See the License for the specific language governing permissions and
~ limitations under the License.
-->
-
-<androidx.recyclerview.widget.RecyclerView
+<androidx.core.widget.NestedScrollView
xmlns:android="http://schemas.android.com/apk/res/android"
- android:id="@+id/list"
android:layout_width="match_parent"
- android:layout_height="match_parent"
- >
+ android:layout_height="0dp"
+ android:layout_weight="1"
+ android:orientation="vertical"
+ android:layout_marginTop="@dimen/controls_management_list_margin">
+
+ <androidx.recyclerview.widget.RecyclerView
+ android:id="@+id/list"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ />
-</androidx.recyclerview.widget.RecyclerView> \ No newline at end of file
+</androidx.core.widget.NestedScrollView>
diff --git a/packages/SystemUI/res/layout/controls_management_favorites.xml b/packages/SystemUI/res/layout/controls_management_favorites.xml
index aab32f45e77a..d2ccfcb11c5c 100644
--- a/packages/SystemUI/res/layout/controls_management_favorites.xml
+++ b/packages/SystemUI/res/layout/controls_management_favorites.xml
@@ -17,7 +17,7 @@
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
- android:layout_height="match_parent"
+ android:layout_height="0dp"
android:orientation="vertical">
<TextView
@@ -29,11 +29,17 @@
android:gravity="center_horizontal"
/>
- <androidx.recyclerview.widget.RecyclerView
- android:id="@+id/listAll"
- android:layout_width="match_parent"
+ <com.android.systemui.controls.management.ManagementPageIndicator
+ android:id="@+id/structure_page_indicator"
+ android:layout_width="wrap_content"
android:layout_height="match_parent"
+ android:layout_gravity="center"
android:layout_marginTop="@dimen/controls_management_list_margin"
- android:nestedScrollingEnabled="false"/>
+ android:visibility="gone" />
+
+ <androidx.viewpager2.widget.ViewPager2
+ android:id="@+id/structure_pager"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"/>
</LinearLayout> \ No newline at end of file
diff --git a/packages/SystemUI/res/layout/controls_no_favorites.xml b/packages/SystemUI/res/layout/controls_no_favorites.xml
index 3e0699dff197..8074efd18492 100644
--- a/packages/SystemUI/res/layout/controls_no_favorites.xml
+++ b/packages/SystemUI/res/layout/controls_no_favorites.xml
@@ -28,6 +28,7 @@
android:paddingBottom="40dp"
android:layout_marginLeft="10dp"
android:layout_marginRight="10dp"
+ android:layout_marginTop="@dimen/controls_top_margin"
android:background="@drawable/control_no_favorites_background">
<LinearLayout
diff --git a/packages/SystemUI/res/layout/controls_spinner_item.xml b/packages/SystemUI/res/layout/controls_spinner_item.xml
index 6b880545b296..44ae3b12e123 100644
--- a/packages/SystemUI/res/layout/controls_spinner_item.xml
+++ b/packages/SystemUI/res/layout/controls_spinner_item.xml
@@ -15,36 +15,29 @@
-->
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
- android:orientation="horizontal"
android:layout_width="match_parent"
android:layout_height="wrap_content"
- android:paddingTop="12dp"
- android:paddingBottom="12dp">
+ android:padding="4dp">
+
+ <LinearLayout
+ android:orientation="horizontal"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:gravity="center">
- <Space
- android:layout_weight="1"
- android:layout_width="0dp"
- android:layout_height="1dp" />
<ImageView
android:id="@+id/app_icon"
android:layout_gravity="center"
- android:layout_width="34dp"
- android:layout_height="24dp"
+ android:layout_width="@dimen/controls_header_app_icon_size"
+ android:layout_height="@dimen/controls_header_app_icon_size"
android:layout_marginEnd="10dp" />
<TextView
+ style="@style/Control.Spinner.Item"
android:id="@+id/controls_spinner_item"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
- android:singleLine="true"
- android:layout_gravity="center"
- android:textSize="25sp"
- android:textColor="@color/control_secondary_text"
- android:fontFamily="@*android:string/config_headlineFontFamily" />
+ android:layout_gravity="center" />
+ </LinearLayout>
- <Space
- android:layout_weight="1"
- android:layout_width="0dp"
- android:layout_height="1dp" />
</LinearLayout>
-
diff --git a/packages/SystemUI/res/layout/controls_structure_page.xml b/packages/SystemUI/res/layout/controls_structure_page.xml
new file mode 100644
index 000000000000..2c7e1681f2e1
--- /dev/null
+++ b/packages/SystemUI/res/layout/controls_structure_page.xml
@@ -0,0 +1,31 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ ~ Copyright (C) 2020 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ -->
+
+<androidx.core.widget.NestedScrollView
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:orientation="vertical"
+ android:layout_marginTop="@dimen/controls_management_list_margin">
+
+ <androidx.recyclerview.widget.RecyclerView
+ android:id="@+id/listAll"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ />
+
+</androidx.core.widget.NestedScrollView> \ No newline at end of file
diff --git a/packages/SystemUI/res/layout/controls_with_favorites.xml b/packages/SystemUI/res/layout/controls_with_favorites.xml
index 77bcc3575fad..d3de4cdb42ba 100644
--- a/packages/SystemUI/res/layout/controls_with_favorites.xml
+++ b/packages/SystemUI/res/layout/controls_with_favorites.xml
@@ -14,47 +14,51 @@
~ limitations under the License.
-->
<merge
- xmlns:android="http://schemas.android.com/apk/res/android">
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:app="http://schemas.android.com/apk/res-auto">
- <LinearLayout
- android:id="@+id/controls_header"
- android:orientation="horizontal"
+ <androidx.constraintlayout.widget.ConstraintLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
- android:paddingTop="12dp">
+ android:layout_marginTop="@dimen/controls_top_margin">
- <Space
- android:layout_weight="1"
- android:layout_width="0dp"
- android:layout_height="1dp" />
+ <LinearLayout
+ android:id="@+id/controls_header"
+ android:orientation="horizontal"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:layout_marginStart="@dimen/controls_header_side_margin"
+ android:layout_marginEnd="@dimen/controls_header_side_margin"
+ android:gravity="center"
+ app:layout_constraintBottom_toBottomOf="parent"
+ app:layout_constraintEnd_toEndOf="parent"
+ app:layout_constraintStart_toStartOf="parent"
+ app:layout_constraintTop_toTopOf="parent" >
- <ImageView
- android:id="@+id/app_icon"
- android:layout_gravity="center"
- android:layout_width="24dp"
- android:layout_height="24dp"
- android:layout_marginEnd="10dp" />
+ <ImageView
+ android:id="@+id/app_icon"
+ android:layout_gravity="center"
+ android:layout_width="@dimen/controls_header_app_icon_size"
+ android:layout_height="@dimen/controls_header_app_icon_size"
+ android:layout_marginEnd="10dp" />
- <TextView
- style="@style/Control.Spinner.Header"
- android:clickable="false"
- android:id="@+id/app_or_structure_spinner"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:singleLine="true"
- android:layout_gravity="center"
- android:ellipsize="end" />
+ <TextView
+ style="@style/Control.Spinner.Header"
+ android:clickable="false"
+ android:id="@+id/app_or_structure_spinner"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_gravity="center" />
+ </LinearLayout>
- <Space
- android:layout_weight="1"
- android:layout_width="0dp"
- android:layout_height="1dp" />
- </LinearLayout>
+ </androidx.constraintlayout.widget.ConstraintLayout>
<LinearLayout
android:id="@+id/global_actions_controls_list"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical"
- android:paddingTop="20dp" />
+ android:paddingTop="30dp"
+ android:layout_marginLeft="@dimen/controls_list_side_margin"
+ android:layout_marginRight="@dimen/controls_list_side_margin" />
</merge>
diff --git a/packages/SystemUI/res/layout/global_actions_grid_v2.xml b/packages/SystemUI/res/layout/global_actions_grid_v2.xml
index 4fe21e5bc0ac..92ae1b95264f 100644
--- a/packages/SystemUI/res/layout/global_actions_grid_v2.xml
+++ b/packages/SystemUI/res/layout/global_actions_grid_v2.xml
@@ -1,73 +1,75 @@
<?xml version="1.0" encoding="utf-8"?>
-<ScrollView
+<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:app="http://schemas.android.com/apk/res-auto"
android:id="@+id/global_actions_container"
android:layout_width="match_parent"
- android:layout_height="match_parent">
-
- <androidx.constraintlayout.widget.ConstraintLayout
- android:id="@+id/global_actions_grid_root"
+ android:layout_height="match_parent"
+ android:orientation="vertical"
+>
+ <com.android.systemui.globalactions.GlobalActionsFlatLayout
+ android:id="@id/global_actions_view"
android:layout_width="match_parent"
- android:layout_height="match_parent"
+ android:layout_height="wrap_content"
+ android:orientation="horizontal"
+ android:theme="@style/qs_theme"
+ android:gravity="top | center_horizontal"
android:clipChildren="false"
android:clipToPadding="false"
- android:paddingBottom="@dimen/global_actions_grid_container_shadow_offset"
- android:layout_marginBottom="@dimen/global_actions_grid_container_negative_shadow_offset">
-
- <com.android.systemui.globalactions.GlobalActionsFlatLayout
- android:id="@id/global_actions_view"
- android:layout_width="match_parent"
+ android:layout_marginTop="@dimen/global_actions_top_margin"
+ >
+ <LinearLayout
+ android:id="@android:id/list"
+ android:layout_width="wrap_content"
android:layout_height="wrap_content"
+ android:layout_marginLeft="@dimen/global_actions_grid_side_margin"
+ android:layout_marginRight="@dimen/global_actions_grid_side_margin"
+ android:paddingLeft="@dimen/global_actions_grid_horizontal_padding"
+ android:paddingRight="@dimen/global_actions_grid_horizontal_padding"
+ android:paddingTop="@dimen/global_actions_grid_vertical_padding"
+ android:paddingBottom="@dimen/global_actions_grid_vertical_padding"
android:orientation="horizontal"
- android:theme="@style/qs_theme"
- app:layout_constraintTop_toTopOf="parent"
- app:layout_constraintLeft_toLeftOf="parent"
- app:layout_constraintRight_toRightOf="parent"
- android:gravity="top | center_horizontal"
- android:clipChildren="false"
- android:clipToPadding="false"
- android:layout_marginTop="@dimen/global_actions_top_margin">
- <LinearLayout
- android:id="@android:id/list"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:layout_marginLeft="@dimen/global_actions_grid_side_margin"
- android:layout_marginRight="@dimen/global_actions_grid_side_margin"
- android:paddingLeft="@dimen/global_actions_grid_horizontal_padding"
- android:paddingRight="@dimen/global_actions_grid_horizontal_padding"
- android:paddingTop="@dimen/global_actions_grid_vertical_padding"
- android:paddingBottom="@dimen/global_actions_grid_vertical_padding"
- android:orientation="horizontal"
- android:gravity="left"
- android:translationZ="@dimen/global_actions_translate" />
- </com.android.systemui.globalactions.GlobalActionsFlatLayout>
+ android:gravity="left"
+ android:translationZ="@dimen/global_actions_translate"
+ />
+ </com.android.systemui.globalactions.GlobalActionsFlatLayout>
+ <com.android.systemui.globalactions.MinHeightScrollView
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:paddingBottom="@dimen/global_actions_grid_container_shadow_offset"
+ android:layout_marginBottom="@dimen/global_actions_grid_container_negative_shadow_offset"
+ android:orientation="vertical"
+ >
<LinearLayout
- android:id="@+id/global_actions_panel"
+ android:id="@+id/global_actions_grid_root"
android:layout_width="match_parent"
android:layout_height="wrap_content"
+ android:clipChildren="false"
android:orientation="vertical"
- app:layout_constraintLeft_toLeftOf="parent"
- app:layout_constraintRight_toRightOf="parent"
- app:layout_constraintTop_toBottomOf="@id/global_actions_view">
+ android:clipToPadding="false"
+ >
+ <LinearLayout
+ android:id="@+id/global_actions_panel"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:orientation="vertical"
+ >
+ <FrameLayout
+ android:id="@+id/global_actions_panel_container"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ />
+ </LinearLayout>
- <FrameLayout
- android:id="@+id/global_actions_panel_container"
+ <LinearLayout
+ android:id="@+id/global_actions_controls"
android:layout_width="match_parent"
- android:layout_height="wrap_content" />
+ android:layout_height="wrap_content"
+ android:orientation="vertical"
+ android:layout_marginRight="@dimen/global_actions_grid_horizontal_padding"
+ android:layout_marginLeft="@dimen/global_actions_grid_horizontal_padding"
+ />
</LinearLayout>
-
- <LinearLayout
- android:id="@+id/global_actions_controls"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:orientation="vertical"
- android:layout_marginRight="@dimen/global_actions_grid_horizontal_padding"
- android:layout_marginLeft="@dimen/global_actions_grid_horizontal_padding"
- app:layout_constraintLeft_toLeftOf="parent"
- app:layout_constraintRight_toRightOf="parent"
- app:layout_constraintTop_toBottomOf="@id/global_actions_panel"
- app:layout_constraintBottom_toBottomOf="parent" />
- </androidx.constraintlayout.widget.ConstraintLayout>
-</ScrollView>
+ </com.android.systemui.globalactions.MinHeightScrollView>
+</LinearLayout> \ No newline at end of file
diff --git a/packages/SystemUI/res/layout/global_actions_wrapped.xml b/packages/SystemUI/res/layout/global_actions_wrapped.xml
deleted file mode 100644
index d4410702a7d1..000000000000
--- a/packages/SystemUI/res/layout/global_actions_wrapped.xml
+++ /dev/null
@@ -1,38 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<com.android.systemui.HardwareUiLayout
- xmlns:android="http://schemas.android.com/apk/res/android"
- android:id="@id/global_actions_view"
- android:layout_width="match_parent"
- android:layout_height="match_parent"
- android:layout_gravity="top|right"
- android:layout_marginBottom="0dp"
- android:orientation="vertical"
- android:paddingTop="@dimen/global_actions_top_padding"
- android:clipToPadding="false"
- android:theme="@style/qs_theme"
- android:clipChildren="false">
-
- <!-- Global actions is right-aligned to be physically near power button -->
- <LinearLayout
- android:id="@android:id/list"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:layout_gravity="top|right"
- android:gravity="center"
- android:orientation="vertical"
- android:padding="@dimen/global_actions_padding"
- android:translationZ="@dimen/global_actions_translate" />
-
- <!-- For separated button-->
- <FrameLayout
- android:id="@+id/separated_button"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:layout_gravity="top|right"
- android:layout_marginTop="6dp"
- android:gravity="center"
- android:orientation="vertical"
- android:padding="@dimen/global_actions_padding"
- android:translationZ="@dimen/global_actions_translate" />
-
-</com.android.systemui.HardwareUiLayout>
diff --git a/packages/SystemUI/res/layout/notification_conversation_info.xml b/packages/SystemUI/res/layout/notification_conversation_info.xml
index 84606126086d..6a7f9e2620db 100644
--- a/packages/SystemUI/res/layout/notification_conversation_info.xml
+++ b/packages/SystemUI/res/layout/notification_conversation_info.xml
@@ -121,7 +121,6 @@
android:layout_marginEnd="2dp"
android:ellipsize="end"
android:text="@string/notification_delegate_header"
- android:layout_toEndOf="@id/pkg_divider"
android:maxLines="1" />
</LinearLayout>
diff --git a/packages/SystemUI/res/layout/notification_info.xml b/packages/SystemUI/res/layout/notification_info.xml
index 5d03eee11f75..6ab573bbfba7 100644
--- a/packages/SystemUI/res/layout/notification_info.xml
+++ b/packages/SystemUI/res/layout/notification_info.xml
@@ -27,51 +27,81 @@
android:paddingStart="@*android:dimen/notification_content_margin_start">
<!-- Package Info -->
- <RelativeLayout
+ <LinearLayout
android:id="@+id/header"
android:layout_width="match_parent"
- android:layout_height="wrap_content"
+ android:layout_height="@dimen/notification_guts_conversation_header_height"
+ android:gravity="center_vertical"
android:clipChildren="false"
android:clipToPadding="false">
<ImageView
- android:id="@+id/pkgicon"
- android:layout_width="@dimen/notification_guts_header_height"
- android:layout_height="@dimen/notification_guts_header_height"
+ android:id="@+id/pkg_icon"
+ android:layout_width="@dimen/notification_guts_conversation_icon_size"
+ android:layout_height="@dimen/notification_guts_conversation_icon_size"
android:layout_centerVertical="true"
android:layout_alignParentStart="true"
- android:layout_marginEnd="3dp" />
- <TextView
- android:id="@+id/pkgname"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:layout_centerVertical="true"
- style="@style/TextAppearance.NotificationImportanceHeader"
- android:layout_marginStart="3dp"
- android:layout_marginEnd="2dp"
- android:layout_toEndOf="@id/pkgicon"
- android:singleLine="true" />
- <TextView
- android:id="@+id/pkg_divider"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:layout_centerVertical="true"
- style="@style/TextAppearance.NotificationImportanceHeader"
- android:layout_marginStart="2dp"
- android:layout_marginEnd="2dp"
- android:layout_toEndOf="@id/pkgname"
- android:text="@*android:string/notification_header_divider_symbol" />
- <TextView
- android:id="@+id/delegate_name"
- android:layout_width="wrap_content"
+ android:layout_marginEnd="15dp" />
+ <LinearLayout
+ android:id="@+id/names"
+ android:layout_weight="1"
+ android:layout_width="0dp"
+ android:orientation="vertical"
+
android:layout_height="wrap_content"
+ android:minHeight="@dimen/notification_guts_conversation_icon_size"
android:layout_centerVertical="true"
- style="@style/TextAppearance.NotificationImportanceHeader"
- android:layout_marginStart="2dp"
- android:layout_marginEnd="2dp"
- android:ellipsize="end"
- android:text="@string/notification_delegate_header"
- android:layout_toEndOf="@id/pkg_divider"
- android:maxLines="1" />
+ android:gravity="center_vertical"
+ android:layout_alignEnd="@id/pkg_icon"
+ android:layout_toEndOf="@id/pkg_icon"
+ android:layout_alignStart="@id/mute">
+ <TextView
+ android:id="@+id/channel_name"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ style="@style/TextAppearance.NotificationImportanceChannel"/>
+ <LinearLayout
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:gravity="start"
+ android:orientation="horizontal">
+ <TextView
+ android:id="@+id/pkg_name"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ style="@style/TextAppearance.NotificationImportanceChannelGroup"
+ android:ellipsize="end"
+ android:maxLines="1"/>
+ <TextView
+ android:id="@+id/group_divider"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_centerVertical="true"
+ style="@style/TextAppearance.NotificationImportanceHeader"
+ android:layout_marginStart="2dp"
+ android:layout_marginEnd="2dp"
+ android:text="@*android:string/notification_header_divider_symbol" />
+ <TextView
+ android:id="@+id/group_name"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_weight="1"
+ style="@style/TextAppearance.NotificationImportanceChannel"/>
+ </LinearLayout>
+ <TextView
+ android:id="@+id/delegate_name"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:layout_centerVertical="true"
+ style="@style/TextAppearance.NotificationImportanceHeader"
+ android:layout_marginStart="2dp"
+ android:layout_marginEnd="2dp"
+ android:ellipsize="end"
+ android:text="@string/notification_delegate_header"
+ android:maxLines="1" />
+
+ </LinearLayout>
+
+ <!-- end aligned fields -->
<!-- Optional link to app. Only appears if the channel is not disabled and the app
asked for it -->
<ImageButton
@@ -95,91 +125,6 @@ asked for it -->
android:src="@drawable/ic_settings"
android:layout_alignParentEnd="true"
android:tint="@color/notification_guts_link_icon_tint"/>
- </RelativeLayout>
-
- <!-- Channel Info Block -->
- <LinearLayout
- android:id="@+id/channel_info"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:paddingEnd="@*android:dimen/notification_content_margin_end"
- android:gravity="center"
- android:orientation="vertical">
- <!-- Channel Name -->
- <TextView
- android:id="@+id/channel_name"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:layout_weight="1"
- style="@style/TextAppearance.NotificationImportanceChannel"/>
- <TextView
- android:id="@+id/group_name"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- style="@style/TextAppearance.NotificationImportanceChannelGroup"
- android:ellipsize="end"
- android:maxLines="1"/>
- </LinearLayout>
-
- <LinearLayout
- android:id="@+id/blocking_helper"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:layout_marginTop="@dimen/notification_guts_button_spacing"
- android:layout_marginBottom="@dimen/notification_guts_button_spacing"
- android:paddingEnd="@*android:dimen/notification_content_margin_end"
- android:clipChildren="false"
- android:clipToPadding="false"
- android:orientation="vertical">
- <!-- blocking helper text. no need for non-configurable check b/c controls won't be
- activated in that case -->
- <TextView
- android:id="@+id/blocking_helper_text"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:layout_marginTop="2dp"
- android:text="@string/inline_blocking_helper"
- style="@*android:style/TextAppearance.DeviceDefault.Notification" />
- <RelativeLayout
- android:id="@+id/block_buttons"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:layout_marginTop="@dimen/notification_guts_button_spacing">
- <TextView
- android:id="@+id/blocking_helper_turn_off_notifications"
- android:text="@string/inline_turn_off_notifications"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:layout_centerVertical="true"
- android:layout_alignParentStart="true"
- android:width="110dp"
- android:paddingEnd="15dp"
- android:breakStrategy="simple"
- style="@style/TextAppearance.NotificationInfo.Button"/>
- <TextView
- android:id="@+id/deliver_silently"
- android:text="@string/inline_deliver_silently_button"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:layout_centerVertical="true"
- android:layout_marginStart="@dimen/notification_guts_button_horizontal_spacing"
- android:paddingEnd="15dp"
- android:width="110dp"
- android:breakStrategy="simple"
- android:layout_toStartOf="@+id/keep_showing"
- style="@style/TextAppearance.NotificationInfo.Button"/>
- <TextView
- android:id="@+id/keep_showing"
- android:text="@string/inline_keep_button"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:layout_centerVertical="true"
- android:layout_marginStart="@dimen/notification_guts_button_horizontal_spacing"
- android:width="110dp"
- android:breakStrategy="simple"
- android:layout_alignParentEnd="true"
- style="@style/TextAppearance.NotificationInfo.Button"/>
- </RelativeLayout>
</LinearLayout>
@@ -357,34 +302,4 @@ asked for it -->
</RelativeLayout>
</LinearLayout>
-
- <com.android.systemui.statusbar.notification.row.NotificationUndoLayout
- android:id="@+id/confirmation"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:visibility="gone"
- android:orientation="horizontal" >
- <TextView
- android:id="@+id/confirmation_text"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:layout_gravity="start|center_vertical"
- android:layout_marginStart="@*android:dimen/notification_content_margin_start"
- android:layout_marginEnd="@*android:dimen/notification_content_margin_start"
- android:text="@string/notification_channel_disabled"
- style="@style/TextAppearance.NotificationInfo.Confirmation"/>
- <TextView
- android:id="@+id/undo"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:minWidth="@dimen/notification_importance_toggle_size"
- android:minHeight="@dimen/notification_importance_toggle_size"
- android:layout_marginTop="@dimen/notification_guts_button_spacing"
- android:layout_marginBottom="@dimen/notification_guts_button_spacing"
- android:layout_marginStart="@dimen/notification_guts_button_side_margin"
- android:layout_marginEnd="@dimen/notification_guts_button_side_margin"
- android:layout_gravity="end|center_vertical"
- android:text="@string/inline_undo"
- style="@style/TextAppearance.NotificationInfo.Button"/>
- </com.android.systemui.statusbar.notification.row.NotificationUndoLayout>
</com.android.systemui.statusbar.notification.row.NotificationInfo>
diff --git a/packages/SystemUI/res/layout/qs_media_panel.xml b/packages/SystemUI/res/layout/qs_media_panel.xml
index 22303dc1d8d2..34bd7035b5ae 100644
--- a/packages/SystemUI/res/layout/qs_media_panel.xml
+++ b/packages/SystemUI/res/layout/qs_media_panel.xml
@@ -32,7 +32,6 @@
android:orientation="horizontal"
android:layout_width="match_parent"
android:layout_height="wrap_content"
- android:id="@+id/header"
android:layout_marginBottom="16dp"
>
@@ -73,7 +72,7 @@
<!-- Song name -->
<TextView
- android:id="@+id/header_text"
+ android:id="@+id/header_title"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:singleLine="true"
diff --git a/packages/SystemUI/res/values-af/strings.xml b/packages/SystemUI/res/values-af/strings.xml
index 02104f5548af..9ba891d982fe 100644
--- a/packages/SystemUI/res/values-af/strings.xml
+++ b/packages/SystemUI/res/values-af/strings.xml
@@ -558,6 +558,7 @@
<string name="monitoring_description_app_personal_work" msgid="6175816356939166101">"<xliff:g id="ORGANIZATION">%1$s</xliff:g> bestuur jou werkprofiel. Die profiel is gekoppel aan <xliff:g id="APPLICATION_WORK">%2$s</xliff:g>, wat jou netwerkaktiwiteit, insluitend e-posse, programme en webwerwe, kan monitor.\n\nJy is ook gekoppel aan <xliff:g id="APPLICATION_PERSONAL">%3$s</xliff:g>, wat jou persoonlike netwerkaktiwiteit kan monitor."</string>
<string name="keyguard_indication_trust_unlocked" msgid="7395154975733744547">"Ontsluit gehou deur TrustAgent"</string>
<string name="keyguard_indication_trust_disabled" msgid="6820793704816727918">"Toestel sal gesluit bly totdat jy dit handmatig ontsluit"</string>
+ <string name="keyguard_indication_trust_unlocked_plugged_in" msgid="2323452175329362855">"<xliff:g id="KEYGUARD_INDICATION">%1$s</xliff:g>\n<xliff:g id="POWER_INDICATION">%2$s</xliff:g>"</string>
<string name="hidden_notifications_title" msgid="1782412844777612795">"Kry kennisgewings vinniger"</string>
<string name="hidden_notifications_text" msgid="5899627470450792578">"Sien hulle voordat jy ontsluit"</string>
<string name="hidden_notifications_cancel" msgid="4805370226181001278">"Nee, dankie"</string>
@@ -979,12 +980,9 @@
<string name="bubble_accessibility_action_move_bottom_left" msgid="6339015902495504715">"Beweeg na links onder"</string>
<string name="bubble_accessibility_action_move_bottom_right" msgid="7471571700628346212">"Beweeg na regs onder"</string>
<string name="bubble_dismiss_text" msgid="7071770411580452911">"Maak toe"</string>
- <!-- no translation found for bubbles_user_education_title (3385222165904578710) -->
- <skip />
- <!-- no translation found for bubbles_user_education_description (6663205638091146934) -->
- <skip />
- <!-- no translation found for bubbles_user_education_manage (1391639189507036423) -->
- <skip />
+ <string name="bubbles_user_education_title" msgid="3385222165904578710">"Hou kletse prominent"</string>
+ <string name="bubbles_user_education_description" msgid="6663205638091146934">"Nuwe kletse van <xliff:g id="APP_NAME">%1$s</xliff:g> af sal as borrels verskyn. Tik op \'n borrel om dit oop te maak. Sleep om dit te skuif.\n\nTik op die borrel"</string>
+ <string name="bubbles_user_education_manage" msgid="1391639189507036423">"Tik op Bestuur om borrels vanaf hierdie program af te skakel"</string>
<string name="notification_content_system_nav_changed" msgid="5077913144844684544">"Stelselnavigasie is opgedateer. Gaan na Instellings toe om veranderinge te maak."</string>
<string name="notification_content_gesture_nav_available" msgid="4431460803004659888">"Gaan na Instellings toe om stelselnavigasie op te dateer"</string>
<string name="inattentive_sleep_warning_title" msgid="3891371591713990373">"Bystandmodus"</string>
@@ -1004,4 +1002,10 @@
<string name="controls_favorite_header_all" msgid="7507855973418969992">"Almal"</string>
<string name="controls_favorite_load_error" msgid="2533215155804455348">"Die lys met alle kontroles kon nie gelaai word nie."</string>
<string name="controls_favorite_other_zone_header" msgid="9089613266575525252">"Ander"</string>
+ <!-- no translation found for controls_dialog_title (8806193219278278442) -->
+ <skip />
+ <!-- no translation found for controls_dialog_ok (7011816381344485651) -->
+ <skip />
+ <!-- no translation found for controls_dialog_message (6292099631702047540) -->
+ <skip />
</resources>
diff --git a/packages/SystemUI/res/values-am/strings.xml b/packages/SystemUI/res/values-am/strings.xml
index 22df5190c9da..a73d48d17131 100644
--- a/packages/SystemUI/res/values-am/strings.xml
+++ b/packages/SystemUI/res/values-am/strings.xml
@@ -558,6 +558,7 @@
<string name="monitoring_description_app_personal_work" msgid="6175816356939166101">"የእርስዎ የሥራ መገለጫ በ<xliff:g id="ORGANIZATION">%1$s</xliff:g> የሚተዳደር ነው። መገለጫው ኢሜይሎችን፣ መተግበሪያዎችን፣ እና የድር ጣቢያዎችን ጨምሮ የአውታረ መረብ እንቅስቃሴን መቆጣጠር ከሚችለው ከ<xliff:g id="APPLICATION_WORK">%2$s</xliff:g> ጋር ተገናኝቷል።\n\nበተጨማሪ የእርስዎን የግል የአውታረ መረብ እንቅስቃሴ መቆጣጠር ከሚችለው ከ<xliff:g id="APPLICATION_PERSONAL">%3$s</xliff:g> ጋር ተገናኝተዋል።"</string>
<string name="keyguard_indication_trust_unlocked" msgid="7395154975733744547">"በ TrustAgent እንደተከፈተ ቀርቷል"</string>
<string name="keyguard_indication_trust_disabled" msgid="6820793704816727918">"እራስዎ እስኪከፍቱት ድረስ መሣሪያ እንደተቆለፈ ይቆያል"</string>
+ <string name="keyguard_indication_trust_unlocked_plugged_in" msgid="2323452175329362855">"<xliff:g id="KEYGUARD_INDICATION">%1$s</xliff:g>\n<xliff:g id="POWER_INDICATION">%2$s</xliff:g>"</string>
<string name="hidden_notifications_title" msgid="1782412844777612795">"ማሳወቂያዎችን ፈጥነው ያግኙ"</string>
<string name="hidden_notifications_text" msgid="5899627470450792578">"ከመክፈትዎ በፊት ይመልከቷቸው"</string>
<string name="hidden_notifications_cancel" msgid="4805370226181001278">"አይ፣ አመሰግናለሁ"</string>
@@ -979,12 +980,9 @@
<string name="bubble_accessibility_action_move_bottom_left" msgid="6339015902495504715">"የግርጌውን ግራ አንቀሳቅስ"</string>
<string name="bubble_accessibility_action_move_bottom_right" msgid="7471571700628346212">"ታችኛውን ቀኝ ያንቀሳቅሱ"</string>
<string name="bubble_dismiss_text" msgid="7071770411580452911">"አሰናብት"</string>
- <!-- no translation found for bubbles_user_education_title (3385222165904578710) -->
- <skip />
- <!-- no translation found for bubbles_user_education_description (6663205638091146934) -->
- <skip />
- <!-- no translation found for bubbles_user_education_manage (1391639189507036423) -->
- <skip />
+ <string name="bubbles_user_education_title" msgid="3385222165904578710">"ውይይቶችን ከፊት ያድርጓቸው"</string>
+ <string name="bubbles_user_education_description" msgid="6663205638091146934">"ከ<xliff:g id="APP_NAME">%1$s</xliff:g> የመጡ አዲስ ውይይቶች እንደ አረፋዎች ሆነው ይታያሉ። አንድ አረፋን ለመክፈት መታ ያድርጉት። እሱን ለማንቀሳቀስ ይጎትቱት።\n\nአረፋውን መታ ያድርጉት"</string>
+ <string name="bubbles_user_education_manage" msgid="1391639189507036423">"የዚህ መተግበሪያ አረፋዎችን ለማጥፋት አቀናብርን መታ ያድርጉ"</string>
<string name="notification_content_system_nav_changed" msgid="5077913144844684544">"የስርዓት ዳሰሳ ተዘምኗል። ለውጦችን ለማድረግ ወደ ቅንብሮች ይሂዱ።"</string>
<string name="notification_content_gesture_nav_available" msgid="4431460803004659888">"የስርዓት ዳሰሳን ለማዘመን ወደ ቅንብሮች ይሂዱ"</string>
<string name="inattentive_sleep_warning_title" msgid="3891371591713990373">"ተጠባባቂ"</string>
@@ -1004,4 +1002,10 @@
<string name="controls_favorite_header_all" msgid="7507855973418969992">"ሁሉም"</string>
<string name="controls_favorite_load_error" msgid="2533215155804455348">"የሁሉም መቆጣጠሪያዎች ዝርዝር ሊጫን አልተቻለም።"</string>
<string name="controls_favorite_other_zone_header" msgid="9089613266575525252">"ሌላ"</string>
+ <!-- no translation found for controls_dialog_title (8806193219278278442) -->
+ <skip />
+ <!-- no translation found for controls_dialog_ok (7011816381344485651) -->
+ <skip />
+ <!-- no translation found for controls_dialog_message (6292099631702047540) -->
+ <skip />
</resources>
diff --git a/packages/SystemUI/res/values-ar/strings.xml b/packages/SystemUI/res/values-ar/strings.xml
index ee0c65fe8900..37f6911a0a94 100644
--- a/packages/SystemUI/res/values-ar/strings.xml
+++ b/packages/SystemUI/res/values-ar/strings.xml
@@ -62,7 +62,7 @@
<string name="usb_debugging_always" msgid="4003121804294739548">"السماح دائمًا من هذا الكمبيوتر"</string>
<string name="usb_debugging_allow" msgid="1722643858015321328">"سماح"</string>
<string name="usb_debugging_secondary_user_title" msgid="7843050591380107998">"‏لا يُسمح بتصحيح أخطاء USB"</string>
- <string name="usb_debugging_secondary_user_message" msgid="3740347841470403244">"‏لا يمكن للمستخدم الذي يسجّل دخوله حاليًا إلى هذا الجهاز تشغيل تصحيح أخطاء USB. لاستخدام هذه الميزة، يمكنك التبديل إلى المستخدم الأساسي."</string>
+ <string name="usb_debugging_secondary_user_message" msgid="3740347841470403244">"‏لا يمكن للمستخدم الذي يسجّل دخوله حاليًا إلى هذا الجهاز تفعيل تصحيح الأخطاء USB. لاستخدام هذه الميزة، يمكنك التبديل إلى المستخدم الأساسي."</string>
<string name="wifi_debugging_title" msgid="7300007687492186076">"‏هل تريد السماح باستخدام ميزة \"تصحيح الأخطاء عبر شبكة Wi-Fi\" على هذه الشبكة؟"</string>
<string name="wifi_debugging_message" msgid="5461204211731802995">"‏اسم الشبكة (SSID)\n<xliff:g id="SSID_0">%1$s</xliff:g>\n\nعنوان شبكة Wi‑Fi (BSSID)\n<xliff:g id="BSSID_1">%2$s</xliff:g>"</string>
<string name="wifi_debugging_always" msgid="2968383799517975155">"السماح باستخدام هذه الميزة على هذه الشبكة دائمًا"</string>
@@ -570,12 +570,13 @@
<string name="monitoring_description_app_personal_work" msgid="6175816356939166101">"يخضع الملف الشخصي للعمل لإدارة <xliff:g id="ORGANIZATION">%1$s</xliff:g>. تم ربط هذا الملف الشخصي بـ <xliff:g id="APPLICATION_WORK">%2$s</xliff:g>، الذي يمكنه مراقبة أنشطة شبكتك، بما في ذلك الرسائل الإلكترونية والتطبيقات ومواقع الويب.\n\nتم ربطك بـ <xliff:g id="APPLICATION_PERSONAL">%3$s</xliff:g>، الذي يمكنه مراقبة أنشطة شبكتك الشخصية."</string>
<string name="keyguard_indication_trust_unlocked" msgid="7395154975733744547">"‏فتح القفل باستمرار بواسطة TrustAgent"</string>
<string name="keyguard_indication_trust_disabled" msgid="6820793704816727918">"سيظل الجهاز مقفلاً إلى أن يتم فتح قفله يدويًا"</string>
+ <string name="keyguard_indication_trust_unlocked_plugged_in" msgid="2323452175329362855">"<xliff:g id="KEYGUARD_INDICATION">%1$s</xliff:g>\n<xliff:g id="POWER_INDICATION">%2$s</xliff:g>"</string>
<string name="hidden_notifications_title" msgid="1782412844777612795">"الحصول على الإشعارات بشكل أسرع"</string>
<string name="hidden_notifications_text" msgid="5899627470450792578">"الاطّلاع عليها قبل فتح القفل"</string>
<string name="hidden_notifications_cancel" msgid="4805370226181001278">"لا، شكرًا"</string>
<string name="hidden_notifications_setup" msgid="2064795578526982467">"إعداد"</string>
<string name="zen_mode_and_condition" msgid="5043165189511223718">"<xliff:g id="ZEN_MODE">%1$s</xliff:g>. <xliff:g id="EXIT_CONDITION">%2$s</xliff:g>"</string>
- <string name="volume_zen_end_now" msgid="5901885672973736563">"إيقاف التشغيل الآن"</string>
+ <string name="volume_zen_end_now" msgid="5901885672973736563">"إيقاف التفعيل الآن"</string>
<string name="accessibility_volume_settings" msgid="1458961116951564784">"إعدادات الصوت"</string>
<string name="accessibility_volume_expand" msgid="7653070939304433603">"توسيع"</string>
<string name="accessibility_volume_collapse" msgid="2746845391013829996">"تصغير"</string>
@@ -779,7 +780,7 @@
<string name="keyboard_key_media_stop" msgid="1509943745250377699">"إيقاف"</string>
<string name="keyboard_key_media_next" msgid="8502476691227914952">"التالي"</string>
<string name="keyboard_key_media_previous" msgid="5637875709190955351">"السابق"</string>
- <string name="keyboard_key_media_rewind" msgid="3450387734224327577">"إرجاع"</string>
+ <string name="keyboard_key_media_rewind" msgid="3450387734224327577">"ترجيع"</string>
<string name="keyboard_key_media_fast_forward" msgid="3572444327046911822">"تقديم سريع"</string>
<string name="keyboard_key_page_up" msgid="173914303254199845">"Page Up"</string>
<string name="keyboard_key_page_down" msgid="9035902490071829731">"Page Down"</string>
@@ -999,12 +1000,9 @@
<string name="bubble_accessibility_action_move_bottom_left" msgid="6339015902495504715">"نقل إلى أسفل يمين الشاشة"</string>
<string name="bubble_accessibility_action_move_bottom_right" msgid="7471571700628346212">"نقل إلى أسفل اليسار"</string>
<string name="bubble_dismiss_text" msgid="7071770411580452911">"تجاهل"</string>
- <!-- no translation found for bubbles_user_education_title (3385222165904578710) -->
- <skip />
- <!-- no translation found for bubbles_user_education_description (6663205638091146934) -->
- <skip />
- <!-- no translation found for bubbles_user_education_manage (1391639189507036423) -->
- <skip />
+ <string name="bubbles_user_education_title" msgid="3385222165904578710">"الاحتفاظ بالمحادثات في المقدمة"</string>
+ <string name="bubbles_user_education_description" msgid="6663205638091146934">"ستظهر المحادثات الجديدة من <xliff:g id="APP_NAME">%1$s</xliff:g> كفقاقيع. انقر على فقعة لفتحها. اسحبها لنقلها.\n\nانقر على الفقاعة."</string>
+ <string name="bubbles_user_education_manage" msgid="1391639189507036423">"انقر على \"إدارة\" لإيقاف الفقاعات من هذا التطبيق."</string>
<string name="notification_content_system_nav_changed" msgid="5077913144844684544">"تم تحديث التنقل داخل النظام. لإجراء التغييرات، يُرجى الانتقال إلى \"الإعدادات\"."</string>
<string name="notification_content_gesture_nav_available" msgid="4431460803004659888">"الانتقال إلى \"الإعدادات\" لتعديل التنقل داخل النظام"</string>
<string name="inattentive_sleep_warning_title" msgid="3891371591713990373">"وضع الاستعداد"</string>
@@ -1028,4 +1026,10 @@
<string name="controls_favorite_header_all" msgid="7507855973418969992">"الكل"</string>
<string name="controls_favorite_load_error" msgid="2533215155804455348">"تعذّر تحميل قائمة كل عناصر التحكّم."</string>
<string name="controls_favorite_other_zone_header" msgid="9089613266575525252">"غير ذلك"</string>
+ <!-- no translation found for controls_dialog_title (8806193219278278442) -->
+ <skip />
+ <!-- no translation found for controls_dialog_ok (7011816381344485651) -->
+ <skip />
+ <!-- no translation found for controls_dialog_message (6292099631702047540) -->
+ <skip />
</resources>
diff --git a/packages/SystemUI/res/values-as/strings.xml b/packages/SystemUI/res/values-as/strings.xml
index a1a6ae9a6ce6..2dc93cdfdeb9 100644
--- a/packages/SystemUI/res/values-as/strings.xml
+++ b/packages/SystemUI/res/values-as/strings.xml
@@ -558,6 +558,8 @@
<string name="monitoring_description_app_personal_work" msgid="6175816356939166101">"<xliff:g id="ORGANIZATION">%1$s</xliff:g>য়ে আপোনাৰ কৰ্মস্থানৰ প্ৰ\'ফাইল পৰিচালনা কৰে। এই প্ৰ\'ফাইলটো <xliff:g id="APPLICATION_WORK">%2$s</xliff:g>ৰে সংযুক্ত হৈ আছে যি ইমেইল, এপ্ আৰু ৱেবছাইটসমূহকে ধৰি আপোনাৰ কর্মস্থানৰ নেটৱর্কৰ কাৰ্যকলাপ নিৰীক্ষণ কৰিব পাৰিব। \n\nআপুনি <xliff:g id="APPLICATION_PERSONAL">%3$s</xliff:g>ৰ সৈতেও সংযুক্ত হৈ আছে, যি আপোনাৰ ব্য়ক্তিগত নেটৱৰ্কৰ কাৰ্যকলাপ নিৰীক্ষণ কৰিব পাৰে।"</string>
<string name="keyguard_indication_trust_unlocked" msgid="7395154975733744547">"TrustAgentএ আনলক কৰি ৰাখিছে"</string>
<string name="keyguard_indication_trust_disabled" msgid="6820793704816727918">"আপুনি নিজে আনলক নকৰালৈকে ডিভাইচ লক হৈ থাকিব"</string>
+ <!-- no translation found for keyguard_indication_trust_unlocked_plugged_in (2323452175329362855) -->
+ <skip />
<string name="hidden_notifications_title" msgid="1782412844777612795">"জাননী ক্ষিপ্ৰতাৰে লাভ কৰক"</string>
<string name="hidden_notifications_text" msgid="5899627470450792578">"আপুনি আনলক কৰাৰ পূৰ্বে তেওঁলোকক চাওক"</string>
<string name="hidden_notifications_cancel" msgid="4805370226181001278">"নালাগে, ধন্যবাদ"</string>
@@ -979,12 +981,9 @@
<string name="bubble_accessibility_action_move_bottom_left" msgid="6339015902495504715">"বুটামটো বাওঁফালে নিয়ক"</string>
<string name="bubble_accessibility_action_move_bottom_right" msgid="7471571700628346212">"তলৰ সোঁফালে নিয়ক"</string>
<string name="bubble_dismiss_text" msgid="7071770411580452911">"অগ্ৰাহ্য কৰক"</string>
- <!-- no translation found for bubbles_user_education_title (3385222165904578710) -->
- <skip />
- <!-- no translation found for bubbles_user_education_description (6663205638091146934) -->
- <skip />
- <!-- no translation found for bubbles_user_education_manage (1391639189507036423) -->
- <skip />
+ <string name="bubbles_user_education_title" msgid="3385222165904578710">"চাটসমূহ সন্মুখত ৰাখক"</string>
+ <string name="bubbles_user_education_description" msgid="6663205638091146934">"<xliff:g id="APP_NAME">%1$s</xliff:g>ৰ নতুন চাটসমূহ বাবল হিচাপে দেখা পোৱা যাব। এইটো খুলিবলৈ এটা বাবলত টিপক। এইটোক আঁতৰাবলৈ টানি আনক।\n\nবাবলটোত টিপক"</string>
+ <string name="bubbles_user_education_manage" msgid="1391639189507036423">"এই এপ্‌টোৰ পৰা বাবল অফ কৰিবলৈ পৰিচালনা কৰকত টিপক"</string>
<string name="notification_content_system_nav_changed" msgid="5077913144844684544">"ছিষ্টেম নেভিগেশ্বন আপডে’ট কৰা হ’ল। সলনি কৰিবলৈ ছেটিংসমূহ-লৈ যাওক।"</string>
<string name="notification_content_gesture_nav_available" msgid="4431460803004659888">"ছিষ্টেম নেভিগেশ্বন আপডে’ট কৰিবলৈ ছেটিংসমূহ-লৈ যাওক"</string>
<string name="inattentive_sleep_warning_title" msgid="3891371591713990373">"ষ্টেণ্ডবাই"</string>
@@ -994,12 +993,20 @@
<string name="quick_controls_title" msgid="525285759614231333">"ক্ষিপ্ৰ নিয়ন্ত্ৰণসমূহ"</string>
<string name="controls_providers_title" msgid="8844124515157926071">"নিয়ন্ত্ৰণসমূহ যোগ দিয়ক"</string>
<string name="controls_providers_subtitle" msgid="8187768950110836569">"এটা এপ্ বাছনি কৰক, যিটোৰ পৰা নিয়ন্ত্ৰণসমূহ যোগ দিয়া হ\'ব"</string>
- <!-- no translation found for controls_number_of_favorites (1057347832073807380) -->
+ <plurals name="controls_number_of_favorites" formatted="false" msgid="1057347832073807380">
+ <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="controls_favorite_default_title" msgid="967742178688938137">"নিয়ন্ত্ৰণসমূহ"</string>
<string name="controls_favorite_subtitle" msgid="4049644994401173949">"ক্ষিপ্ৰ এক্সেছৰ বাবে নিয়ন্ত্ৰণসমূহ বাছনি কৰক"</string>
<string name="controls_favorite_header_favorites" msgid="3118600046217493471">"প্ৰিয়সমূহ"</string>
<string name="controls_favorite_header_all" msgid="7507855973418969992">"সকলো"</string>
<string name="controls_favorite_load_error" msgid="2533215155804455348">"নিয়ন্ত্ৰণসমূহৰ সম্পূর্ণ সূচীখন ল’ড কৰিব পৰা নগ’ল।"</string>
- <!-- no translation found for controls_favorite_other_zone_header (9089613266575525252) -->
+ <string name="controls_favorite_other_zone_header" msgid="9089613266575525252">"অন্য"</string>
+ <!-- no translation found for controls_dialog_title (8806193219278278442) -->
+ <skip />
+ <!-- no translation found for controls_dialog_ok (7011816381344485651) -->
+ <skip />
+ <!-- no translation found for controls_dialog_message (6292099631702047540) -->
<skip />
</resources>
diff --git a/packages/SystemUI/res/values-az/strings.xml b/packages/SystemUI/res/values-az/strings.xml
index 289838ea7a33..f116289d569f 100644
--- a/packages/SystemUI/res/values-az/strings.xml
+++ b/packages/SystemUI/res/values-az/strings.xml
@@ -558,6 +558,7 @@
<string name="monitoring_description_app_personal_work" msgid="6175816356939166101">"İş profili <xliff:g id="ORGANIZATION">%1$s</xliff:g> tərəfindən idarə edilir. Profil e-poçt, tətbiq və veb saytlar da daxil olmaqla şəbəkə fəaliyyətinə nəzarət edən <xliff:g id="APPLICATION_WORK">%2$s</xliff:g> tətbiqinə qoşuludur.\n\nEyni zamanda şəxsi şəbəkə fəaliyyətinə nəzarət edən <xliff:g id="APPLICATION_PERSONAL">%3$s</xliff:g> tətbiqinə qoşulusunuz."</string>
<string name="keyguard_indication_trust_unlocked" msgid="7395154975733744547">"TrustAgent ilə açıq saxlayın"</string>
<string name="keyguard_indication_trust_disabled" msgid="6820793704816727918">"Device will stay locked until you manually unlock"</string>
+ <string name="keyguard_indication_trust_unlocked_plugged_in" msgid="2323452175329362855">"<xliff:g id="KEYGUARD_INDICATION">%1$s</xliff:g>\n<xliff:g id="POWER_INDICATION">%2$s</xliff:g>"</string>
<string name="hidden_notifications_title" msgid="1782412844777612795">"Bildirişləri daha sürətlə əldə edin"</string>
<string name="hidden_notifications_text" msgid="5899627470450792578">"Kiliddən çıxarmadan öncə onları görün"</string>
<string name="hidden_notifications_cancel" msgid="4805370226181001278">"Yox, çox sağ olun"</string>
@@ -979,12 +980,9 @@
<string name="bubble_accessibility_action_move_bottom_left" msgid="6339015902495504715">"Aşağıya sola köçürün"</string>
<string name="bubble_accessibility_action_move_bottom_right" msgid="7471571700628346212">"Aşağıya sağa köçürün"</string>
<string name="bubble_dismiss_text" msgid="7071770411580452911">"Kənarlaşdırın"</string>
- <!-- no translation found for bubbles_user_education_title (3385222165904578710) -->
- <skip />
- <!-- no translation found for bubbles_user_education_description (6663205638091146934) -->
- <skip />
- <!-- no translation found for bubbles_user_education_manage (1391639189507036423) -->
- <skip />
+ <string name="bubbles_user_education_title" msgid="3385222165904578710">"Söhbətləri öndə saxlayın"</string>
+ <string name="bubbles_user_education_description" msgid="6663205638091146934">"Yeni <xliff:g id="APP_NAME">%1$s</xliff:g> söhbətləri qabarcıq şəklində görünəcək. Açmaq üçün qabarcığa toxunun. Hərəkət etdirmək üçün onu sürüşdürün.\n\nQabarcığa toxunun"</string>
+ <string name="bubbles_user_education_manage" msgid="1391639189507036423">"Bu tətbiqdə qabarcıqları deaktiv etmək üçün \"İdarə edin\" seçiminə toxunun"</string>
<string name="notification_content_system_nav_changed" msgid="5077913144844684544">"Sistem naviqasiyası yeniləndi. Dəyişiklik etmək üçün Ayarlara daxil olun."</string>
<string name="notification_content_gesture_nav_available" msgid="4431460803004659888">"Sistem naviqasiyasını yeniləmək üçün Ayarlara keçin"</string>
<string name="inattentive_sleep_warning_title" msgid="3891371591713990373">"Gözləmə rejimi"</string>
@@ -1004,4 +1002,10 @@
<string name="controls_favorite_header_all" msgid="7507855973418969992">"Hamısı"</string>
<string name="controls_favorite_load_error" msgid="2533215155804455348">"Bütün nizamlayıcıların siyahısı yüklənmədi."</string>
<string name="controls_favorite_other_zone_header" msgid="9089613266575525252">"Digər"</string>
+ <!-- no translation found for controls_dialog_title (8806193219278278442) -->
+ <skip />
+ <!-- no translation found for controls_dialog_ok (7011816381344485651) -->
+ <skip />
+ <!-- no translation found for controls_dialog_message (6292099631702047540) -->
+ <skip />
</resources>
diff --git a/packages/SystemUI/res/values-b+sr+Latn/strings.xml b/packages/SystemUI/res/values-b+sr+Latn/strings.xml
index b6908294224c..ac8d9374e537 100644
--- a/packages/SystemUI/res/values-b+sr+Latn/strings.xml
+++ b/packages/SystemUI/res/values-b+sr+Latn/strings.xml
@@ -561,6 +561,7 @@
<string name="monitoring_description_app_personal_work" msgid="6175816356939166101">"Profilom za Work upravlja <xliff:g id="ORGANIZATION">%1$s</xliff:g>. Povezan je sa aplikacijom <xliff:g id="APPLICATION_WORK">%2$s</xliff:g>, koja može da nadgleda aktivnosti na poslovnoj mreži, uključujući imejlove, aplikacije i veb-sajtove.\n\nPovezani ste i sa aplikacijom <xliff:g id="APPLICATION_PERSONAL">%3$s</xliff:g>, koja može da nadgleda aktivnosti na ličnoj mreži."</string>
<string name="keyguard_indication_trust_unlocked" msgid="7395154975733744547">"Pouzdani agent sprečava zaključavanje"</string>
<string name="keyguard_indication_trust_disabled" msgid="6820793704816727918">"Uređaj će ostati zaključan dok ga ne otključate ručno"</string>
+ <string name="keyguard_indication_trust_unlocked_plugged_in" msgid="2323452175329362855">"<xliff:g id="KEYGUARD_INDICATION">%1$s</xliff:g>\n<xliff:g id="POWER_INDICATION">%2$s</xliff:g>"</string>
<string name="hidden_notifications_title" msgid="1782412844777612795">"Brže dobijajte obaveštenja"</string>
<string name="hidden_notifications_text" msgid="5899627470450792578">"Pregledajte ih pre otključavanja"</string>
<string name="hidden_notifications_cancel" msgid="4805370226181001278">"Ne, hvala"</string>
@@ -984,12 +985,9 @@
<string name="bubble_accessibility_action_move_bottom_left" msgid="6339015902495504715">"Premesti dole levo"</string>
<string name="bubble_accessibility_action_move_bottom_right" msgid="7471571700628346212">"Premesti dole desno"</string>
<string name="bubble_dismiss_text" msgid="7071770411580452911">"Odbaci"</string>
- <!-- no translation found for bubbles_user_education_title (3385222165904578710) -->
- <skip />
- <!-- no translation found for bubbles_user_education_description (6663205638091146934) -->
- <skip />
- <!-- no translation found for bubbles_user_education_manage (1391639189507036423) -->
- <skip />
+ <string name="bubbles_user_education_title" msgid="3385222165904578710">"Neka poruke ćaskanja ostanu u prvom planu"</string>
+ <string name="bubbles_user_education_description" msgid="6663205638091146934">"Nove poruke ćaskanja iz aplikacije <xliff:g id="APP_NAME">%1$s</xliff:g> će se prikazati kao oblačići. Dodirnite oblačić da biste ga otvorili. Prevucite da biste ga premestili.\n\nDodirnite oblačić"</string>
+ <string name="bubbles_user_education_manage" msgid="1391639189507036423">"Dodirnite Upravljajte da biste isključili oblačiće iz ove aplikacije"</string>
<string name="notification_content_system_nav_changed" msgid="5077913144844684544">"Navigacija sistema je ažurirana. Da biste uneli izmene, idite u Podešavanja."</string>
<string name="notification_content_gesture_nav_available" msgid="4431460803004659888">"Idite u Podešavanja da biste ažurirali navigaciju sistema"</string>
<string name="inattentive_sleep_warning_title" msgid="3891371591713990373">"Stanje pripravnosti"</string>
@@ -1010,4 +1008,10 @@
<string name="controls_favorite_header_all" msgid="7507855973418969992">"Sve"</string>
<string name="controls_favorite_load_error" msgid="2533215155804455348">"Učitavanje liste svih kontrola nije uspelo."</string>
<string name="controls_favorite_other_zone_header" msgid="9089613266575525252">"Drugo"</string>
+ <!-- no translation found for controls_dialog_title (8806193219278278442) -->
+ <skip />
+ <!-- no translation found for controls_dialog_ok (7011816381344485651) -->
+ <skip />
+ <!-- no translation found for controls_dialog_message (6292099631702047540) -->
+ <skip />
</resources>
diff --git a/packages/SystemUI/res/values-be/strings.xml b/packages/SystemUI/res/values-be/strings.xml
index feee6a23f57f..29d76a6a2770 100644
--- a/packages/SystemUI/res/values-be/strings.xml
+++ b/packages/SystemUI/res/values-be/strings.xml
@@ -566,6 +566,7 @@
<string name="monitoring_description_app_personal_work" msgid="6175816356939166101">"Ваш працоўны профіль знаходзіцца пад кіраваннем <xliff:g id="ORGANIZATION">%1$s</xliff:g>. Ён падключаны да праграмы <xliff:g id="APPLICATION_WORK">%2$s</xliff:g>, якая можа сачыць за вашай працоўнай сеткавай актыўнасцю, уключаючы электронную пошту, праграмы і вэб-сайты.\n\nВы таксама падключаны да праграмы <xliff:g id="APPLICATION_PERSONAL">%3$s</xliff:g>, якая можа сачыць за вашай асабістай сеткавай актыўнасцю."</string>
<string name="keyguard_indication_trust_unlocked" msgid="7395154975733744547">"Разблакіравана з дапамогай TrustAgent"</string>
<string name="keyguard_indication_trust_disabled" msgid="6820793704816727918">"Прылада будзе заставацца заблакіраванай, пакуль вы не разблакіруеце яе ўручную"</string>
+ <string name="keyguard_indication_trust_unlocked_plugged_in" msgid="2323452175329362855">"<xliff:g id="KEYGUARD_INDICATION">%1$s</xliff:g>\n<xliff:g id="POWER_INDICATION">%2$s</xliff:g>"</string>
<string name="hidden_notifications_title" msgid="1782412844777612795">"Атрымлівайце апавяшчэнні хутчэй"</string>
<string name="hidden_notifications_text" msgid="5899627470450792578">"Праглядайце іх перад разблакіроўкай"</string>
<string name="hidden_notifications_cancel" msgid="4805370226181001278">"Не, дзякуй"</string>
@@ -991,12 +992,9 @@
<string name="bubble_accessibility_action_move_bottom_left" msgid="6339015902495504715">"Перамясціць лявей і ніжэй"</string>
<string name="bubble_accessibility_action_move_bottom_right" msgid="7471571700628346212">"Перамясціць правей і ніжэй"</string>
<string name="bubble_dismiss_text" msgid="7071770411580452911">"Адхіліць"</string>
- <!-- no translation found for bubbles_user_education_title (3385222165904578710) -->
- <skip />
- <!-- no translation found for bubbles_user_education_description (6663205638091146934) -->
- <skip />
- <!-- no translation found for bubbles_user_education_manage (1391639189507036423) -->
- <skip />
+ <string name="bubbles_user_education_title" msgid="3385222165904578710">"Пакідаць чаты на экране"</string>
+ <string name="bubbles_user_education_description" msgid="6663205638091146934">"Новыя чаты з праграмы \"<xliff:g id="APP_NAME">%1$s</xliff:g>\" будуць паказвацца ў выглядзе ўсплывальных апавяшчэнняў. Каб адкрыць усплывальнае апавяшчэнне, націсніце на яго. Каб перамясціць – перацягніце.\n\nНацісніце на ўсплывальнае апавяшчэнне"</string>
+ <string name="bubbles_user_education_manage" msgid="1391639189507036423">"Каб выключыць усплывальная апавяшчэнні з гэтай праграмы, націсніце \"Кіраваць\""</string>
<string name="notification_content_system_nav_changed" msgid="5077913144844684544">"Навігацыя ў сістэме абноўлена. Каб унесці змяненні, перайдзіце ў Налады."</string>
<string name="notification_content_gesture_nav_available" msgid="4431460803004659888">"Перайдзіце ў Налады, каб абнавіць параметры навігацыі ў сістэме"</string>
<string name="inattentive_sleep_warning_title" msgid="3891371591713990373">"Рэжым чакання"</string>
@@ -1018,4 +1016,10 @@
<string name="controls_favorite_header_all" msgid="7507855973418969992">"Усе"</string>
<string name="controls_favorite_load_error" msgid="2533215155804455348">"Не ўдалося загрузіць спіс усіх сродкаў кіравання."</string>
<string name="controls_favorite_other_zone_header" msgid="9089613266575525252">"Іншае"</string>
+ <!-- no translation found for controls_dialog_title (8806193219278278442) -->
+ <skip />
+ <!-- no translation found for controls_dialog_ok (7011816381344485651) -->
+ <skip />
+ <!-- no translation found for controls_dialog_message (6292099631702047540) -->
+ <skip />
</resources>
diff --git a/packages/SystemUI/res/values-bg/strings.xml b/packages/SystemUI/res/values-bg/strings.xml
index fa57d285e206..efb5b0704f13 100644
--- a/packages/SystemUI/res/values-bg/strings.xml
+++ b/packages/SystemUI/res/values-bg/strings.xml
@@ -558,6 +558,7 @@
<string name="monitoring_description_app_personal_work" msgid="6175816356939166101">"Служебният ви потребителски профил се управлява от <xliff:g id="ORGANIZATION">%1$s</xliff:g>. Той е свързан с приложението <xliff:g id="APPLICATION_WORK">%2$s</xliff:g>, което може да наблюдава служебната ви активност в мрежата, включително имейли, приложения и уебсайтове.\n\nУстановена е връзка и с приложението <xliff:g id="APPLICATION_PERSONAL">%3$s</xliff:g>, което може да наблюдава личната ви активност в мрежата."</string>
<string name="keyguard_indication_trust_unlocked" msgid="7395154975733744547">"Поддържа се отключено от надежден агент"</string>
<string name="keyguard_indication_trust_disabled" msgid="6820793704816727918">"Устройството ще остане заключено, докато не го отключите ръчно"</string>
+ <string name="keyguard_indication_trust_unlocked_plugged_in" msgid="2323452175329362855">"<xliff:g id="KEYGUARD_INDICATION">%1$s</xliff:g>\n<xliff:g id="POWER_INDICATION">%2$s</xliff:g>"</string>
<string name="hidden_notifications_title" msgid="1782412844777612795">"Получавайте известия по-бързо"</string>
<string name="hidden_notifications_text" msgid="5899627470450792578">"Вижте известията, преди да отключите"</string>
<string name="hidden_notifications_cancel" msgid="4805370226181001278">"Няма нужда"</string>
@@ -979,12 +980,9 @@
<string name="bubble_accessibility_action_move_bottom_left" msgid="6339015902495504715">"Преместване долу вляво"</string>
<string name="bubble_accessibility_action_move_bottom_right" msgid="7471571700628346212">"Преместване долу вдясно"</string>
<string name="bubble_dismiss_text" msgid="7071770411580452911">"Отхвърляне"</string>
- <!-- no translation found for bubbles_user_education_title (3385222165904578710) -->
- <skip />
- <!-- no translation found for bubbles_user_education_description (6663205638091146934) -->
- <skip />
- <!-- no translation found for bubbles_user_education_manage (1391639189507036423) -->
- <skip />
+ <string name="bubbles_user_education_title" msgid="3385222165904578710">"Задръжте чатовете на екрана"</string>
+ <string name="bubbles_user_education_description" msgid="6663205638091146934">"Новите чатове от <xliff:g id="APP_NAME">%1$s</xliff:g> ще се показват като балончета. Докоснете някое, за да го отворите. Плъзнете, за да го преместите.\n\nДокоснете балончето"</string>
+ <string name="bubbles_user_education_manage" msgid="1391639189507036423">"Докоснете „Управление“, за да изключите балончетата от това приложение"</string>
<string name="notification_content_system_nav_changed" msgid="5077913144844684544">"Режимът за навигиране в системата е актуализиран. За да извършите промени, отворете настройките."</string>
<string name="notification_content_gesture_nav_available" msgid="4431460803004659888">"Отворете настройките, за да актуализирате режима за навигиране в системата"</string>
<string name="inattentive_sleep_warning_title" msgid="3891371591713990373">"Режим на готовност"</string>
@@ -1004,4 +1002,10 @@
<string name="controls_favorite_header_all" msgid="7507855973418969992">"Всички"</string>
<string name="controls_favorite_load_error" msgid="2533215155804455348">"Списъкът с всички контроли не бе зареден."</string>
<string name="controls_favorite_other_zone_header" msgid="9089613266575525252">"Друго"</string>
+ <!-- no translation found for controls_dialog_title (8806193219278278442) -->
+ <skip />
+ <!-- no translation found for controls_dialog_ok (7011816381344485651) -->
+ <skip />
+ <!-- no translation found for controls_dialog_message (6292099631702047540) -->
+ <skip />
</resources>
diff --git a/packages/SystemUI/res/values-bn/strings.xml b/packages/SystemUI/res/values-bn/strings.xml
index 1f6a37745aa3..7c0701fa36b6 100644
--- a/packages/SystemUI/res/values-bn/strings.xml
+++ b/packages/SystemUI/res/values-bn/strings.xml
@@ -558,6 +558,8 @@
<string name="monitoring_description_app_personal_work" msgid="6175816356939166101">"<xliff:g id="ORGANIZATION">%1$s</xliff:g> আপনার কর্মস্থলের প্রোফাইল পরিচালনা করে। প্রোফাইলটি <xliff:g id="APPLICATION_WORK">%2$s</xliff:g> এর সাথে সংযুক্ত, যেটি ইমেল অ্যাপ, ও ওয়েবসাইট সহ আপনার কর্মস্থলের নেটওয়ার্ক অ্যাক্টিভিটির উপরে নজর রাখতে পারে।\n\n এ ছাড়াও আপনি <xliff:g id="APPLICATION_PERSONAL">%3$s</xliff:g> এর সাথে সংযুক্ত, যেটি আপনার ব্যক্তিগত নেটওয়ার্কে নজর রাখে।"</string>
<string name="keyguard_indication_trust_unlocked" msgid="7395154975733744547">"TrustAgent দিয়ে আনলক করে রাখা হয়েছে"</string>
<string name="keyguard_indication_trust_disabled" msgid="6820793704816727918">"আপনি নিজে আনলক না করা পর্যন্ত ডিভাইসটি লক হয়ে থাকবে"</string>
+ <!-- no translation found for keyguard_indication_trust_unlocked_plugged_in (2323452175329362855) -->
+ <skip />
<string name="hidden_notifications_title" msgid="1782412844777612795">"বিজ্ঞপ্তিগুলি আরও দ্রুত পান"</string>
<string name="hidden_notifications_text" msgid="5899627470450792578">"আপনি আনলক করার আগে ওগুলো দেখুন"</string>
<string name="hidden_notifications_cancel" msgid="4805370226181001278">"না থাক"</string>
@@ -979,12 +981,9 @@
<string name="bubble_accessibility_action_move_bottom_left" msgid="6339015902495504715">"নিচে বাঁদিকে সরান"</string>
<string name="bubble_accessibility_action_move_bottom_right" msgid="7471571700628346212">"নিচে ডান দিকে সরান"</string>
<string name="bubble_dismiss_text" msgid="7071770411580452911">"খারিজ করুন"</string>
- <!-- no translation found for bubbles_user_education_title (3385222165904578710) -->
- <skip />
- <!-- no translation found for bubbles_user_education_description (6663205638091146934) -->
- <skip />
- <!-- no translation found for bubbles_user_education_manage (1391639189507036423) -->
- <skip />
+ <string name="bubbles_user_education_title" msgid="3385222165904578710">"চ্যাটগুলি সামনে রাখুন"</string>
+ <string name="bubbles_user_education_description" msgid="6663205638091146934">"<xliff:g id="APP_NAME">%1$s</xliff:g>-এর তরফ থেকে নতুন চ্যাট বাবল হিসেবে দেখানো হবে। এটি খোলার জন্য বাবল ট্যাপ করুন। এটি সরানোর জন্য টেনে আনুন।\n\nবাবল ট্যাপ করুন"</string>
+ <string name="bubbles_user_education_manage" msgid="1391639189507036423">"এই অ্যাপ থেকে বাবল বন্ধ করতে ম্যানেজ করুন বিকল্প ট্যাপ করুন"</string>
<string name="notification_content_system_nav_changed" msgid="5077913144844684544">"সিস্টেম নেভিগেশন আপডেট হয়েছে। পরিবর্তন করার জন্য সেটিংসে যান।"</string>
<string name="notification_content_gesture_nav_available" msgid="4431460803004659888">"সিস্টেম নেভিগেশন আপডেট করতে সেটিংসে যান"</string>
<string name="inattentive_sleep_warning_title" msgid="3891371591713990373">"স্ট্যান্ডবাই"</string>
@@ -994,12 +993,20 @@
<string name="quick_controls_title" msgid="525285759614231333">"দ্রুত নিয়ন্ত্রণ"</string>
<string name="controls_providers_title" msgid="8844124515157926071">"কন্ট্রোল যোগ করুন"</string>
<string name="controls_providers_subtitle" msgid="8187768950110836569">"এমন একটি অ্যাপ বাছুন যেটি থেকে কন্ট্রোল যোগ করা যাবে"</string>
- <!-- no translation found for controls_number_of_favorites (1057347832073807380) -->
+ <plurals name="controls_number_of_favorites" formatted="false" msgid="1057347832073807380">
+ <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="controls_favorite_default_title" msgid="967742178688938137">"নিয়ন্ত্রণ"</string>
<string name="controls_favorite_subtitle" msgid="4049644994401173949">"দ্রুত অ্যাক্সেস করার জন্য কন্ট্রোল বেছে নিন"</string>
<string name="controls_favorite_header_favorites" msgid="3118600046217493471">"পছন্দসই"</string>
<string name="controls_favorite_header_all" msgid="7507855973418969992">"সব"</string>
<string name="controls_favorite_load_error" msgid="2533215155804455348">"সব কন্ট্রোলের তালিকা লোড করা যায়নি।"</string>
- <!-- no translation found for controls_favorite_other_zone_header (9089613266575525252) -->
+ <string name="controls_favorite_other_zone_header" msgid="9089613266575525252">"অন্য"</string>
+ <!-- no translation found for controls_dialog_title (8806193219278278442) -->
+ <skip />
+ <!-- no translation found for controls_dialog_ok (7011816381344485651) -->
+ <skip />
+ <!-- no translation found for controls_dialog_message (6292099631702047540) -->
<skip />
</resources>
diff --git a/packages/SystemUI/res/values-bs/strings.xml b/packages/SystemUI/res/values-bs/strings.xml
index fcc3680e3665..ce6fe5223389 100644
--- a/packages/SystemUI/res/values-bs/strings.xml
+++ b/packages/SystemUI/res/values-bs/strings.xml
@@ -561,6 +561,7 @@
<string name="monitoring_description_app_personal_work" msgid="6175816356939166101">"Radnim profilom upravlja <xliff:g id="ORGANIZATION">%1$s</xliff:g>. Profil je povezan s aplikacijom <xliff:g id="APPLICATION_WORK">%2$s</xliff:g>, koja može pratiti vašu aktivnost na radnoj mreži, uključujući e-poruke, aplikacije i web lokacije.\n\nPovezani ste i sa aplikacijom <xliff:g id="APPLICATION_PERSONAL">%3$s</xliff:g>, koja može pratiti vašu aktivnost na privatnoj mreži."</string>
<string name="keyguard_indication_trust_unlocked" msgid="7395154975733744547">"Pouzdani agent sprečava zaključavanje"</string>
<string name="keyguard_indication_trust_disabled" msgid="6820793704816727918">"Uređaj će ostati zaključan dok ga ručno ne otključate"</string>
+ <string name="keyguard_indication_trust_unlocked_plugged_in" msgid="2323452175329362855">"<xliff:g id="KEYGUARD_INDICATION">%1$s</xliff:g>\n<xliff:g id="POWER_INDICATION">%2$s</xliff:g>"</string>
<string name="hidden_notifications_title" msgid="1782412844777612795">"Brže primaj obavještenja"</string>
<string name="hidden_notifications_text" msgid="5899627470450792578">"Vidi ih prije otključavanja"</string>
<string name="hidden_notifications_cancel" msgid="4805370226181001278">"Ne, hvala"</string>
@@ -986,12 +987,9 @@
<string name="bubble_accessibility_action_move_bottom_left" msgid="6339015902495504715">"Pomjeri dolje lijevo"</string>
<string name="bubble_accessibility_action_move_bottom_right" msgid="7471571700628346212">"Pomjerite dolje desno"</string>
<string name="bubble_dismiss_text" msgid="7071770411580452911">"Odbaci"</string>
- <!-- no translation found for bubbles_user_education_title (3385222165904578710) -->
- <skip />
- <!-- no translation found for bubbles_user_education_description (6663205638091146934) -->
- <skip />
- <!-- no translation found for bubbles_user_education_manage (1391639189507036423) -->
- <skip />
+ <string name="bubbles_user_education_title" msgid="3385222165904578710">"Zadržite chatove u prvom planu"</string>
+ <string name="bubbles_user_education_description" msgid="6663205638091146934">"Novi chatovi iz aplikacije <xliff:g id="APP_NAME">%1$s</xliff:g> će se prikazati u oblačićima. Dodirnite oblačić da ga otvorite. Prevucite da ga premjestite.\n\nDodirnite oblačić"</string>
+ <string name="bubbles_user_education_manage" msgid="1391639189507036423">"Dodirnite Upravljaj da isključite oblačiće iz ove aplikacije"</string>
<string name="notification_content_system_nav_changed" msgid="5077913144844684544">"Navigiranje sistemom je ažurirano. Da izvršite promjene, idite u Postavke."</string>
<string name="notification_content_gesture_nav_available" msgid="4431460803004659888">"Idite u Postavke da ažurirate navigiranje sistemom"</string>
<string name="inattentive_sleep_warning_title" msgid="3891371591713990373">"Stanje mirovanja"</string>
@@ -1012,4 +1010,10 @@
<string name="controls_favorite_header_all" msgid="7507855973418969992">"Sve"</string>
<string name="controls_favorite_load_error" msgid="2533215155804455348">"Učitavanje liste svih kontrola nije uspjelo."</string>
<string name="controls_favorite_other_zone_header" msgid="9089613266575525252">"Drugo"</string>
+ <!-- no translation found for controls_dialog_title (8806193219278278442) -->
+ <skip />
+ <!-- no translation found for controls_dialog_ok (7011816381344485651) -->
+ <skip />
+ <!-- no translation found for controls_dialog_message (6292099631702047540) -->
+ <skip />
</resources>
diff --git a/packages/SystemUI/res/values-ca/strings.xml b/packages/SystemUI/res/values-ca/strings.xml
index 7f7eff185490..f6f89fd4eedc 100644
--- a/packages/SystemUI/res/values-ca/strings.xml
+++ b/packages/SystemUI/res/values-ca/strings.xml
@@ -558,6 +558,7 @@
<string name="monitoring_description_app_personal_work" msgid="6175816356939166101">"<xliff:g id="ORGANIZATION">%1$s</xliff:g> gestiona el teu perfil de treball. El perfil està connectat a <xliff:g id="APPLICATION_WORK">%2$s</xliff:g>, que pot supervisar la teva activitat a la xarxa de treball, com ara els correus electrònics, les aplicacions i els llocs web.\n\nTambé estàs connectat a <xliff:g id="APPLICATION_PERSONAL">%3$s</xliff:g>, que pot supervisar la teva activitat personal a la xarxa."</string>
<string name="keyguard_indication_trust_unlocked" msgid="7395154975733744547">"Desbloquejat per TrustAgent"</string>
<string name="keyguard_indication_trust_disabled" msgid="6820793704816727918">"El dispositiu continuarà bloquejat fins que no el desbloquegis manualment."</string>
+ <string name="keyguard_indication_trust_unlocked_plugged_in" msgid="2323452175329362855">"<xliff:g id="KEYGUARD_INDICATION">%1$s</xliff:g>\n<xliff:g id="POWER_INDICATION">%2$s</xliff:g>"</string>
<string name="hidden_notifications_title" msgid="1782412844777612795">"Rep notificacions més ràpidament"</string>
<string name="hidden_notifications_text" msgid="5899627470450792578">"Mostra-les abans de desbloquejar"</string>
<string name="hidden_notifications_cancel" msgid="4805370226181001278">"No, gràcies"</string>
@@ -979,12 +980,9 @@
<string name="bubble_accessibility_action_move_bottom_left" msgid="6339015902495504715">"Mou a baix a l\'esquerra"</string>
<string name="bubble_accessibility_action_move_bottom_right" msgid="7471571700628346212">"Mou a baix a la dreta"</string>
<string name="bubble_dismiss_text" msgid="7071770411580452911">"Omet"</string>
- <!-- no translation found for bubbles_user_education_title (3385222165904578710) -->
- <skip />
- <!-- no translation found for bubbles_user_education_description (6663205638091146934) -->
- <skip />
- <!-- no translation found for bubbles_user_education_manage (1391639189507036423) -->
- <skip />
+ <string name="bubbles_user_education_title" msgid="3385222165904578710">"Mantén els xats a la vista"</string>
+ <string name="bubbles_user_education_description" msgid="6663205638091146934">"Els xats nous de l\'aplicació <xliff:g id="APP_NAME">%1$s</xliff:g> es mostraran en forma de bombolles. Toca una bombolla per obrir-la. Arrossega-la per moure-la.\n\nToca la bombolla"</string>
+ <string name="bubbles_user_education_manage" msgid="1391639189507036423">"Toca Gestiona per desactivar les bombolles d\'aquesta aplicació"</string>
<string name="notification_content_system_nav_changed" msgid="5077913144844684544">"S\'ha actualitzat el sistema de navegació. Per fer canvis, ves a Configuració."</string>
<string name="notification_content_gesture_nav_available" msgid="4431460803004659888">"Ves a Configuració per actualitzar el sistema de navegació"</string>
<string name="inattentive_sleep_warning_title" msgid="3891371591713990373">"En espera"</string>
@@ -1004,4 +1002,10 @@
<string name="controls_favorite_header_all" msgid="7507855973418969992">"Tots"</string>
<string name="controls_favorite_load_error" msgid="2533215155804455348">"No s\'ha pogut carregar la llista completa de controls."</string>
<string name="controls_favorite_other_zone_header" msgid="9089613266575525252">"Altres"</string>
+ <!-- no translation found for controls_dialog_title (8806193219278278442) -->
+ <skip />
+ <!-- no translation found for controls_dialog_ok (7011816381344485651) -->
+ <skip />
+ <!-- no translation found for controls_dialog_message (6292099631702047540) -->
+ <skip />
</resources>
diff --git a/packages/SystemUI/res/values-cs/strings.xml b/packages/SystemUI/res/values-cs/strings.xml
index 8d26c4a5a042..63290521a8c6 100644
--- a/packages/SystemUI/res/values-cs/strings.xml
+++ b/packages/SystemUI/res/values-cs/strings.xml
@@ -564,6 +564,7 @@
<string name="monitoring_description_app_personal_work" msgid="6175816356939166101">"Váš pracovní profil spravuje organizace <xliff:g id="ORGANIZATION">%1$s</xliff:g>. Je připojen k aplikaci <xliff:g id="APPLICATION_WORK">%2$s</xliff:g>, která může sledovat vaši aktivitu v síti, včetně e-mailů, aplikací a webů.\n\nTaké jste připojeni k aplikaci <xliff:g id="APPLICATION_PERSONAL">%3$s</xliff:g>, která může sledovat vaši osobní aktivitu v síti."</string>
<string name="keyguard_indication_trust_unlocked" msgid="7395154975733744547">"Odemknutí udržováno funkcí TrustAgent"</string>
<string name="keyguard_indication_trust_disabled" msgid="6820793704816727918">"Zařízení zůstane uzamčeno, dokud je ručně neodemknete"</string>
+ <string name="keyguard_indication_trust_unlocked_plugged_in" msgid="2323452175329362855">"<xliff:g id="KEYGUARD_INDICATION">%1$s</xliff:g>\n<xliff:g id="POWER_INDICATION">%2$s</xliff:g>"</string>
<string name="hidden_notifications_title" msgid="1782412844777612795">"Čtěte si oznámení rychleji"</string>
<string name="hidden_notifications_text" msgid="5899627470450792578">"Můžete si je přečíst před odemčením obrazovky."</string>
<string name="hidden_notifications_cancel" msgid="4805370226181001278">"Ne, děkuji"</string>
@@ -989,12 +990,9 @@
<string name="bubble_accessibility_action_move_bottom_left" msgid="6339015902495504715">"Přesunout vlevo dolů"</string>
<string name="bubble_accessibility_action_move_bottom_right" msgid="7471571700628346212">"Přesunout vpravo dolů"</string>
<string name="bubble_dismiss_text" msgid="7071770411580452911">"Zavřít"</string>
- <!-- no translation found for bubbles_user_education_title (3385222165904578710) -->
- <skip />
- <!-- no translation found for bubbles_user_education_description (6663205638091146934) -->
- <skip />
- <!-- no translation found for bubbles_user_education_manage (1391639189507036423) -->
- <skip />
+ <string name="bubbles_user_education_title" msgid="3385222165904578710">"Zobrazovat chaty v popředí"</string>
+ <string name="bubbles_user_education_description" msgid="6663205638091146934">"Nové chaty z aplikace <xliff:g id="APP_NAME">%1$s</xliff:g> se budou zobrazovat jako bubliny. Bublinu otevřete klepnutím. Přetažením ji přemístíte.\n\nKlepnout na bublinu"</string>
+ <string name="bubbles_user_education_manage" msgid="1391639189507036423">"Bubliny pro tuto aplikaci můžete vypnout klepnutím na Spravovat"</string>
<string name="notification_content_system_nav_changed" msgid="5077913144844684544">"Systémová navigace byla aktualizována. Chcete-li provést změny, přejděte do Nastavení."</string>
<string name="notification_content_gesture_nav_available" msgid="4431460803004659888">"Přejděte do Nastavení a aktualizujte systémovou navigaci"</string>
<string name="inattentive_sleep_warning_title" msgid="3891371591713990373">"Pohotovostní režim"</string>
@@ -1016,4 +1014,10 @@
<string name="controls_favorite_header_all" msgid="7507855973418969992">"Vše"</string>
<string name="controls_favorite_load_error" msgid="2533215155804455348">"Načtení seznamu všech ovládacích prvků se nezdařilo."</string>
<string name="controls_favorite_other_zone_header" msgid="9089613266575525252">"Jiné"</string>
+ <!-- no translation found for controls_dialog_title (8806193219278278442) -->
+ <skip />
+ <!-- no translation found for controls_dialog_ok (7011816381344485651) -->
+ <skip />
+ <!-- no translation found for controls_dialog_message (6292099631702047540) -->
+ <skip />
</resources>
diff --git a/packages/SystemUI/res/values-da/strings.xml b/packages/SystemUI/res/values-da/strings.xml
index 1ad31022648f..bb2f57affbde 100644
--- a/packages/SystemUI/res/values-da/strings.xml
+++ b/packages/SystemUI/res/values-da/strings.xml
@@ -558,6 +558,7 @@
<string name="monitoring_description_app_personal_work" msgid="6175816356939166101">"Din arbejdsprofil administreres af <xliff:g id="ORGANIZATION">%1$s</xliff:g>. Profilen har forbindelse til <xliff:g id="APPLICATION_WORK">%2$s</xliff:g>, som kan overvåge din netværksaktivitet, bl.a. mails, apps og websites.\n\nDu har også forbindelse til <xliff:g id="APPLICATION_PERSONAL">%3$s</xliff:g>, som kan overvåge din personlige netværksaktivitet."</string>
<string name="keyguard_indication_trust_unlocked" msgid="7395154975733744547">"Holdes oplåst af TrustAgent"</string>
<string name="keyguard_indication_trust_disabled" msgid="6820793704816727918">"Enheden vil forblive låst, indtil du manuelt låser den op"</string>
+ <string name="keyguard_indication_trust_unlocked_plugged_in" msgid="2323452175329362855">"<xliff:g id="KEYGUARD_INDICATION">%1$s</xliff:g>\n<xliff:g id="POWER_INDICATION">%2$s</xliff:g>"</string>
<string name="hidden_notifications_title" msgid="1782412844777612795">"Modtag notifikationer hurtigere"</string>
<string name="hidden_notifications_text" msgid="5899627470450792578">"Se dem, før du låser op"</string>
<string name="hidden_notifications_cancel" msgid="4805370226181001278">"Nej tak"</string>
@@ -979,12 +980,9 @@
<string name="bubble_accessibility_action_move_bottom_left" msgid="6339015902495504715">"Flyt ned til venstre"</string>
<string name="bubble_accessibility_action_move_bottom_right" msgid="7471571700628346212">"Flyt ned til højre"</string>
<string name="bubble_dismiss_text" msgid="7071770411580452911">"Afvis"</string>
- <!-- no translation found for bubbles_user_education_title (3385222165904578710) -->
- <skip />
- <!-- no translation found for bubbles_user_education_description (6663205638091146934) -->
- <skip />
- <!-- no translation found for bubbles_user_education_manage (1391639189507036423) -->
- <skip />
+ <string name="bubbles_user_education_title" msgid="3385222165904578710">"Hold chatsamtaler i forgrunden"</string>
+ <string name="bubbles_user_education_description" msgid="6663205638091146934">"Nye chatsamtaler fra <xliff:g id="APP_NAME">%1$s</xliff:g> vises som bobler. Tryk på en boble for at åbne samtalen. Træk boblen for at flytte den.\n\nTryk på boblen"</string>
+ <string name="bubbles_user_education_manage" msgid="1391639189507036423">"Tryk på Administrer for at deaktivere bobler fra denne app"</string>
<string name="notification_content_system_nav_changed" msgid="5077913144844684544">"Systemnavigationen blev opdateret. Gå til Indstillinger for at foretage ændringer."</string>
<string name="notification_content_gesture_nav_available" msgid="4431460803004659888">"Gå til Indstillinger for at opdatere systemnavigationen"</string>
<string name="inattentive_sleep_warning_title" msgid="3891371591713990373">"Standby"</string>
@@ -1004,4 +1002,10 @@
<string name="controls_favorite_header_all" msgid="7507855973418969992">"Alle"</string>
<string name="controls_favorite_load_error" msgid="2533215155804455348">"Listen over styringselementer kunne ikke indlæses."</string>
<string name="controls_favorite_other_zone_header" msgid="9089613266575525252">"Andre"</string>
+ <!-- no translation found for controls_dialog_title (8806193219278278442) -->
+ <skip />
+ <!-- no translation found for controls_dialog_ok (7011816381344485651) -->
+ <skip />
+ <!-- no translation found for controls_dialog_message (6292099631702047540) -->
+ <skip />
</resources>
diff --git a/packages/SystemUI/res/values-de/strings.xml b/packages/SystemUI/res/values-de/strings.xml
index 497804129341..bfbc73597d35 100644
--- a/packages/SystemUI/res/values-de/strings.xml
+++ b/packages/SystemUI/res/values-de/strings.xml
@@ -562,6 +562,8 @@
<string name="monitoring_description_app_personal_work" msgid="6175816356939166101">"Dein Arbeitsprofil wird von <xliff:g id="ORGANIZATION">%1$s</xliff:g> verwaltet. Das Profil ist mit <xliff:g id="APPLICATION_WORK">%2$s</xliff:g> verknüpft. Diese App kann deine Netzwerkaktivitäten überwachen, einschließlich E-Mails, Apps und Websites.\n\nDu bist auch mit <xliff:g id="APPLICATION_PERSONAL">%3$s</xliff:g> verbunden, die deine persönlichen Netzwerkaktivitäten überwachen kann."</string>
<string name="keyguard_indication_trust_unlocked" msgid="7395154975733744547">"Durch TrustAgent entsperrt"</string>
<string name="keyguard_indication_trust_disabled" msgid="6820793704816727918">"Das Gerät bleibt gesperrt, bis du es manuell entsperrst."</string>
+ <!-- no translation found for keyguard_indication_trust_unlocked_plugged_in (2323452175329362855) -->
+ <skip />
<string name="hidden_notifications_title" msgid="1782412844777612795">"Benachrichtigungen schneller erhalten"</string>
<string name="hidden_notifications_text" msgid="5899627470450792578">"Vor dem Entsperren anzeigen"</string>
<string name="hidden_notifications_cancel" msgid="4805370226181001278">"Nein danke"</string>
@@ -983,12 +985,9 @@
<string name="bubble_accessibility_action_move_bottom_left" msgid="6339015902495504715">"Nach unten links verschieben"</string>
<string name="bubble_accessibility_action_move_bottom_right" msgid="7471571700628346212">"Nach unten rechts verschieben"</string>
<string name="bubble_dismiss_text" msgid="7071770411580452911">"Schließen"</string>
- <!-- no translation found for bubbles_user_education_title (3385222165904578710) -->
- <skip />
- <!-- no translation found for bubbles_user_education_description (6663205638091146934) -->
- <skip />
- <!-- no translation found for bubbles_user_education_manage (1391639189507036423) -->
- <skip />
+ <string name="bubbles_user_education_title" msgid="3385222165904578710">"Chats im Vordergrund behalten"</string>
+ <string name="bubbles_user_education_description" msgid="6663205638091146934">"Neue <xliff:g id="APP_NAME">%1$s</xliff:g>-Chats werden als Bubbles angezeigt. Wenn du eine Bubble öffnen möchtest, tippe sie an. Wenn du sie verschieben möchtest, ziehe an ihr.\n\nTippe die Bubble an."</string>
+ <string name="bubbles_user_education_manage" msgid="1391639189507036423">"Tippe auf \"Verwalten\", um Bubbles für diese App zu deaktivieren"</string>
<string name="notification_content_system_nav_changed" msgid="5077913144844684544">"Systemsteuerungseinstellungen wurden angepasst. Änderungen kannst du in den Einstellungen vornehmen."</string>
<string name="notification_content_gesture_nav_available" msgid="4431460803004659888">"Gehe zu den Einstellungen, um die Systemsteuerung anzupassen"</string>
<string name="inattentive_sleep_warning_title" msgid="3891371591713990373">"Standby"</string>
@@ -1008,4 +1007,10 @@
<string name="controls_favorite_header_all" msgid="7507855973418969992">"Alle"</string>
<string name="controls_favorite_load_error" msgid="2533215155804455348">"Fehler beim Laden der Liste mit Steuerelementen."</string>
<string name="controls_favorite_other_zone_header" msgid="9089613266575525252">"Andere"</string>
+ <!-- no translation found for controls_dialog_title (8806193219278278442) -->
+ <skip />
+ <!-- no translation found for controls_dialog_ok (7011816381344485651) -->
+ <skip />
+ <!-- no translation found for controls_dialog_message (6292099631702047540) -->
+ <skip />
</resources>
diff --git a/packages/SystemUI/res/values-el/strings.xml b/packages/SystemUI/res/values-el/strings.xml
index 3eab4dd38436..f0b09345e375 100644
--- a/packages/SystemUI/res/values-el/strings.xml
+++ b/packages/SystemUI/res/values-el/strings.xml
@@ -558,6 +558,7 @@
<string name="monitoring_description_app_personal_work" msgid="6175816356939166101">"Ο οργανισμός <xliff:g id="ORGANIZATION">%1$s</xliff:g> διαχειρίζεται το προφίλ εργασίας σας. Το προφίλ συνδέεται με την εφαρμογή <xliff:g id="APPLICATION_WORK">%2$s</xliff:g>, η οποία μπορεί να παρακολουθεί τη δραστηριότητα του δικτύου της εργασίας σας, συμπεριλαμβανομένων μηνυμάτων ηλεκτρονικού ταχυδρομείου, εφαρμογών και ιστοτόπων.\n\nΕπίσης, είστε συνδεδεμένοι στην εφαρμογή <xliff:g id="APPLICATION_PERSONAL">%3$s</xliff:g>, που έχει τη δυνατότητα παρακολούθησης της δραστηριότητας του προσωπικού σας δικτύου."</string>
<string name="keyguard_indication_trust_unlocked" msgid="7395154975733744547">"Διατήρηση ξεκλειδώματος με TrustAgent"</string>
<string name="keyguard_indication_trust_disabled" msgid="6820793704816727918">"Η συσκευή θα παραμείνει κλειδωμένη μέχρι να την ξεκλειδώσετε μη αυτόματα"</string>
+ <string name="keyguard_indication_trust_unlocked_plugged_in" msgid="2323452175329362855">"<xliff:g id="KEYGUARD_INDICATION">%1$s</xliff:g>\n<xliff:g id="POWER_INDICATION">%2$s</xliff:g>"</string>
<string name="hidden_notifications_title" msgid="1782412844777612795">"Λάβετε ειδοποιήσεις γρηγορότερα"</string>
<string name="hidden_notifications_text" msgid="5899627470450792578">"Εμφάνιση πριν το ξεκλείδωμα"</string>
<string name="hidden_notifications_cancel" msgid="4805370226181001278">"Όχι"</string>
@@ -1001,4 +1002,10 @@
<string name="controls_favorite_header_all" msgid="7507855973418969992">"Όλα"</string>
<string name="controls_favorite_load_error" msgid="2533215155804455348">"Ανεπιτυχής φόρτωση λίστας όλων των στοιχ. ελέγχου."</string>
<string name="controls_favorite_other_zone_header" msgid="9089613266575525252">"Άλλο"</string>
+ <!-- no translation found for controls_dialog_title (8806193219278278442) -->
+ <skip />
+ <!-- no translation found for controls_dialog_ok (7011816381344485651) -->
+ <skip />
+ <!-- no translation found for controls_dialog_message (6292099631702047540) -->
+ <skip />
</resources>
diff --git a/packages/SystemUI/res/values-en-rAU/strings.xml b/packages/SystemUI/res/values-en-rAU/strings.xml
index 98fcd53cdea5..c560b17a67b5 100644
--- a/packages/SystemUI/res/values-en-rAU/strings.xml
+++ b/packages/SystemUI/res/values-en-rAU/strings.xml
@@ -558,6 +558,7 @@
<string name="monitoring_description_app_personal_work" msgid="6175816356939166101">"Your work profile is managed by <xliff:g id="ORGANIZATION">%1$s</xliff:g>. The profile is connected to <xliff:g id="APPLICATION_WORK">%2$s</xliff:g>, which can monitor your work network activity, including emails, apps and websites.\n\nYou\'re also connected to <xliff:g id="APPLICATION_PERSONAL">%3$s</xliff:g>, which can monitor your personal network activity."</string>
<string name="keyguard_indication_trust_unlocked" msgid="7395154975733744547">"Kept unlocked by trust agent"</string>
<string name="keyguard_indication_trust_disabled" msgid="6820793704816727918">"Device will stay locked until you manually unlock"</string>
+ <string name="keyguard_indication_trust_unlocked_plugged_in" msgid="2323452175329362855">"<xliff:g id="KEYGUARD_INDICATION">%1$s</xliff:g>\n<xliff:g id="POWER_INDICATION">%2$s</xliff:g>"</string>
<string name="hidden_notifications_title" msgid="1782412844777612795">"Get notifications faster"</string>
<string name="hidden_notifications_text" msgid="5899627470450792578">"See them before you unlock"</string>
<string name="hidden_notifications_cancel" msgid="4805370226181001278">"No, thanks"</string>
@@ -1001,4 +1002,7 @@
<string name="controls_favorite_header_all" msgid="7507855973418969992">"All"</string>
<string name="controls_favorite_load_error" msgid="2533215155804455348">"The list of all controls could not be loaded."</string>
<string name="controls_favorite_other_zone_header" msgid="9089613266575525252">"Other"</string>
+ <string name="controls_dialog_title" msgid="8806193219278278442">"Add to Quick Controls"</string>
+ <string name="controls_dialog_ok" msgid="7011816381344485651">"Add to favourites"</string>
+ <string name="controls_dialog_message" msgid="6292099631702047540">"<xliff:g id="APP">%s</xliff:g> suggested this control to add to your favourites."</string>
</resources>
diff --git a/packages/SystemUI/res/values-en-rCA/strings.xml b/packages/SystemUI/res/values-en-rCA/strings.xml
index dbdff59f2a63..91d0d7468550 100644
--- a/packages/SystemUI/res/values-en-rCA/strings.xml
+++ b/packages/SystemUI/res/values-en-rCA/strings.xml
@@ -558,6 +558,7 @@
<string name="monitoring_description_app_personal_work" msgid="6175816356939166101">"Your work profile is managed by <xliff:g id="ORGANIZATION">%1$s</xliff:g>. The profile is connected to <xliff:g id="APPLICATION_WORK">%2$s</xliff:g>, which can monitor your work network activity, including emails, apps and websites.\n\nYou\'re also connected to <xliff:g id="APPLICATION_PERSONAL">%3$s</xliff:g>, which can monitor your personal network activity."</string>
<string name="keyguard_indication_trust_unlocked" msgid="7395154975733744547">"Kept unlocked by trust agent"</string>
<string name="keyguard_indication_trust_disabled" msgid="6820793704816727918">"Device will stay locked until you manually unlock"</string>
+ <string name="keyguard_indication_trust_unlocked_plugged_in" msgid="2323452175329362855">"<xliff:g id="KEYGUARD_INDICATION">%1$s</xliff:g>\n<xliff:g id="POWER_INDICATION">%2$s</xliff:g>"</string>
<string name="hidden_notifications_title" msgid="1782412844777612795">"Get notifications faster"</string>
<string name="hidden_notifications_text" msgid="5899627470450792578">"See them before you unlock"</string>
<string name="hidden_notifications_cancel" msgid="4805370226181001278">"No, thanks"</string>
@@ -1001,4 +1002,7 @@
<string name="controls_favorite_header_all" msgid="7507855973418969992">"All"</string>
<string name="controls_favorite_load_error" msgid="2533215155804455348">"The list of all controls could not be loaded."</string>
<string name="controls_favorite_other_zone_header" msgid="9089613266575525252">"Other"</string>
+ <string name="controls_dialog_title" msgid="8806193219278278442">"Add to Quick Controls"</string>
+ <string name="controls_dialog_ok" msgid="7011816381344485651">"Add to favourites"</string>
+ <string name="controls_dialog_message" msgid="6292099631702047540">"<xliff:g id="APP">%s</xliff:g> suggested this control to add to your favourites."</string>
</resources>
diff --git a/packages/SystemUI/res/values-en-rGB/strings.xml b/packages/SystemUI/res/values-en-rGB/strings.xml
index 98fcd53cdea5..c560b17a67b5 100644
--- a/packages/SystemUI/res/values-en-rGB/strings.xml
+++ b/packages/SystemUI/res/values-en-rGB/strings.xml
@@ -558,6 +558,7 @@
<string name="monitoring_description_app_personal_work" msgid="6175816356939166101">"Your work profile is managed by <xliff:g id="ORGANIZATION">%1$s</xliff:g>. The profile is connected to <xliff:g id="APPLICATION_WORK">%2$s</xliff:g>, which can monitor your work network activity, including emails, apps and websites.\n\nYou\'re also connected to <xliff:g id="APPLICATION_PERSONAL">%3$s</xliff:g>, which can monitor your personal network activity."</string>
<string name="keyguard_indication_trust_unlocked" msgid="7395154975733744547">"Kept unlocked by trust agent"</string>
<string name="keyguard_indication_trust_disabled" msgid="6820793704816727918">"Device will stay locked until you manually unlock"</string>
+ <string name="keyguard_indication_trust_unlocked_plugged_in" msgid="2323452175329362855">"<xliff:g id="KEYGUARD_INDICATION">%1$s</xliff:g>\n<xliff:g id="POWER_INDICATION">%2$s</xliff:g>"</string>
<string name="hidden_notifications_title" msgid="1782412844777612795">"Get notifications faster"</string>
<string name="hidden_notifications_text" msgid="5899627470450792578">"See them before you unlock"</string>
<string name="hidden_notifications_cancel" msgid="4805370226181001278">"No, thanks"</string>
@@ -1001,4 +1002,7 @@
<string name="controls_favorite_header_all" msgid="7507855973418969992">"All"</string>
<string name="controls_favorite_load_error" msgid="2533215155804455348">"The list of all controls could not be loaded."</string>
<string name="controls_favorite_other_zone_header" msgid="9089613266575525252">"Other"</string>
+ <string name="controls_dialog_title" msgid="8806193219278278442">"Add to Quick Controls"</string>
+ <string name="controls_dialog_ok" msgid="7011816381344485651">"Add to favourites"</string>
+ <string name="controls_dialog_message" msgid="6292099631702047540">"<xliff:g id="APP">%s</xliff:g> suggested this control to add to your favourites."</string>
</resources>
diff --git a/packages/SystemUI/res/values-en-rIN/strings.xml b/packages/SystemUI/res/values-en-rIN/strings.xml
index 98fcd53cdea5..c560b17a67b5 100644
--- a/packages/SystemUI/res/values-en-rIN/strings.xml
+++ b/packages/SystemUI/res/values-en-rIN/strings.xml
@@ -558,6 +558,7 @@
<string name="monitoring_description_app_personal_work" msgid="6175816356939166101">"Your work profile is managed by <xliff:g id="ORGANIZATION">%1$s</xliff:g>. The profile is connected to <xliff:g id="APPLICATION_WORK">%2$s</xliff:g>, which can monitor your work network activity, including emails, apps and websites.\n\nYou\'re also connected to <xliff:g id="APPLICATION_PERSONAL">%3$s</xliff:g>, which can monitor your personal network activity."</string>
<string name="keyguard_indication_trust_unlocked" msgid="7395154975733744547">"Kept unlocked by trust agent"</string>
<string name="keyguard_indication_trust_disabled" msgid="6820793704816727918">"Device will stay locked until you manually unlock"</string>
+ <string name="keyguard_indication_trust_unlocked_plugged_in" msgid="2323452175329362855">"<xliff:g id="KEYGUARD_INDICATION">%1$s</xliff:g>\n<xliff:g id="POWER_INDICATION">%2$s</xliff:g>"</string>
<string name="hidden_notifications_title" msgid="1782412844777612795">"Get notifications faster"</string>
<string name="hidden_notifications_text" msgid="5899627470450792578">"See them before you unlock"</string>
<string name="hidden_notifications_cancel" msgid="4805370226181001278">"No, thanks"</string>
@@ -1001,4 +1002,7 @@
<string name="controls_favorite_header_all" msgid="7507855973418969992">"All"</string>
<string name="controls_favorite_load_error" msgid="2533215155804455348">"The list of all controls could not be loaded."</string>
<string name="controls_favorite_other_zone_header" msgid="9089613266575525252">"Other"</string>
+ <string name="controls_dialog_title" msgid="8806193219278278442">"Add to Quick Controls"</string>
+ <string name="controls_dialog_ok" msgid="7011816381344485651">"Add to favourites"</string>
+ <string name="controls_dialog_message" msgid="6292099631702047540">"<xliff:g id="APP">%s</xliff:g> suggested this control to add to your favourites."</string>
</resources>
diff --git a/packages/SystemUI/res/values-en-rXC/strings.xml b/packages/SystemUI/res/values-en-rXC/strings.xml
index 8b6a7eb07881..4c83c13f7cff 100644
--- a/packages/SystemUI/res/values-en-rXC/strings.xml
+++ b/packages/SystemUI/res/values-en-rXC/strings.xml
@@ -558,6 +558,7 @@
<string name="monitoring_description_app_personal_work" msgid="6175816356939166101">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‎‏‎‏‎‏‏‎‏‏‎‏‎‎‏‏‏‎‏‎‎‎‎‏‎‎‎‎‎‏‎‏‏‏‏‎‎‏‎‏‏‎‎‏‏‏‏‏‏‏‎‎‎‏‏‎‎‏‎‏‎‏‎Your work profile is managed by ‎‏‎‎‏‏‎<xliff:g id="ORGANIZATION">%1$s</xliff:g>‎‏‎‎‏‏‏‎. The profile is connected to ‎‏‎‎‏‏‎<xliff:g id="APPLICATION_WORK">%2$s</xliff:g>‎‏‎‎‏‏‏‎, which can monitor your work network activity, including emails, apps, and websites.‎‏‎‎‏‏‎\n‎‏‎‎‏‏‏‎‎‏‎‎‏‏‎\n‎‏‎‎‏‏‏‎You\'re also connected to ‎‏‎‎‏‏‎<xliff:g id="APPLICATION_PERSONAL">%3$s</xliff:g>‎‏‎‎‏‏‏‎, which can monitor your personal network activity.‎‏‎‎‏‎"</string>
<string name="keyguard_indication_trust_unlocked" msgid="7395154975733744547">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‏‎‎‏‏‎‏‎‏‎‎‎‎‎‏‏‎‏‏‏‏‎‎‏‎‎‎‏‎‎‏‏‏‎‏‎‏‏‏‎‎‏‎‎‏‎‏‎‎‎‎‎‏‏‏‎‏‎‎‎‏‏‎Kept unlocked by TrustAgent‎‏‎‎‏‎"</string>
<string name="keyguard_indication_trust_disabled" msgid="6820793704816727918">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‎‏‏‏‏‎‏‎‏‎‏‎‎‎‎‏‎‏‎‎‏‏‏‎‏‏‏‏‎‎‏‎‎‎‎‏‎‏‏‏‎‏‎‎‏‎‎‏‎‏‎‏‏‏‎‏‏‎‏‏‏‎‎Device will stay locked until you manually unlock‎‏‎‎‏‎"</string>
+ <string name="keyguard_indication_trust_unlocked_plugged_in" msgid="2323452175329362855">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‎‏‎‎‎‎‎‎‎‏‏‏‏‏‎‏‎‎‎‏‏‏‏‎‏‏‏‎‎‎‏‎‏‏‏‏‎‏‏‎‎‎‏‏‏‎‏‏‎‎‎‎‎‏‏‏‎‏‎‎‏‏‏‎‎‏‎‎‏‏‎<xliff:g id="KEYGUARD_INDICATION">%1$s</xliff:g>‎‏‎‎‏‏‏‎‎‏‎‎‏‏‎\n‎‏‎‎‏‏‏‎‎‏‎‎‏‏‎<xliff:g id="POWER_INDICATION">%2$s</xliff:g>‎‏‎‎‏‏‏‎‎‏‎‎‏‎"</string>
<string name="hidden_notifications_title" msgid="1782412844777612795">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‎‏‏‏‎‎‎‏‎‏‏‏‏‎‎‎‏‏‎‎‏‏‏‎‎‎‎‏‎‎‏‏‏‏‎‏‎‎‎‎‎‎‏‎‎‎‎‎‎‏‎‎‏‎‏‏‏‏‏‏‎‏‏‎Get notifications faster‎‏‎‎‏‎"</string>
<string name="hidden_notifications_text" msgid="5899627470450792578">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‎‏‎‎‎‏‏‏‎‏‏‏‏‏‏‎‏‎‏‏‏‏‏‏‏‎‏‏‎‏‎‏‎‎‎‎‏‏‎‏‎‏‏‎‏‏‎‎‎‏‏‎‎‎‏‎‎‎‎‎‏‎‎See them before you unlock‎‏‎‎‏‎"</string>
<string name="hidden_notifications_cancel" msgid="4805370226181001278">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‎‎‎‎‏‎‏‎‏‏‎‎‎‎‎‎‎‏‏‎‏‎‏‏‎‎‎‎‏‎‏‏‎‎‎‎‎‏‏‏‎‎‎‎‎‏‏‏‎‏‎‎‎‎‎‎‏‏‏‏‏‎‎No thanks‎‏‎‎‏‎"</string>
@@ -1001,4 +1002,7 @@
<string name="controls_favorite_header_all" msgid="7507855973418969992">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‏‎‏‎‎‎‎‎‏‏‎‎‎‏‎‏‎‎‎‎‏‏‎‎‏‏‏‎‏‎‏‏‎‎‎‎‎‎‎‏‏‎‏‏‏‎‏‎‏‎‏‎‏‏‏‎‎‎‏‎‎‎‎All‎‏‎‎‏‎"</string>
<string name="controls_favorite_load_error" msgid="2533215155804455348">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‎‏‎‎‎‏‏‎‎‏‎‎‏‏‏‏‏‎‎‏‎‎‏‏‏‎‎‎‎‏‏‎‎‏‏‏‏‎‏‎‏‎‏‏‏‎‎‎‏‎‎‎‎‎‏‏‎‏‏‎‏‎‎‎The list of all controls could not be loaded.‎‏‎‎‏‎"</string>
<string name="controls_favorite_other_zone_header" msgid="9089613266575525252">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‏‏‏‏‏‎‎‎‏‎‎‏‎‎‏‏‎‎‏‎‏‏‎‎‎‏‏‎‏‏‎‏‏‎‏‎‏‏‏‏‏‎‏‎‎‏‏‎‎‎‎‏‎‏‏‎‎‎‎‏‎‎‎Other‎‏‎‎‏‎"</string>
+ <string name="controls_dialog_title" msgid="8806193219278278442">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‏‏‏‎‏‎‎‎‏‏‎‏‎‏‏‏‏‎‎‎‏‎‎‎‎‏‎‎‏‏‎‏‏‎‎‎‏‎‏‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‎‎‏‎‏‎‏‎‎Add to Quick Controls‎‏‎‎‏‎"</string>
+ <string name="controls_dialog_ok" msgid="7011816381344485651">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‏‎‎‎‎‏‎‏‎‎‏‏‏‎‏‏‏‏‏‎‎‏‏‏‎‏‏‎‎‏‎‏‎‎‎‎‎‎‎‏‎‎‏‏‎‏‏‎‎‏‎‎‎‏‎‎‎‏‎‎‏‏‎Add to favorites‎‏‎‎‏‎"</string>
+ <string name="controls_dialog_message" msgid="6292099631702047540">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‎‏‎‏‏‏‎‏‎‏‎‎‏‎‎‎‎‎‎‏‏‏‎‏‎‎‎‏‏‏‎‎‏‎‏‏‏‎‏‏‏‏‎‏‏‏‎‏‏‏‏‎‏‏‎‎‏‏‎‏‎‎‎‎‏‎‎‏‏‎<xliff:g id="APP">%s</xliff:g>‎‏‎‎‏‏‏‎ suggested this control to add to your favorites.‎‏‎‎‏‎"</string>
</resources>
diff --git a/packages/SystemUI/res/values-es-rUS/strings.xml b/packages/SystemUI/res/values-es-rUS/strings.xml
index f5c780889934..979e4abdd1ad 100644
--- a/packages/SystemUI/res/values-es-rUS/strings.xml
+++ b/packages/SystemUI/res/values-es-rUS/strings.xml
@@ -558,6 +558,7 @@
<string name="monitoring_description_app_personal_work" msgid="6175816356939166101">"<xliff:g id="ORGANIZATION">%1$s</xliff:g> administra tu perfil de red. El perfil está conectado a <xliff:g id="APPLICATION_WORK">%2$s</xliff:g>, que puede controlar tu actividad de red de trabajo, incluidos los correos electrónicos, las apps y los sitios web.\n\nTambién estás conectado a <xliff:g id="APPLICATION_PERSONAL">%3$s</xliff:g>, que puede controlar tu actividad de red personal."</string>
<string name="keyguard_indication_trust_unlocked" msgid="7395154975733744547">"TrustAgent lo mantiene desbloqueado"</string>
<string name="keyguard_indication_trust_disabled" msgid="6820793704816727918">"El dispositivo permanecerá bloqueado hasta que lo desbloquees manualmente."</string>
+ <string name="keyguard_indication_trust_unlocked_plugged_in" msgid="2323452175329362855">"<xliff:g id="KEYGUARD_INDICATION">%1$s</xliff:g>\n<xliff:g id="POWER_INDICATION">%2$s</xliff:g>"</string>
<string name="hidden_notifications_title" msgid="1782412844777612795">"Recibe notificaciones más rápido"</string>
<string name="hidden_notifications_text" msgid="5899627470450792578">"Ver antes de desbloquear"</string>
<string name="hidden_notifications_cancel" msgid="4805370226181001278">"No, gracias"</string>
@@ -979,12 +980,9 @@
<string name="bubble_accessibility_action_move_bottom_left" msgid="6339015902495504715">"Ubicar abajo a la izquierda"</string>
<string name="bubble_accessibility_action_move_bottom_right" msgid="7471571700628346212">"Ubicar abajo a la derecha"</string>
<string name="bubble_dismiss_text" msgid="7071770411580452911">"Ignorar"</string>
- <!-- no translation found for bubbles_user_education_title (3385222165904578710) -->
- <skip />
- <!-- no translation found for bubbles_user_education_description (6663205638091146934) -->
- <skip />
- <!-- no translation found for bubbles_user_education_manage (1391639189507036423) -->
- <skip />
+ <string name="bubbles_user_education_title" msgid="3385222165904578710">"Mantener los chats a la vista"</string>
+ <string name="bubbles_user_education_description" msgid="6663205638091146934">"Los chats nuevos de <xliff:g id="APP_NAME">%1$s</xliff:g> se mostrarán como burbujas. Presiona una burbuja para abrirla. Arrástrala para moverla.\n\nPresiona la burbuja"</string>
+ <string name="bubbles_user_education_manage" msgid="1391639189507036423">"Presiona Administrar para desactivar las burbujas de esta app"</string>
<string name="notification_content_system_nav_changed" msgid="5077913144844684544">"Se actualizó el sistema de navegación. Para hacer cambios, ve a Configuración."</string>
<string name="notification_content_gesture_nav_available" msgid="4431460803004659888">"Ve a Configuración para actualizar la navegación del sistema"</string>
<string name="inattentive_sleep_warning_title" msgid="3891371591713990373">"En espera"</string>
@@ -1004,4 +1002,10 @@
<string name="controls_favorite_header_all" msgid="7507855973418969992">"Todo"</string>
<string name="controls_favorite_load_error" msgid="2533215155804455348">"No se cargó la lista completa de controles."</string>
<string name="controls_favorite_other_zone_header" msgid="9089613266575525252">"Otros"</string>
+ <!-- no translation found for controls_dialog_title (8806193219278278442) -->
+ <skip />
+ <!-- no translation found for controls_dialog_ok (7011816381344485651) -->
+ <skip />
+ <!-- no translation found for controls_dialog_message (6292099631702047540) -->
+ <skip />
</resources>
diff --git a/packages/SystemUI/res/values-es/strings.xml b/packages/SystemUI/res/values-es/strings.xml
index 85af824caa53..c58ec87453a7 100644
--- a/packages/SystemUI/res/values-es/strings.xml
+++ b/packages/SystemUI/res/values-es/strings.xml
@@ -558,6 +558,7 @@
<string name="monitoring_description_app_personal_work" msgid="6175816356939166101">"<xliff:g id="ORGANIZATION">%1$s</xliff:g> gestiona tu perfil de trabajo. El perfil está conectado a <xliff:g id="APPLICATION_WORK">%2$s</xliff:g>, que puede supervisar tu actividad de red profesional, como los correos electrónicos, las aplicaciones y los sitios web.\n\nTambién te has conectado a <xliff:g id="APPLICATION_PERSONAL">%3$s</xliff:g>, que puede supervisar tu actividad de red personal."</string>
<string name="keyguard_indication_trust_unlocked" msgid="7395154975733744547">"Desbloqueado por TrustAgent"</string>
<string name="keyguard_indication_trust_disabled" msgid="6820793704816727918">"El dispositivo permanecerá bloqueado hasta que se desbloquee manualmente"</string>
+ <string name="keyguard_indication_trust_unlocked_plugged_in" msgid="2323452175329362855">"<xliff:g id="KEYGUARD_INDICATION">%1$s</xliff:g>\n<xliff:g id="POWER_INDICATION">%2$s</xliff:g>"</string>
<string name="hidden_notifications_title" msgid="1782412844777612795">"Recibe notificaciones más rápido"</string>
<string name="hidden_notifications_text" msgid="5899627470450792578">"Ver antes de desbloquear"</string>
<string name="hidden_notifications_cancel" msgid="4805370226181001278">"No, gracias"</string>
@@ -979,12 +980,9 @@
<string name="bubble_accessibility_action_move_bottom_left" msgid="6339015902495504715">"Mover abajo a la izquierda."</string>
<string name="bubble_accessibility_action_move_bottom_right" msgid="7471571700628346212">"Mover abajo a la derecha"</string>
<string name="bubble_dismiss_text" msgid="7071770411580452911">"Cerrar"</string>
- <!-- no translation found for bubbles_user_education_title (3385222165904578710) -->
- <skip />
- <!-- no translation found for bubbles_user_education_description (6663205638091146934) -->
- <skip />
- <!-- no translation found for bubbles_user_education_manage (1391639189507036423) -->
- <skip />
+ <string name="bubbles_user_education_title" msgid="3385222165904578710">"Mantén los chats a la vista"</string>
+ <string name="bubbles_user_education_description" msgid="6663205638091146934">"Los nuevos chats de <xliff:g id="APP_NAME">%1$s</xliff:g> se mostrarán como burbujas. Toca una burbuja para abrirla. Arrástrala para moverla.\n\nToca la burbuja"</string>
+ <string name="bubbles_user_education_manage" msgid="1391639189507036423">"Toca Gestionar para desactivar las burbujas de esta aplicación"</string>
<string name="notification_content_system_nav_changed" msgid="5077913144844684544">"Se ha actualizado la navegación del sistema. Para hacer cambios, ve a Ajustes."</string>
<string name="notification_content_gesture_nav_available" msgid="4431460803004659888">"Ve a Ajustes para actualizar la navegación del sistema"</string>
<string name="inattentive_sleep_warning_title" msgid="3891371591713990373">"En espera"</string>
@@ -1004,4 +1002,10 @@
<string name="controls_favorite_header_all" msgid="7507855973418969992">"Todos"</string>
<string name="controls_favorite_load_error" msgid="2533215155804455348">"No se ha podido cargar la lista de los controles."</string>
<string name="controls_favorite_other_zone_header" msgid="9089613266575525252">"Otros"</string>
+ <!-- no translation found for controls_dialog_title (8806193219278278442) -->
+ <skip />
+ <!-- no translation found for controls_dialog_ok (7011816381344485651) -->
+ <skip />
+ <!-- no translation found for controls_dialog_message (6292099631702047540) -->
+ <skip />
</resources>
diff --git a/packages/SystemUI/res/values-et/strings.xml b/packages/SystemUI/res/values-et/strings.xml
index 548076d4d925..bb15e29dd783 100644
--- a/packages/SystemUI/res/values-et/strings.xml
+++ b/packages/SystemUI/res/values-et/strings.xml
@@ -558,6 +558,7 @@
<string name="monitoring_description_app_personal_work" msgid="6175816356939166101">"Teie tööprofiili haldab <xliff:g id="ORGANIZATION">%1$s</xliff:g>. Profiil on ühendatud rakendusega <xliff:g id="APPLICATION_WORK">%2$s</xliff:g>, mis saab jälgida teie töökoha võrgutegevusi, sh meile, rakendusi ja veebisaite.\n\nOlete ühendatud ka rakendusega <xliff:g id="APPLICATION_PERSONAL">%3$s</xliff:g>, mis saab jälgida teie isiklikke võrgutegevusi."</string>
<string name="keyguard_indication_trust_unlocked" msgid="7395154975733744547">"Avatuna hoiab TrustAgent"</string>
<string name="keyguard_indication_trust_disabled" msgid="6820793704816727918">"Seade jääb lukku, kuni selle käsitsi avate"</string>
+ <string name="keyguard_indication_trust_unlocked_plugged_in" msgid="2323452175329362855">"<xliff:g id="KEYGUARD_INDICATION">%1$s</xliff:g>\n<xliff:g id="POWER_INDICATION">%2$s</xliff:g>"</string>
<string name="hidden_notifications_title" msgid="1782412844777612795">"Saate märguandeid kiiremini"</string>
<string name="hidden_notifications_text" msgid="5899627470450792578">"Näete neid enne avamist"</string>
<string name="hidden_notifications_cancel" msgid="4805370226181001278">"Tänan, ei"</string>
@@ -979,12 +980,9 @@
<string name="bubble_accessibility_action_move_bottom_left" msgid="6339015902495504715">"Teisalda alla vasakule"</string>
<string name="bubble_accessibility_action_move_bottom_right" msgid="7471571700628346212">"Teisalda alla paremale"</string>
<string name="bubble_dismiss_text" msgid="7071770411580452911">"Loobu"</string>
- <!-- no translation found for bubbles_user_education_title (3385222165904578710) -->
- <skip />
- <!-- no translation found for bubbles_user_education_description (6663205638091146934) -->
- <skip />
- <!-- no translation found for bubbles_user_education_manage (1391639189507036423) -->
- <skip />
+ <string name="bubbles_user_education_title" msgid="3385222165904578710">"Hoia vestlused esiplaanil"</string>
+ <string name="bubbles_user_education_description" msgid="6663205638091146934">"Uued vestlused rakendusest <xliff:g id="APP_NAME">%1$s</xliff:g> kuvatakse mullidena. Selle avamiseks puudutage mulli. Teisaldamiseks lohistage.\n\nPuudutage mulli"</string>
+ <string name="bubbles_user_education_manage" msgid="1391639189507036423">"Selle rakenduse puhul mullide väljalülitamiseks puudutage valikut Haldamine"</string>
<string name="notification_content_system_nav_changed" msgid="5077913144844684544">"Süsteemis navigeerimine on värskendatud. Muutmiseks avage jaotis Seaded."</string>
<string name="notification_content_gesture_nav_available" msgid="4431460803004659888">"Süsteemi navigeerimise värskendamiseks avage jaotis Seaded"</string>
<string name="inattentive_sleep_warning_title" msgid="3891371591713990373">"Ooterežiim"</string>
@@ -1004,4 +1002,10 @@
<string name="controls_favorite_header_all" msgid="7507855973418969992">"Kõik"</string>
<string name="controls_favorite_load_error" msgid="2533215155804455348">"Kõikide juhtelementide loendit ei saanud laadida."</string>
<string name="controls_favorite_other_zone_header" msgid="9089613266575525252">"Muu"</string>
+ <!-- no translation found for controls_dialog_title (8806193219278278442) -->
+ <skip />
+ <!-- no translation found for controls_dialog_ok (7011816381344485651) -->
+ <skip />
+ <!-- no translation found for controls_dialog_message (6292099631702047540) -->
+ <skip />
</resources>
diff --git a/packages/SystemUI/res/values-eu/strings.xml b/packages/SystemUI/res/values-eu/strings.xml
index 380b7523127e..5961e5219a5f 100644
--- a/packages/SystemUI/res/values-eu/strings.xml
+++ b/packages/SystemUI/res/values-eu/strings.xml
@@ -558,6 +558,7 @@
<string name="monitoring_description_app_personal_work" msgid="6175816356939166101">"<xliff:g id="ORGANIZATION">%1$s</xliff:g> erakundeak kudeatzen dizu laneko profila. <xliff:g id="APPLICATION_WORK">%2$s</xliff:g> aplikaziora dago konektatuta profila, eta aplikazio horrek sarean egiten dituzun jarduerak kontrola ditzake, mezu elektronikoak, aplikazioak eta webguneak barne. \n\n<xliff:g id="APPLICATION_PERSONAL">%3$s</xliff:g> aplikaziora ere zaude konektatuta, eta hark sare pertsonalean egiten dituzun jarduerak kontrola ditzake."</string>
<string name="keyguard_indication_trust_unlocked" msgid="7395154975733744547">"TrustAgent bidez desblokeatuta"</string>
<string name="keyguard_indication_trust_disabled" msgid="6820793704816727918">"Gailua blokeatuta egongo da eskuz desblokeatu arte"</string>
+ <string name="keyguard_indication_trust_unlocked_plugged_in" msgid="2323452175329362855">"<xliff:g id="KEYGUARD_INDICATION">%1$s</xliff:g>\n<xliff:g id="POWER_INDICATION">%2$s</xliff:g>"</string>
<string name="hidden_notifications_title" msgid="1782412844777612795">"Eskuratu jakinarazpenak azkarrago"</string>
<string name="hidden_notifications_text" msgid="5899627470450792578">"Ikusi desblokeatu baino lehen"</string>
<string name="hidden_notifications_cancel" msgid="4805370226181001278">"Ez, eskerrik asko"</string>
@@ -979,12 +980,9 @@
<string name="bubble_accessibility_action_move_bottom_left" msgid="6339015902495504715">"Eraman behealdera, ezkerretara"</string>
<string name="bubble_accessibility_action_move_bottom_right" msgid="7471571700628346212">"Eraman behealdera, eskuinetara"</string>
<string name="bubble_dismiss_text" msgid="7071770411580452911">"Baztertu"</string>
- <!-- no translation found for bubbles_user_education_title (3385222165904578710) -->
- <skip />
- <!-- no translation found for bubbles_user_education_description (6663205638091146934) -->
- <skip />
- <!-- no translation found for bubbles_user_education_manage (1391639189507036423) -->
- <skip />
+ <string name="bubbles_user_education_title" msgid="3385222165904578710">"Utzi txatak aurrealdean"</string>
+ <string name="bubbles_user_education_description" msgid="6663205638091146934">"<xliff:g id="APP_NAME">%1$s</xliff:g> aplikazioaren txat berriak burbuila gisa agertuko dira. Burbuilak irekitzeko, saka itzazu. Mugitzeko, berriz, arrasta itzazu.\n\nSakatu burbuila"</string>
+ <string name="bubbles_user_education_manage" msgid="1391639189507036423">"Aplikazioaren burbuilak desaktibatzeko, sakatu Kudeatu"</string>
<string name="notification_content_system_nav_changed" msgid="5077913144844684544">"Eguneratu da sistemaren nabigazioa. Aldaketak egiteko, joan Ezarpenak atalera."</string>
<string name="notification_content_gesture_nav_available" msgid="4431460803004659888">"Sistemaren nabigazioa eguneratzeko, joan Ezarpenak atalera"</string>
<string name="inattentive_sleep_warning_title" msgid="3891371591713990373">"Egonean"</string>
@@ -1004,4 +1002,10 @@
<string name="controls_favorite_header_all" msgid="7507855973418969992">"Guztiak"</string>
<string name="controls_favorite_load_error" msgid="2533215155804455348">"Ezin izan da kargatu kontrol guztien zerrenda."</string>
<string name="controls_favorite_other_zone_header" msgid="9089613266575525252">"Beste bat"</string>
+ <!-- no translation found for controls_dialog_title (8806193219278278442) -->
+ <skip />
+ <!-- no translation found for controls_dialog_ok (7011816381344485651) -->
+ <skip />
+ <!-- no translation found for controls_dialog_message (6292099631702047540) -->
+ <skip />
</resources>
diff --git a/packages/SystemUI/res/values-fa/strings.xml b/packages/SystemUI/res/values-fa/strings.xml
index c7c033661d02..b2c0d2ec63a3 100644
--- a/packages/SystemUI/res/values-fa/strings.xml
+++ b/packages/SystemUI/res/values-fa/strings.xml
@@ -498,7 +498,7 @@
<string name="notification_section_header_conversations" msgid="821834744538345661">"مکالمه‌ها"</string>
<string name="accessibility_notification_section_header_gentle_clear_all" msgid="6490207897764933919">"پاک کردن همه اعلان‌های بی‌صدا"</string>
<string name="dnd_suppressing_shade_text" msgid="5588252250634464042">"اعلان‌ها توسط «مزاحم نشوید» موقتاً متوقف شدند"</string>
- <string name="media_projection_action_text" msgid="3634906766918186440">"اکنون شروع شود"</string>
+ <string name="media_projection_action_text" msgid="3634906766918186440">"اکنون شروع کنید"</string>
<string name="empty_shade_text" msgid="8935967157319717412">"اعلانی موجود نیست"</string>
<string name="profile_owned_footer" msgid="2756770645766113964">"شاید نمایه کنترل شود"</string>
<string name="vpn_footer" msgid="3457155078010607471">"ممکن است شبکه کنترل شود"</string>
@@ -558,6 +558,7 @@
<string name="monitoring_description_app_personal_work" msgid="6175816356939166101">"نمایه کاری‌تان توسط <xliff:g id="ORGANIZATION">%1$s</xliff:g> مدیریت می‌شود. این نمایه به <xliff:g id="APPLICATION_WORK">%2$s</xliff:g> متصل است که می‌تواند تنظیمات، دسترسی شرکتی، برنامه‌ها، داده‌های مرتبط با دستگاه و اطلاعات مکان دستگاه شما را پایش کند.\n\nشما همچنین به <xliff:g id="APPLICATION_PERSONAL">%3$s</xliff:g> متصل هستید که می‌تواند فعالیت خصوصی شما را در شبکه پایش کند."</string>
<string name="keyguard_indication_trust_unlocked" msgid="7395154975733744547">"‏با TrustAgent قفل را باز نگه‌دارید"</string>
<string name="keyguard_indication_trust_disabled" msgid="6820793704816727918">"دستگاه قفل باقی می‌ماند تا زمانی که قفل آن را به صورت دستی باز کنید"</string>
+ <string name="keyguard_indication_trust_unlocked_plugged_in" msgid="2323452175329362855">"<xliff:g id="KEYGUARD_INDICATION">%1$s</xliff:g>\n<xliff:g id="POWER_INDICATION">%2$s</xliff:g>"</string>
<string name="hidden_notifications_title" msgid="1782412844777612795">"دریافت سریع‌تر اعلان‌ها"</string>
<string name="hidden_notifications_text" msgid="5899627470450792578">"قبل از باز کردن قفل آنها را مشاهده کنید"</string>
<string name="hidden_notifications_cancel" msgid="4805370226181001278">"نه متشکرم"</string>
@@ -979,12 +980,9 @@
<string name="bubble_accessibility_action_move_bottom_left" msgid="6339015902495504715">"انتقال به پایین سمت راست"</string>
<string name="bubble_accessibility_action_move_bottom_right" msgid="7471571700628346212">"انتقال به پایین سمت چپ"</string>
<string name="bubble_dismiss_text" msgid="7071770411580452911">"رد کردن"</string>
- <!-- no translation found for bubbles_user_education_title (3385222165904578710) -->
- <skip />
- <!-- no translation found for bubbles_user_education_description (6663205638091146934) -->
- <skip />
- <!-- no translation found for bubbles_user_education_manage (1391639189507036423) -->
- <skip />
+ <string name="bubbles_user_education_title" msgid="3385222165904578710">"نگه داشتن گپ‌ها در جلو"</string>
+ <string name="bubbles_user_education_description" msgid="6663205638091146934">"گپ‌های جدید از <xliff:g id="APP_NAME">%1$s</xliff:g> به‌صورت «حباب» نمایش داده می‌شوند. روی «حباب» ضربه بزنید تا باز شود. آن را بکشید تا جابه‌جا شود.\n\nروی «حباب» ضربه بزنید"</string>
+ <string name="bubbles_user_education_manage" msgid="1391639189507036423">"برای خاموش کردن «حباب‌ها» از این برنامه، روی «مدیریت» ضربه بزنید"</string>
<string name="notification_content_system_nav_changed" msgid="5077913144844684544">"پیمایش سیستم به‌روزرسانی شد. برای انجام تغییرات به «تنظیمات» بروید."</string>
<string name="notification_content_gesture_nav_available" msgid="4431460803004659888">"برای به‌روزرسانی پیمایش سیستم، به «تنظیمات» بروید"</string>
<string name="inattentive_sleep_warning_title" msgid="3891371591713990373">"آماده‌به‌کار"</string>
@@ -1004,4 +1002,10 @@
<string name="controls_favorite_header_all" msgid="7507855973418969992">"همه"</string>
<string name="controls_favorite_load_error" msgid="2533215155804455348">"فهرست همه کنترل‌ها را نمی‌توان بارگیری کرد."</string>
<string name="controls_favorite_other_zone_header" msgid="9089613266575525252">"موارد دیگر"</string>
+ <!-- no translation found for controls_dialog_title (8806193219278278442) -->
+ <skip />
+ <!-- no translation found for controls_dialog_ok (7011816381344485651) -->
+ <skip />
+ <!-- no translation found for controls_dialog_message (6292099631702047540) -->
+ <skip />
</resources>
diff --git a/packages/SystemUI/res/values-fi/strings.xml b/packages/SystemUI/res/values-fi/strings.xml
index 0daab9e253cd..86c6e7c078cb 100644
--- a/packages/SystemUI/res/values-fi/strings.xml
+++ b/packages/SystemUI/res/values-fi/strings.xml
@@ -558,6 +558,7 @@
<string name="monitoring_description_app_personal_work" msgid="6175816356939166101">"<xliff:g id="ORGANIZATION">%1$s</xliff:g> hallinnoi työprofiiliasi. Se on yhteydessä sovellukseen <xliff:g id="APPLICATION_WORK">%2$s</xliff:g>, joka voi valvoa toimintaasi verkossa, esimerkiksi sähköposteja, sovelluksia ja verkkosivustoja.\n\nLisäksi olet yhteydessä sovellukseen <xliff:g id="APPLICATION_PERSONAL">%3$s</xliff:g>, joka voi valvoa henkilökohtaista toimintaasi verkossa."</string>
<string name="keyguard_indication_trust_unlocked" msgid="7395154975733744547">"TrustAgent pitää lukitusta avattuna"</string>
<string name="keyguard_indication_trust_disabled" msgid="6820793704816727918">"Laite pysyy lukittuna, kunnes se avataan käsin"</string>
+ <string name="keyguard_indication_trust_unlocked_plugged_in" msgid="2323452175329362855">"<xliff:g id="KEYGUARD_INDICATION">%1$s</xliff:g>\n<xliff:g id="POWER_INDICATION">%2$s</xliff:g>"</string>
<string name="hidden_notifications_title" msgid="1782412844777612795">"Näe ilmoitukset nopeammin"</string>
<string name="hidden_notifications_text" msgid="5899627470450792578">"Näytä ennen lukituksen avaamista"</string>
<string name="hidden_notifications_cancel" msgid="4805370226181001278">"Ei kiitos"</string>
@@ -979,12 +980,9 @@
<string name="bubble_accessibility_action_move_bottom_left" msgid="6339015902495504715">"Siirrä vasempaan alareunaan"</string>
<string name="bubble_accessibility_action_move_bottom_right" msgid="7471571700628346212">"Siirrä oikeaan alareunaan"</string>
<string name="bubble_dismiss_text" msgid="7071770411580452911">"Ohita"</string>
- <!-- no translation found for bubbles_user_education_title (3385222165904578710) -->
- <skip />
- <!-- no translation found for bubbles_user_education_description (6663205638091146934) -->
- <skip />
- <!-- no translation found for bubbles_user_education_manage (1391639189507036423) -->
- <skip />
+ <string name="bubbles_user_education_title" msgid="3385222165904578710">"Säilytä chatit etualalla"</string>
+ <string name="bubbles_user_education_description" msgid="6663205638091146934">"Sovelluksen <xliff:g id="APP_NAME">%1$s</xliff:g> uudet chatit näkyvät ohjekuplina. Kosketa ohjekuplaa avataksesi sen. Siirrä sitä vetämällä.\n\n Kosketa ohjekuplaa."</string>
+ <string name="bubbles_user_education_manage" msgid="1391639189507036423">"Valitse Hallinnoi, jos haluat poistaa ohjekuplat käytöstä tästä sovelluksesta"</string>
<string name="notification_content_system_nav_changed" msgid="5077913144844684544">"Järjestelmän navigointitapa vaihdettu. Voit muuttaa sitä asetuksista."</string>
<string name="notification_content_gesture_nav_available" msgid="4431460803004659888">"Vaihda järjestelmän navigointitapaa asetuksista"</string>
<string name="inattentive_sleep_warning_title" msgid="3891371591713990373">"Virransäästötila"</string>
@@ -1004,4 +1002,10 @@
<string name="controls_favorite_header_all" msgid="7507855973418969992">"Kaikki"</string>
<string name="controls_favorite_load_error" msgid="2533215155804455348">"Kaikkien säätimien luetteloa ei voitu ladata."</string>
<string name="controls_favorite_other_zone_header" msgid="9089613266575525252">"Muu"</string>
+ <!-- no translation found for controls_dialog_title (8806193219278278442) -->
+ <skip />
+ <!-- no translation found for controls_dialog_ok (7011816381344485651) -->
+ <skip />
+ <!-- no translation found for controls_dialog_message (6292099631702047540) -->
+ <skip />
</resources>
diff --git a/packages/SystemUI/res/values-fr-rCA/strings.xml b/packages/SystemUI/res/values-fr-rCA/strings.xml
index cc9b7c23d766..2c5da714557a 100644
--- a/packages/SystemUI/res/values-fr-rCA/strings.xml
+++ b/packages/SystemUI/res/values-fr-rCA/strings.xml
@@ -558,6 +558,7 @@
<string name="monitoring_description_app_personal_work" msgid="6175816356939166101">"Votre profil professionnel est géré par <xliff:g id="ORGANIZATION">%1$s</xliff:g>. Ce profil est connecté à <xliff:g id="APPLICATION_WORK">%2$s</xliff:g>, qui peut contrôler votre activité professionnelle sur le réseau, y compris l\'activité relative aux courriels, aux applications et aux sites Web.\n\nVous êtes également connecté à <xliff:g id="APPLICATION_PERSONAL">%3$s</xliff:g>, qui peut contrôler votre activité personnelle sur le réseau."</string>
<string name="keyguard_indication_trust_unlocked" msgid="7395154975733744547">"Maintenu déverrouillé par TrustAgent"</string>
<string name="keyguard_indication_trust_disabled" msgid="6820793704816727918">"L\'appareil restera verrouillé jusqu\'à ce que vous le déverrouilliez manuellement"</string>
+ <string name="keyguard_indication_trust_unlocked_plugged_in" msgid="2323452175329362855">"<xliff:g id="KEYGUARD_INDICATION">%1$s</xliff:g>\n<xliff:g id="POWER_INDICATION">%2$s</xliff:g>"</string>
<string name="hidden_notifications_title" msgid="1782412844777612795">"Voir les notifications plus rapidement"</string>
<string name="hidden_notifications_text" msgid="5899627470450792578">"Afficher les notifications avant de déverrouiller l\'appareil"</string>
<string name="hidden_notifications_cancel" msgid="4805370226181001278">"Non, merci"</string>
@@ -979,12 +980,9 @@
<string name="bubble_accessibility_action_move_bottom_left" msgid="6339015902495504715">"Déplacer dans coin inf. gauche"</string>
<string name="bubble_accessibility_action_move_bottom_right" msgid="7471571700628346212">"Déplacer dans coin inf. droit"</string>
<string name="bubble_dismiss_text" msgid="7071770411580452911">"Fermer"</string>
- <!-- no translation found for bubbles_user_education_title (3385222165904578710) -->
- <skip />
- <!-- no translation found for bubbles_user_education_description (6663205638091146934) -->
- <skip />
- <!-- no translation found for bubbles_user_education_manage (1391639189507036423) -->
- <skip />
+ <string name="bubbles_user_education_title" msgid="3385222165904578710">"Garder les messages de clavardage à l\'avant"</string>
+ <string name="bubbles_user_education_description" msgid="6663205638091146934">"Les nouveaux messages de clavardage de <xliff:g id="APP_NAME">%1$s</xliff:g> s\'afficheront sous forme de bulles. Pour ouvrir une bulle, touchez-la. Pour la déplacer, faites-la glisser.\n\nTouchez la bulle"</string>
+ <string name="bubbles_user_education_manage" msgid="1391639189507036423">"Toucher Gérer pour désactiver les bulles de cette application"</string>
<string name="notification_content_system_nav_changed" msgid="5077913144844684544">"La navigation système a été mise à jour. Pour apporter des modifications, accédez au menu Paramètres."</string>
<string name="notification_content_gesture_nav_available" msgid="4431460803004659888">"Accédez au menu Paramètres pour mettre à jour la navigation système"</string>
<string name="inattentive_sleep_warning_title" msgid="3891371591713990373">"Veille"</string>
@@ -1004,4 +1002,10 @@
<string name="controls_favorite_header_all" msgid="7507855973418969992">"Tous"</string>
<string name="controls_favorite_load_error" msgid="2533215155804455348">"Impossible de charger la liste des commandes."</string>
<string name="controls_favorite_other_zone_header" msgid="9089613266575525252">"Autre"</string>
+ <!-- no translation found for controls_dialog_title (8806193219278278442) -->
+ <skip />
+ <!-- no translation found for controls_dialog_ok (7011816381344485651) -->
+ <skip />
+ <!-- no translation found for controls_dialog_message (6292099631702047540) -->
+ <skip />
</resources>
diff --git a/packages/SystemUI/res/values-fr/strings.xml b/packages/SystemUI/res/values-fr/strings.xml
index 26a4010c4be8..aebb52b13927 100644
--- a/packages/SystemUI/res/values-fr/strings.xml
+++ b/packages/SystemUI/res/values-fr/strings.xml
@@ -558,6 +558,7 @@
<string name="monitoring_description_app_personal_work" msgid="6175816356939166101">"Votre profil professionnel est géré par <xliff:g id="ORGANIZATION">%1$s</xliff:g>. Ce profil est connecté à <xliff:g id="APPLICATION_WORK">%2$s</xliff:g>, qui peut contrôler votre activité professionnelle sur le réseau, y compris l\'activité relative aux e-mails, aux applications et aux sites Web.\n\nVous êtes également connecté à <xliff:g id="APPLICATION_PERSONAL">%3$s</xliff:g>, qui peut contrôler votre activité personnelle sur le réseau."</string>
<string name="keyguard_indication_trust_unlocked" msgid="7395154975733744547">"Maintenu déverrouillé par TrustAgent"</string>
<string name="keyguard_indication_trust_disabled" msgid="6820793704816727918">"L\'appareil restera verrouillé jusqu\'à ce que vous le déverrouilliez manuellement."</string>
+ <string name="keyguard_indication_trust_unlocked_plugged_in" msgid="2323452175329362855">"<xliff:g id="KEYGUARD_INDICATION">%1$s</xliff:g>\n<xliff:g id="POWER_INDICATION">%2$s</xliff:g>"</string>
<string name="hidden_notifications_title" msgid="1782412844777612795">"Recevoir les notifications plus vite"</string>
<string name="hidden_notifications_text" msgid="5899627470450792578">"Afficher les notifications avant de déverrouiller l\'appareil"</string>
<string name="hidden_notifications_cancel" msgid="4805370226181001278">"Non, merci"</string>
@@ -979,12 +980,9 @@
<string name="bubble_accessibility_action_move_bottom_left" msgid="6339015902495504715">"Déplacer en bas à gauche"</string>
<string name="bubble_accessibility_action_move_bottom_right" msgid="7471571700628346212">"Déplacer en bas à droite"</string>
<string name="bubble_dismiss_text" msgid="7071770411580452911">"Ignorer"</string>
- <!-- no translation found for bubbles_user_education_title (3385222165904578710) -->
- <skip />
- <!-- no translation found for bubbles_user_education_description (6663205638091146934) -->
- <skip />
- <!-- no translation found for bubbles_user_education_manage (1391639189507036423) -->
- <skip />
+ <string name="bubbles_user_education_title" msgid="3385222165904578710">"Accédez rapidement à vos chats"</string>
+ <string name="bubbles_user_education_description" msgid="6663205638091146934">"Les nouveaux chats <xliff:g id="APP_NAME">%1$s</xliff:g> s\'afficheront sous forme de bulles. Appuyez sur une bulle pour l\'ouvrir. Faites-la glisser pour la déplacer.\n\nAppuyez sur la bulle"</string>
+ <string name="bubbles_user_education_manage" msgid="1391639189507036423">"Appuyez sur \"Gérer\" pour désactiver les bulles pour cette application"</string>
<string name="notification_content_system_nav_changed" msgid="5077913144844684544">"Navigation système mise à jour. Pour apporter des modifications, accédez aux paramètres."</string>
<string name="notification_content_gesture_nav_available" msgid="4431460803004659888">"Accédez aux paramètres pour mettre à jour la navigation système"</string>
<string name="inattentive_sleep_warning_title" msgid="3891371591713990373">"Mode Veille imminent"</string>
@@ -1004,4 +1002,10 @@
<string name="controls_favorite_header_all" msgid="7507855973418969992">"Tout"</string>
<string name="controls_favorite_load_error" msgid="2533215155804455348">"Impossible de charger toutes les commandes."</string>
<string name="controls_favorite_other_zone_header" msgid="9089613266575525252">"Autre"</string>
+ <!-- no translation found for controls_dialog_title (8806193219278278442) -->
+ <skip />
+ <!-- no translation found for controls_dialog_ok (7011816381344485651) -->
+ <skip />
+ <!-- no translation found for controls_dialog_message (6292099631702047540) -->
+ <skip />
</resources>
diff --git a/packages/SystemUI/res/values-gl/strings.xml b/packages/SystemUI/res/values-gl/strings.xml
index e1e8c76da1ad..7711742eb8f4 100644
--- a/packages/SystemUI/res/values-gl/strings.xml
+++ b/packages/SystemUI/res/values-gl/strings.xml
@@ -558,6 +558,7 @@
<string name="monitoring_description_app_personal_work" msgid="6175816356939166101">"<xliff:g id="ORGANIZATION">%1$s</xliff:g> xestiona o teu perfil de traballo, que está conectado a <xliff:g id="APPLICATION_WORK">%2$s</xliff:g>. Esta aplicación pode controlar a túa actividade na rede, mesmo os correos electrónicos, as aplicacións e os sitios web.\n\nTamén estás conectado a <xliff:g id="APPLICATION_PERSONAL">%3$s</xliff:g>, que pode controlar a túa actividade persoal na rede."</string>
<string name="keyguard_indication_trust_unlocked" msgid="7395154975733744547">"Desbloqueado por un axente de confianza"</string>
<string name="keyguard_indication_trust_disabled" msgid="6820793704816727918">"O dispositivo permanecerá bloqueado ata que o desbloquees manualmente"</string>
+ <string name="keyguard_indication_trust_unlocked_plugged_in" msgid="2323452175329362855">"<xliff:g id="KEYGUARD_INDICATION">%1$s</xliff:g>\n<xliff:g id="POWER_INDICATION">%2$s</xliff:g>"</string>
<string name="hidden_notifications_title" msgid="1782412844777612795">"Recibir notificacións máis rápido"</string>
<string name="hidden_notifications_text" msgid="5899627470450792578">"Consúltaas antes de desbloquear"</string>
<string name="hidden_notifications_cancel" msgid="4805370226181001278">"Non, grazas"</string>
@@ -979,12 +980,9 @@
<string name="bubble_accessibility_action_move_bottom_left" msgid="6339015902495504715">"Mover á parte infer. esquerda"</string>
<string name="bubble_accessibility_action_move_bottom_right" msgid="7471571700628346212">"Mover á parte inferior dereita"</string>
<string name="bubble_dismiss_text" msgid="7071770411580452911">"Ignorar"</string>
- <!-- no translation found for bubbles_user_education_title (3385222165904578710) -->
- <skip />
- <!-- no translation found for bubbles_user_education_description (6663205638091146934) -->
- <skip />
- <!-- no translation found for bubbles_user_education_manage (1391639189507036423) -->
- <skip />
+ <string name="bubbles_user_education_title" msgid="3385222165904578710">"Manter os chats á vista"</string>
+ <string name="bubbles_user_education_description" msgid="6663205638091146934">"Os chats novos de <xliff:g id="APP_NAME">%1$s</xliff:g> mostraranse como burbullas. Toca unha para abrila ou arrástraa para movela.\n\nToca a burbulla"</string>
+ <string name="bubbles_user_education_manage" msgid="1391639189507036423">"Para desactivar as burbullas nesta aplicación, toca Xestionar"</string>
<string name="notification_content_system_nav_changed" msgid="5077913144844684544">"Actualizouse a navegación do sistema. Para facer cambios, vai a Configuración."</string>
<string name="notification_content_gesture_nav_available" msgid="4431460803004659888">"Para actualizar a navegación do sistema, vai a Configuración"</string>
<string name="inattentive_sleep_warning_title" msgid="3891371591713990373">"Modo de espera"</string>
@@ -1004,4 +1002,10 @@
<string name="controls_favorite_header_all" msgid="7507855973418969992">"Todo"</string>
<string name="controls_favorite_load_error" msgid="2533215155804455348">"Non se puido cargar a lista de todos os controis."</string>
<string name="controls_favorite_other_zone_header" msgid="9089613266575525252">"Outra"</string>
+ <!-- no translation found for controls_dialog_title (8806193219278278442) -->
+ <skip />
+ <!-- no translation found for controls_dialog_ok (7011816381344485651) -->
+ <skip />
+ <!-- no translation found for controls_dialog_message (6292099631702047540) -->
+ <skip />
</resources>
diff --git a/packages/SystemUI/res/values-gu/strings.xml b/packages/SystemUI/res/values-gu/strings.xml
index b16362b63fd2..cb09ac92e4b3 100644
--- a/packages/SystemUI/res/values-gu/strings.xml
+++ b/packages/SystemUI/res/values-gu/strings.xml
@@ -558,6 +558,8 @@
<string name="monitoring_description_app_personal_work" msgid="6175816356939166101">"તમારી કાર્યાલયની પ્રોફાઇલ <xliff:g id="ORGANIZATION">%1$s</xliff:g> દ્વારા સંચાલિત થાય છે. આ પ્રોફાઇલ <xliff:g id="APPLICATION_WORK">%2$s</xliff:g> સાથે કનેક્ટ કરેલ છે, જે ઇમેઇલ, ઍપ્લિકેશનો અને વેબસાઇટો સહિતની તમારી નેટવર્ક પ્રવૃત્તિનું નિયમન કરી શકે છે.\n\nતમે <xliff:g id="APPLICATION_PERSONAL">%3$s</xliff:g> સાથે પણ કનેક્ટ કરેલું છે, જે તમારી વ્યક્તિગત નેટવર્ક પ્રવૃત્તિનું નિયમન કરી શકે છે."</string>
<string name="keyguard_indication_trust_unlocked" msgid="7395154975733744547">"TrustAgent દ્વારા અનલૉક રાખેલું"</string>
<string name="keyguard_indication_trust_disabled" msgid="6820793704816727918">"તમે ઉપકરણને મેન્યુઅલી અનલૉક કરશો નહીં ત્યાં સુધી તે લૉક રહેશે"</string>
+ <!-- no translation found for keyguard_indication_trust_unlocked_plugged_in (2323452175329362855) -->
+ <skip />
<string name="hidden_notifications_title" msgid="1782412844777612795">"વધુ ઝડપથી સૂચનાઓ મેળવો"</string>
<string name="hidden_notifications_text" msgid="5899627470450792578">"તમે અનલૉક કરો તે પહેલાં તેમને જુઓ"</string>
<string name="hidden_notifications_cancel" msgid="4805370226181001278">"ના, આભાર"</string>
@@ -979,12 +981,9 @@
<string name="bubble_accessibility_action_move_bottom_left" msgid="6339015902495504715">"નીચે ડાબે ખસેડો"</string>
<string name="bubble_accessibility_action_move_bottom_right" msgid="7471571700628346212">"નીચે જમણે ખસેડો"</string>
<string name="bubble_dismiss_text" msgid="7071770411580452911">"છોડી દો"</string>
- <!-- no translation found for bubbles_user_education_title (3385222165904578710) -->
- <skip />
- <!-- no translation found for bubbles_user_education_description (6663205638091146934) -->
- <skip />
- <!-- no translation found for bubbles_user_education_manage (1391639189507036423) -->
- <skip />
+ <string name="bubbles_user_education_title" msgid="3385222165904578710">"ચૅટને સૌથી પહેલાં રાખો"</string>
+ <string name="bubbles_user_education_description" msgid="6663205638091146934">"<xliff:g id="APP_NAME">%1$s</xliff:g>ની નવી ચૅટ બબલ તરીકે દેખાશે. બબલને ખોલવા માટે તેને ટૅપ કરો. તેને ખસેડવા માટે ખેંચો.\n\nબબલને ટૅપ કરો"</string>
+ <string name="bubbles_user_education_manage" msgid="1391639189507036423">"આ ઍપમાંથી બબલને બંધ કરવા માટે મેનેજ કરો પર ટૅપ કરો"</string>
<string name="notification_content_system_nav_changed" msgid="5077913144844684544">"સિસ્ટમ નૅવિગેશન અપડેટ કર્યું. ફેરફારો કરવા માટે, સેટિંગ પર જાઓ."</string>
<string name="notification_content_gesture_nav_available" msgid="4431460803004659888">"સિસ્ટમ નૅવિગેશનને અપડેટ કરવા માટે સેટિંગ પર જાઓ"</string>
<string name="inattentive_sleep_warning_title" msgid="3891371591713990373">"સ્ટૅન્ડબાય"</string>
@@ -994,12 +993,20 @@
<string name="quick_controls_title" msgid="525285759614231333">"ઝડપી નિયંત્રણો"</string>
<string name="controls_providers_title" msgid="8844124515157926071">"નિયંત્રણો ઉમેરો"</string>
<string name="controls_providers_subtitle" msgid="8187768950110836569">"જેમાંથી નિયંત્રણો ઉમેરવા હોય તે ઍપ પસંદ કરો"</string>
- <!-- no translation found for controls_number_of_favorites (1057347832073807380) -->
+ <plurals name="controls_number_of_favorites" formatted="false" msgid="1057347832073807380">
+ <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="controls_favorite_default_title" msgid="967742178688938137">"નિયંત્રણો"</string>
<string name="controls_favorite_subtitle" msgid="4049644994401173949">"ઝડપી ઍક્સેસ માટેનાં નિયંત્રણો પસંદ કરો"</string>
<string name="controls_favorite_header_favorites" msgid="3118600046217493471">"મનપસંદ"</string>
<string name="controls_favorite_header_all" msgid="7507855973418969992">"તમામ"</string>
<string name="controls_favorite_load_error" msgid="2533215155804455348">"બધા નિયંત્રણોની સૂચિ લોડ કરી શકાઈ નથી."</string>
- <!-- no translation found for controls_favorite_other_zone_header (9089613266575525252) -->
+ <string name="controls_favorite_other_zone_header" msgid="9089613266575525252">"અન્ય"</string>
+ <!-- no translation found for controls_dialog_title (8806193219278278442) -->
+ <skip />
+ <!-- no translation found for controls_dialog_ok (7011816381344485651) -->
+ <skip />
+ <!-- no translation found for controls_dialog_message (6292099631702047540) -->
<skip />
</resources>
diff --git a/packages/SystemUI/res/values-hi/strings.xml b/packages/SystemUI/res/values-hi/strings.xml
index 3cb4c6f17810..4fd83109e360 100644
--- a/packages/SystemUI/res/values-hi/strings.xml
+++ b/packages/SystemUI/res/values-hi/strings.xml
@@ -92,7 +92,7 @@
<string name="screenrecord_description" msgid="1123231719680353736">"रिकॉर्ड करते समय, Android सिस्टम आपकी स्क्रीन पर दिखने वाली या चलाई जाने वाली संवेदनशील जानकारी को कैप्चर कर सकता है. इसमें पासवर्ड, पैसे चुकाने से जुड़ी जानकारी, फ़ोटो, मैसेज, और ऑडियो शामिल हैं."</string>
<string name="screenrecord_audio_label" msgid="6183558856175159629">"ऑडियो रिकॉर्ड करें"</string>
<string name="screenrecord_device_audio_label" msgid="9016927171280567791">"डिवाइस ऑडियो"</string>
- <string name="screenrecord_device_audio_description" msgid="4922694220572186193">"आपके डिवाइस से आने वाली आवाज़. जैसे कि संगीत, कॉल, और रिंगटोन"</string>
+ <string name="screenrecord_device_audio_description" msgid="4922694220572186193">"आपके डिवाइस से आने वाली आवाज़ जैसे कि संगीत, कॉल, और रिंगटोन"</string>
<string name="screenrecord_mic_label" msgid="2111264835791332350">"माइक्रोफ़ोन"</string>
<string name="screenrecord_device_audio_and_mic_label" msgid="1831323771978646841">"डिवाइस ऑडियो और माइक्रोफ़ोन"</string>
<string name="screenrecord_start" msgid="330991441575775004">"शुरू करें"</string>
@@ -558,6 +558,8 @@
<string name="monitoring_description_app_personal_work" msgid="6175816356939166101">"आपकी वर्क प्रोफ़ाइल का प्रबंधन <xliff:g id="ORGANIZATION">%1$s</xliff:g> करता है. प्रोफ़ाइल <xliff:g id="APPLICATION_WORK">%2$s</xliff:g> से कनेक्ट है, जो ईमेल, ऐप्लिकेशन और वेबसाइटों सहित आपकी नेटवर्क गतिविधि की निगरानी कर सकता है.\n\nआप <xliff:g id="APPLICATION_PERSONAL">%3$s</xliff:g> से भी कनेक्ट हैं, जो आपकी व्यक्तिगत नेटवर्क गतिविधि की निगरानी कर सकता है."</string>
<string name="keyguard_indication_trust_unlocked" msgid="7395154975733744547">"TrustAgent की वजह से अनलॉक रखा गया है"</string>
<string name="keyguard_indication_trust_disabled" msgid="6820793704816727918">"जब तक कि आप मैन्‍युअल रूप से अनलॉक नहीं करते तब तक डिवाइस लॉक रहेगा"</string>
+ <!-- no translation found for keyguard_indication_trust_unlocked_plugged_in (2323452175329362855) -->
+ <skip />
<string name="hidden_notifications_title" msgid="1782412844777612795">"सूचनाएं ज़्यादा तेज़ी से पाएं"</string>
<string name="hidden_notifications_text" msgid="5899627470450792578">" उन्हें अनलॉक किए जाने से पहले देखें"</string>
<string name="hidden_notifications_cancel" msgid="4805370226181001278">"रहने दें"</string>
@@ -979,12 +981,9 @@
<string name="bubble_accessibility_action_move_bottom_left" msgid="6339015902495504715">"बाईं ओर सबसे नीचे ले जाएं"</string>
<string name="bubble_accessibility_action_move_bottom_right" msgid="7471571700628346212">"सबसे नीचे दाईं ओर ले जाएं"</string>
<string name="bubble_dismiss_text" msgid="7071770411580452911">"खारिज करें"</string>
- <!-- no translation found for bubbles_user_education_title (3385222165904578710) -->
- <skip />
- <!-- no translation found for bubbles_user_education_description (6663205638091146934) -->
- <skip />
- <!-- no translation found for bubbles_user_education_manage (1391639189507036423) -->
- <skip />
+ <string name="bubbles_user_education_title" msgid="3385222165904578710">"चैट को पहले से तैयार रखें"</string>
+ <string name="bubbles_user_education_description" msgid="6663205638091146934">"<xliff:g id="APP_NAME">%1$s</xliff:g> की नई चैट बबल्स की तरह दिखेंगी. इसे खोलने के लिए किसी बबल पर टैप करें. इसे एक जगह से दूसरी जगह ले जाने के लिए, खींचें और छोड़ें.\n\nबबल पर टैप करें"</string>
+ <string name="bubbles_user_education_manage" msgid="1391639189507036423">"इस ऐप्लिकेशन पर बबल्स को बंद करने के लिए \'प्रबंधित करें\' पर टैप करें"</string>
<string name="notification_content_system_nav_changed" msgid="5077913144844684544">"सिस्टम नेविगेशन अपडेट हो गया. बदलाव करने के लिए \'सेटिंग\' पर जाएं."</string>
<string name="notification_content_gesture_nav_available" msgid="4431460803004659888">"सिस्टम नेविगेशन अपडेट करने के लिए \'सेटिंग\' में जाएं"</string>
<string name="inattentive_sleep_warning_title" msgid="3891371591713990373">"स्टैंडबाई"</string>
@@ -994,12 +993,20 @@
<string name="quick_controls_title" msgid="525285759614231333">"फटाफट नियंत्रण"</string>
<string name="controls_providers_title" msgid="8844124515157926071">"कंट्राेल जोड़ें"</string>
<string name="controls_providers_subtitle" msgid="8187768950110836569">"वह ऐप्लिकेशन चुनें जिससे आप कंट्राेल जोड़ना चाहते हैं"</string>
- <!-- no translation found for controls_number_of_favorites (1057347832073807380) -->
+ <plurals name="controls_number_of_favorites" formatted="false" msgid="1057347832073807380">
+ <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="controls_favorite_default_title" msgid="967742178688938137">"कंट्राेल"</string>
<string name="controls_favorite_subtitle" msgid="4049644994401173949">"झटपट ऐक्सेस पाने के लिए कंट्राेल चुनें"</string>
<string name="controls_favorite_header_favorites" msgid="3118600046217493471">"पसंदीदा"</string>
<string name="controls_favorite_header_all" msgid="7507855973418969992">"सभी"</string>
<string name="controls_favorite_load_error" msgid="2533215155804455348">"सभी कंट्रोल की सूची लोड नहीं हो सकी."</string>
- <!-- no translation found for controls_favorite_other_zone_header (9089613266575525252) -->
+ <string name="controls_favorite_other_zone_header" msgid="9089613266575525252">"अन्य"</string>
+ <!-- no translation found for controls_dialog_title (8806193219278278442) -->
+ <skip />
+ <!-- no translation found for controls_dialog_ok (7011816381344485651) -->
+ <skip />
+ <!-- no translation found for controls_dialog_message (6292099631702047540) -->
<skip />
</resources>
diff --git a/packages/SystemUI/res/values-hr/strings.xml b/packages/SystemUI/res/values-hr/strings.xml
index d648aeb5948a..bb538029a8a8 100644
--- a/packages/SystemUI/res/values-hr/strings.xml
+++ b/packages/SystemUI/res/values-hr/strings.xml
@@ -561,6 +561,7 @@
<string name="monitoring_description_app_personal_work" msgid="6175816356939166101">"Vašim radnim profilom upravlja organizacija <xliff:g id="ORGANIZATION">%1$s</xliff:g>. Profil je povezan s aplikacijom <xliff:g id="APPLICATION_WORK">%2$s</xliff:g> koja može nadzirati vaše poslovne aktivnosti na mreži, uključujući e-poruke, aplikacije i web-lokacije.\n\nPovezani ste i s aplikacijom <xliff:g id="APPLICATION_PERSONAL">%3$s</xliff:g> koja može nadzirati vaše osobne aktivnosti na mreži."</string>
<string name="keyguard_indication_trust_unlocked" msgid="7395154975733744547">"Otključano održava TrustAgent"</string>
<string name="keyguard_indication_trust_disabled" msgid="6820793704816727918">"Uređaj će ostati zaključan dok ga ručno ne otključate"</string>
+ <string name="keyguard_indication_trust_unlocked_plugged_in" msgid="2323452175329362855">"<xliff:g id="KEYGUARD_INDICATION">%1$s</xliff:g>\n<xliff:g id="POWER_INDICATION">%2$s</xliff:g>"</string>
<string name="hidden_notifications_title" msgid="1782412844777612795">"Primajte obavijesti brže"</string>
<string name="hidden_notifications_text" msgid="5899627470450792578">"Pogledajte ih prije otključavanja"</string>
<string name="hidden_notifications_cancel" msgid="4805370226181001278">"Ne, hvala"</string>
@@ -984,12 +985,9 @@
<string name="bubble_accessibility_action_move_bottom_left" msgid="6339015902495504715">"Premjesti u donji lijevi kut"</string>
<string name="bubble_accessibility_action_move_bottom_right" msgid="7471571700628346212">"Premjestite u donji desni kut"</string>
<string name="bubble_dismiss_text" msgid="7071770411580452911">"Odbaci"</string>
- <!-- no translation found for bubbles_user_education_title (3385222165904578710) -->
- <skip />
- <!-- no translation found for bubbles_user_education_description (6663205638091146934) -->
- <skip />
- <!-- no translation found for bubbles_user_education_manage (1391639189507036423) -->
- <skip />
+ <string name="bubbles_user_education_title" msgid="3385222165904578710">"Isticanje chatova"</string>
+ <string name="bubbles_user_education_description" msgid="6663205638091146934">"Novi chatovi iz aplikacije <xliff:g id="APP_NAME">%1$s</xliff:g> prikazat će se kao oblačići. Dodirnite oblačić da biste ga otvorili. Povucite da biste ga premjestili.\n\nDodirnite oblačić"</string>
+ <string name="bubbles_user_education_manage" msgid="1391639189507036423">"Dodirnite Upravljanje da biste isključili oblačiće iz ove aplikacije"</string>
<string name="notification_content_system_nav_changed" msgid="5077913144844684544">"Ažurirana je navigacija sustavom. Možete je promijeniti u Postavkama."</string>
<string name="notification_content_gesture_nav_available" msgid="4431460803004659888">"Navigaciju sustavom možete ažurirati u Postavkama"</string>
<string name="inattentive_sleep_warning_title" msgid="3891371591713990373">"Stanje mirovanja"</string>
@@ -1010,4 +1008,10 @@
<string name="controls_favorite_header_all" msgid="7507855973418969992">"Sve"</string>
<string name="controls_favorite_load_error" msgid="2533215155804455348">"Popis svih kontrola nije se učitao."</string>
<string name="controls_favorite_other_zone_header" msgid="9089613266575525252">"Drugo"</string>
+ <!-- no translation found for controls_dialog_title (8806193219278278442) -->
+ <skip />
+ <!-- no translation found for controls_dialog_ok (7011816381344485651) -->
+ <skip />
+ <!-- no translation found for controls_dialog_message (6292099631702047540) -->
+ <skip />
</resources>
diff --git a/packages/SystemUI/res/values-hu/strings.xml b/packages/SystemUI/res/values-hu/strings.xml
index 03151aeeb31e..7d1159c66fea 100644
--- a/packages/SystemUI/res/values-hu/strings.xml
+++ b/packages/SystemUI/res/values-hu/strings.xml
@@ -558,6 +558,7 @@
<string name="monitoring_description_app_personal_work" msgid="6175816356939166101">"Munkaprofilját a(z) <xliff:g id="ORGANIZATION">%1$s</xliff:g> kezeli. A profil csatlakozik a(z) <xliff:g id="APPLICATION_WORK">%2$s</xliff:g> alkalmazáshoz, amely figyelheti az Ön hálózati tevékenységeit, beleértve az e-maileket, alkalmazásokat és webhelyeket.\n\nCsatlakoztatta továbbá a(z) <xliff:g id="APPLICATION_PERSONAL">%3$s</xliff:g> alkalmazást, amely figyelheti az Ön személyes hálózati tevékenységeit."</string>
<string name="keyguard_indication_trust_unlocked" msgid="7395154975733744547">"Feloldva tartva TrustAgent által"</string>
<string name="keyguard_indication_trust_disabled" msgid="6820793704816727918">"Az eszköz addig zárolva marad, amíg kézileg fel nem oldja"</string>
+ <string name="keyguard_indication_trust_unlocked_plugged_in" msgid="2323452175329362855">"<xliff:g id="KEYGUARD_INDICATION">%1$s</xliff:g>\n<xliff:g id="POWER_INDICATION">%2$s</xliff:g>"</string>
<string name="hidden_notifications_title" msgid="1782412844777612795">"Gyorsabban megkaphatja az értesítéseket"</string>
<string name="hidden_notifications_text" msgid="5899627470450792578">"Már a képernyőzár feloldása előtt megtekintheti őket"</string>
<string name="hidden_notifications_cancel" msgid="4805370226181001278">"Nem, köszönöm"</string>
@@ -979,12 +980,9 @@
<string name="bubble_accessibility_action_move_bottom_left" msgid="6339015902495504715">"Áthelyezés le és balra"</string>
<string name="bubble_accessibility_action_move_bottom_right" msgid="7471571700628346212">"Áthelyezés le és jobbra"</string>
<string name="bubble_dismiss_text" msgid="7071770411580452911">"Elvetés"</string>
- <!-- no translation found for bubbles_user_education_title (3385222165904578710) -->
- <skip />
- <!-- no translation found for bubbles_user_education_description (6663205638091146934) -->
- <skip />
- <!-- no translation found for bubbles_user_education_manage (1391639189507036423) -->
- <skip />
+ <string name="bubbles_user_education_title" msgid="3385222165904578710">"A csevegések előtérben tartása"</string>
+ <string name="bubbles_user_education_description" msgid="6663205638091146934">"A(z) <xliff:g id="APP_NAME">%1$s</xliff:g> alkalmazásból származó új csevegőüzenetek buborékként jelennek meg. A csevegés megnyitásához koppintson a buborékra. Az áthelyezéséhez húzza a buborékot a kívánt helyre.\n\nKoppintson a buborékra"</string>
+ <string name="bubbles_user_education_manage" msgid="1391639189507036423">"A Kezelés gombra koppintva kapcsolhatja ki az alkalmazásból származó buborékokat"</string>
<string name="notification_content_system_nav_changed" msgid="5077913144844684544">"A rendszer-navigáció módja megváltozott. Módosításához nyissa meg a Beállításokat."</string>
<string name="notification_content_gesture_nav_available" msgid="4431460803004659888">"A rendszer-navigációs lehetőségeket a Beállításokban módosíthatja"</string>
<string name="inattentive_sleep_warning_title" msgid="3891371591713990373">"Készenléti mód"</string>
@@ -1004,4 +1002,10 @@
<string name="controls_favorite_header_all" msgid="7507855973418969992">"Összes"</string>
<string name="controls_favorite_load_error" msgid="2533215155804455348">"Nem sikerült betölteni az összes vezérlő listáját."</string>
<string name="controls_favorite_other_zone_header" msgid="9089613266575525252">"Más"</string>
+ <!-- no translation found for controls_dialog_title (8806193219278278442) -->
+ <skip />
+ <!-- no translation found for controls_dialog_ok (7011816381344485651) -->
+ <skip />
+ <!-- no translation found for controls_dialog_message (6292099631702047540) -->
+ <skip />
</resources>
diff --git a/packages/SystemUI/res/values-hy/strings.xml b/packages/SystemUI/res/values-hy/strings.xml
index d8728f561094..3f447368c3a8 100644
--- a/packages/SystemUI/res/values-hy/strings.xml
+++ b/packages/SystemUI/res/values-hy/strings.xml
@@ -558,6 +558,7 @@
<string name="monitoring_description_app_personal_work" msgid="6175816356939166101">"Ձեր աշխատանքային պրոֆիլի կառավարիչն է <xliff:g id="ORGANIZATION">%1$s</xliff:g> կազմակերպությունը: Այն կապակցված է <xliff:g id="APPLICATION_WORK">%2$s</xliff:g> հավելվածին, որը կարող է վերահսկել աշխատանքային ցանցում կատարած գործունեությունը, այդ թվում նաև էլփոստի հաշիվները, հավելվածները և կայքերը:\n\nԴուք կապակցված եք նաև <xliff:g id="APPLICATION_PERSONAL">%3$s</xliff:g> հավելվածին, որը կարող է վերահսկել անձնական ցանցում կատարած ձեր գործողությունները:"</string>
<string name="keyguard_indication_trust_unlocked" msgid="7395154975733744547">"Ապակողպվում է TrustAgent-ի միջոցով"</string>
<string name="keyguard_indication_trust_disabled" msgid="6820793704816727918">"Սարքը կմնա արգելափակված՝ մինչև ձեռքով չբացեք"</string>
+ <string name="keyguard_indication_trust_unlocked_plugged_in" msgid="2323452175329362855">"<xliff:g id="KEYGUARD_INDICATION">%1$s</xliff:g>\n<xliff:g id="POWER_INDICATION">%2$s</xliff:g>"</string>
<string name="hidden_notifications_title" msgid="1782412844777612795">"Ավելի արագ ստացեք ծանուցումները"</string>
<string name="hidden_notifications_text" msgid="5899627470450792578">"Տեսեք դրանք մինչև ապակողպելը"</string>
<string name="hidden_notifications_cancel" msgid="4805370226181001278">"Ոչ"</string>
@@ -1001,4 +1002,10 @@
<string name="controls_favorite_header_all" msgid="7507855973418969992">"Բոլորը"</string>
<string name="controls_favorite_load_error" msgid="2533215155804455348">"Չհաջողվեց բեռնել բոլոր կառավարների ցանկը։"</string>
<string name="controls_favorite_other_zone_header" msgid="9089613266575525252">"Այլ"</string>
+ <!-- no translation found for controls_dialog_title (8806193219278278442) -->
+ <skip />
+ <!-- no translation found for controls_dialog_ok (7011816381344485651) -->
+ <skip />
+ <!-- no translation found for controls_dialog_message (6292099631702047540) -->
+ <skip />
</resources>
diff --git a/packages/SystemUI/res/values-in/strings.xml b/packages/SystemUI/res/values-in/strings.xml
index 012a16e1482f..18728a190ba5 100644
--- a/packages/SystemUI/res/values-in/strings.xml
+++ b/packages/SystemUI/res/values-in/strings.xml
@@ -558,6 +558,7 @@
<string name="monitoring_description_app_personal_work" msgid="6175816356939166101">"Profil kerja Anda dikelola oleh <xliff:g id="ORGANIZATION">%1$s</xliff:g>. Profil tersambung ke <xliff:g id="APPLICATION_WORK">%2$s</xliff:g>, yang dapat memantau aktivitas jaringan, termasuk email, aplikasi, dan situs.\n\nAnda juga tersambung ke <xliff:g id="APPLICATION_PERSONAL">%3$s</xliff:g>, yang dapat memantau aktivitas jaringan pribadi."</string>
<string name="keyguard_indication_trust_unlocked" msgid="7395154975733744547">"Tetap terbuka kuncinya oleh TrustAgent"</string>
<string name="keyguard_indication_trust_disabled" msgid="6820793704816727918">"Perangkat akan tetap terkunci hingga Anda membukanya secara manual"</string>
+ <string name="keyguard_indication_trust_unlocked_plugged_in" msgid="2323452175329362855">"<xliff:g id="KEYGUARD_INDICATION">%1$s</xliff:g>\n<xliff:g id="POWER_INDICATION">%2$s</xliff:g>"</string>
<string name="hidden_notifications_title" msgid="1782412844777612795">"Dapatkan pemberitahuan lebih cepat"</string>
<string name="hidden_notifications_text" msgid="5899627470450792578">"Lihat sebelum membuka kunci"</string>
<string name="hidden_notifications_cancel" msgid="4805370226181001278">"Tidak"</string>
@@ -1001,4 +1002,10 @@
<string name="controls_favorite_header_all" msgid="7507855973418969992">"Semua"</string>
<string name="controls_favorite_load_error" msgid="2533215155804455348">"Daftar semua kontrol tidak dapat dimuat."</string>
<string name="controls_favorite_other_zone_header" msgid="9089613266575525252">"Lainnya"</string>
+ <!-- no translation found for controls_dialog_title (8806193219278278442) -->
+ <skip />
+ <!-- no translation found for controls_dialog_ok (7011816381344485651) -->
+ <skip />
+ <!-- no translation found for controls_dialog_message (6292099631702047540) -->
+ <skip />
</resources>
diff --git a/packages/SystemUI/res/values-is/strings.xml b/packages/SystemUI/res/values-is/strings.xml
index 7542e3e056f9..07b0d7686d54 100644
--- a/packages/SystemUI/res/values-is/strings.xml
+++ b/packages/SystemUI/res/values-is/strings.xml
@@ -558,6 +558,7 @@
<string name="monitoring_description_app_personal_work" msgid="6175816356939166101">"Vinnusniðinu þínu er stýrt af <xliff:g id="ORGANIZATION">%1$s</xliff:g>. Sniðið er tengt <xliff:g id="APPLICATION_WORK">%2$s</xliff:g>, sem getur fylgst með netnotkun þinni, þ. á m. tölvupósti, forritum og vefsvæðum\n\nÞú ert einnig með tengingu við <xliff:g id="APPLICATION_PERSONAL">%3$s</xliff:g>, sem getur fylgst með persónulegri netnotkun þinni."</string>
<string name="keyguard_indication_trust_unlocked" msgid="7395154975733744547">"Haldið opnu af TrustAgent"</string>
<string name="keyguard_indication_trust_disabled" msgid="6820793704816727918">"Tækið verður læst þar til þú opnar það handvirkt"</string>
+ <string name="keyguard_indication_trust_unlocked_plugged_in" msgid="2323452175329362855">"<xliff:g id="KEYGUARD_INDICATION">%1$s</xliff:g>\n<xliff:g id="POWER_INDICATION">%2$s</xliff:g>"</string>
<string name="hidden_notifications_title" msgid="1782412844777612795">"Fáðu tilkynningar hraðar"</string>
<string name="hidden_notifications_text" msgid="5899627470450792578">"Sjáðu þær áður en þú opnar"</string>
<string name="hidden_notifications_cancel" msgid="4805370226181001278">"Nei, takk"</string>
@@ -979,12 +980,9 @@
<string name="bubble_accessibility_action_move_bottom_left" msgid="6339015902495504715">"Færa neðst til vinstri"</string>
<string name="bubble_accessibility_action_move_bottom_right" msgid="7471571700628346212">"Færðu neðst til hægri"</string>
<string name="bubble_dismiss_text" msgid="7071770411580452911">"Hunsa"</string>
- <!-- no translation found for bubbles_user_education_title (3385222165904578710) -->
- <skip />
- <!-- no translation found for bubbles_user_education_description (6663205638091146934) -->
- <skip />
- <!-- no translation found for bubbles_user_education_manage (1391639189507036423) -->
- <skip />
+ <string name="bubbles_user_education_title" msgid="3385222165904578710">"Halda spjalli fyrir framan"</string>
+ <string name="bubbles_user_education_description" msgid="6663205638091146934">"Nýtt spjall úr <xliff:g id="APP_NAME">%1$s</xliff:g> birtist sem blöðrur. Ýttu á blöðru til að opna hana. Dragðu hana til að færa hana.\n\nÝttu á blöðruna"</string>
+ <string name="bubbles_user_education_manage" msgid="1391639189507036423">"Ýttu á „Stjórna“ til að slökkva á blöðrum frá þessu forriti"</string>
<string name="notification_content_system_nav_changed" msgid="5077913144844684544">"Kerfisstjórnun uppfærð. Þú getur breytt þessu í stillingunum."</string>
<string name="notification_content_gesture_nav_available" msgid="4431460803004659888">"Farðu í stillingar til að uppfæra kerfisstjórnun"</string>
<string name="inattentive_sleep_warning_title" msgid="3891371591713990373">"Biðstaða"</string>
@@ -1004,4 +1002,10 @@
<string name="controls_favorite_header_all" msgid="7507855973418969992">"Allt"</string>
<string name="controls_favorite_load_error" msgid="2533215155804455348">"Ekki tókst að hlaða lista yfir allar stýringar."</string>
<string name="controls_favorite_other_zone_header" msgid="9089613266575525252">"Annað"</string>
+ <!-- no translation found for controls_dialog_title (8806193219278278442) -->
+ <skip />
+ <!-- no translation found for controls_dialog_ok (7011816381344485651) -->
+ <skip />
+ <!-- no translation found for controls_dialog_message (6292099631702047540) -->
+ <skip />
</resources>
diff --git a/packages/SystemUI/res/values-it/strings.xml b/packages/SystemUI/res/values-it/strings.xml
index 65dc5148875b..1c8bafde75bf 100644
--- a/packages/SystemUI/res/values-it/strings.xml
+++ b/packages/SystemUI/res/values-it/strings.xml
@@ -558,6 +558,7 @@
<string name="monitoring_description_app_personal_work" msgid="6175816356939166101">"Il tuo profilo di lavoro è gestito da <xliff:g id="ORGANIZATION">%1$s</xliff:g> ed è collegato a <xliff:g id="APPLICATION_WORK">%2$s</xliff:g>, da cui è possibile monitorare la tua attività di rete lavorativa, inclusi siti web, email e app.\n\nSei collegato anche a <xliff:g id="APPLICATION_PERSONAL">%3$s</xliff:g>, da cui è possibile monitorare la tua attività di rete personale."</string>
<string name="keyguard_indication_trust_unlocked" msgid="7395154975733744547">"Sbloccato da TrustAgent"</string>
<string name="keyguard_indication_trust_disabled" msgid="6820793704816727918">"Il dispositivo resterà bloccato fino allo sblocco manuale"</string>
+ <string name="keyguard_indication_trust_unlocked_plugged_in" msgid="2323452175329362855">"<xliff:g id="KEYGUARD_INDICATION">%1$s</xliff:g>\n<xliff:g id="POWER_INDICATION">%2$s</xliff:g>"</string>
<string name="hidden_notifications_title" msgid="1782412844777612795">"Ricevi notifiche più velocemente"</string>
<string name="hidden_notifications_text" msgid="5899627470450792578">"Visualizza prima di sbloccare"</string>
<string name="hidden_notifications_cancel" msgid="4805370226181001278">"No, grazie"</string>
@@ -979,12 +980,9 @@
<string name="bubble_accessibility_action_move_bottom_left" msgid="6339015902495504715">"Sposta in basso a sinistra"</string>
<string name="bubble_accessibility_action_move_bottom_right" msgid="7471571700628346212">"Sposta in basso a destra"</string>
<string name="bubble_dismiss_text" msgid="7071770411580452911">"Ignora"</string>
- <!-- no translation found for bubbles_user_education_title (3385222165904578710) -->
- <skip />
- <!-- no translation found for bubbles_user_education_description (6663205638091146934) -->
- <skip />
- <!-- no translation found for bubbles_user_education_manage (1391639189507036423) -->
- <skip />
+ <string name="bubbles_user_education_title" msgid="3385222165904578710">"Tieni davanti le chat"</string>
+ <string name="bubbles_user_education_description" msgid="6663205638091146934">"Le nuove chat da <xliff:g id="APP_NAME">%1$s</xliff:g> verranno visualizzate come bolle. Tocca una bolla per aprirla. Trascinala per spostarla.\n\nTocca la bolla"</string>
+ <string name="bubbles_user_education_manage" msgid="1391639189507036423">"Tocca Gestisci per disattivare le bolle dall\'app"</string>
<string name="notification_content_system_nav_changed" msgid="5077913144844684544">"Navigazione del sistema aggiornata. Per apportare modifiche, usa le Impostazioni."</string>
<string name="notification_content_gesture_nav_available" msgid="4431460803004659888">"Usa le Impostazioni per aggiornare la navigazione del sistema"</string>
<string name="inattentive_sleep_warning_title" msgid="3891371591713990373">"Standby"</string>
@@ -1004,4 +1002,10 @@
<string name="controls_favorite_header_all" msgid="7507855973418969992">"Tutti"</string>
<string name="controls_favorite_load_error" msgid="2533215155804455348">"Impossibile caricare l\'elenco di tutti i controlli."</string>
<string name="controls_favorite_other_zone_header" msgid="9089613266575525252">"Altro"</string>
+ <!-- no translation found for controls_dialog_title (8806193219278278442) -->
+ <skip />
+ <!-- no translation found for controls_dialog_ok (7011816381344485651) -->
+ <skip />
+ <!-- no translation found for controls_dialog_message (6292099631702047540) -->
+ <skip />
</resources>
diff --git a/packages/SystemUI/res/values-iw/strings.xml b/packages/SystemUI/res/values-iw/strings.xml
index 2a9d596cbc7f..a798cfae3bd0 100644
--- a/packages/SystemUI/res/values-iw/strings.xml
+++ b/packages/SystemUI/res/values-iw/strings.xml
@@ -564,6 +564,7 @@
<string name="monitoring_description_app_personal_work" msgid="6175816356939166101">"פרופיל העבודה שלך מנוהל על ידי <xliff:g id="ORGANIZATION">%1$s</xliff:g>. הפרופיל מחובר לאפליקציה <xliff:g id="APPLICATION_WORK">%2$s</xliff:g>, שיכולה לעקוב אחר הפעילות שלך ברשת, כולל הודעות אימייל, אפליקציות ואתרים.\n\nהפרופיל מחובר גם לאפליקציה <xliff:g id="APPLICATION_PERSONAL">%3$s</xliff:g>, שיכולה לעקוב אחר הפעילות שלך ברשת."</string>
<string name="keyguard_indication_trust_unlocked" msgid="7395154975733744547">"הנעילה נמנעת על ידי סביבה אמינה"</string>
<string name="keyguard_indication_trust_disabled" msgid="6820793704816727918">"המכשיר יישאר נעול עד שתבטל את נעילתו באופן ידני"</string>
+ <string name="keyguard_indication_trust_unlocked_plugged_in" msgid="2323452175329362855">"<xliff:g id="KEYGUARD_INDICATION">%1$s</xliff:g>\n<xliff:g id="POWER_INDICATION">%2$s</xliff:g>"</string>
<string name="hidden_notifications_title" msgid="1782412844777612795">"קבלה מהירה של התראות"</string>
<string name="hidden_notifications_text" msgid="5899627470450792578">"צפה בהן לפני שתבטל נעילה"</string>
<string name="hidden_notifications_cancel" msgid="4805370226181001278">"לא, תודה"</string>
@@ -989,12 +990,9 @@
<string name="bubble_accessibility_action_move_bottom_left" msgid="6339015902495504715">"העברה לפינה השמאלית התחתונה"</string>
<string name="bubble_accessibility_action_move_bottom_right" msgid="7471571700628346212">"העברה לפינה הימנית התחתונה"</string>
<string name="bubble_dismiss_text" msgid="7071770411580452911">"סגירה"</string>
- <!-- no translation found for bubbles_user_education_title (3385222165904578710) -->
- <skip />
- <!-- no translation found for bubbles_user_education_description (6663205638091146934) -->
- <skip />
- <!-- no translation found for bubbles_user_education_manage (1391639189507036423) -->
- <skip />
+ <string name="bubbles_user_education_title" msgid="3385222165904578710">"הצ\'אטים תמיד יוצגו מלפנים"</string>
+ <string name="bubbles_user_education_description" msgid="6663205638091146934">"צ\'אטים חדשים מאפליקציית <xliff:g id="APP_NAME">%1$s</xliff:g> יוצגו כבועות. יש להקיש על בועה כדי לפתוח אותה. יש לגרור אותה כדי להזיז אותה.\n\nיש להקיש על הבועה"</string>
+ <string name="bubbles_user_education_manage" msgid="1391639189507036423">"יש להקיש על \'ניהול\' כדי להשבית את הבועות מהאפליקציה הזו"</string>
<string name="notification_content_system_nav_changed" msgid="5077913144844684544">"הניווט במערכת עודכן. אפשר לערוך שינויים דרך ההגדרות."</string>
<string name="notification_content_gesture_nav_available" msgid="4431460803004659888">"יש לעבור להגדרות כדי לעדכן את הניווט במערכת"</string>
<string name="inattentive_sleep_warning_title" msgid="3891371591713990373">"המתנה"</string>
@@ -1016,4 +1014,10 @@
<string name="controls_favorite_header_all" msgid="7507855973418969992">"הכול"</string>
<string name="controls_favorite_load_error" msgid="2533215155804455348">"לא ניתן היה לטעון את הרשימה של כל הפקדים."</string>
<string name="controls_favorite_other_zone_header" msgid="9089613266575525252">"אחר"</string>
+ <!-- no translation found for controls_dialog_title (8806193219278278442) -->
+ <skip />
+ <!-- no translation found for controls_dialog_ok (7011816381344485651) -->
+ <skip />
+ <!-- no translation found for controls_dialog_message (6292099631702047540) -->
+ <skip />
</resources>
diff --git a/packages/SystemUI/res/values-ja/strings.xml b/packages/SystemUI/res/values-ja/strings.xml
index b4952ff4c318..b62dae693b69 100644
--- a/packages/SystemUI/res/values-ja/strings.xml
+++ b/packages/SystemUI/res/values-ja/strings.xml
@@ -558,6 +558,7 @@
<string name="monitoring_description_app_personal_work" msgid="6175816356939166101">"この仕事用プロファイルは<xliff:g id="ORGANIZATION">%1$s</xliff:g>によって管理され、<xliff:g id="APPLICATION_WORK">%2$s</xliff:g> に接続しています。このアプリはあなたの仕事のネットワーク アクティビティ(メール、アプリ、ウェブサイトなど)を管理できます。\n\nまた、<xliff:g id="APPLICATION_PERSONAL">%3$s</xliff:g> にも接続しているため、あなたの個人のネットワーク アクティビティも監視できます。"</string>
<string name="keyguard_indication_trust_unlocked" msgid="7395154975733744547">"信頼エージェントがロック解除を管理"</string>
<string name="keyguard_indication_trust_disabled" msgid="6820793704816727918">"手動でロックを解除するまでロックされたままとなります"</string>
+ <string name="keyguard_indication_trust_unlocked_plugged_in" msgid="2323452175329362855">"<xliff:g id="KEYGUARD_INDICATION">%1$s</xliff:g>\n<xliff:g id="POWER_INDICATION">%2$s</xliff:g>"</string>
<string name="hidden_notifications_title" msgid="1782412844777612795">"通知をすばやく確認できます"</string>
<string name="hidden_notifications_text" msgid="5899627470450792578">"ロックを解除する前にご確認ください"</string>
<string name="hidden_notifications_cancel" msgid="4805370226181001278">"キャンセル"</string>
@@ -979,12 +980,9 @@
<string name="bubble_accessibility_action_move_bottom_left" msgid="6339015902495504715">"左下に移動"</string>
<string name="bubble_accessibility_action_move_bottom_right" msgid="7471571700628346212">"右下に移動"</string>
<string name="bubble_dismiss_text" msgid="7071770411580452911">"閉じる"</string>
- <!-- no translation found for bubbles_user_education_title (3385222165904578710) -->
- <skip />
- <!-- no translation found for bubbles_user_education_description (6663205638091146934) -->
- <skip />
- <!-- no translation found for bubbles_user_education_manage (1391639189507036423) -->
- <skip />
+ <string name="bubbles_user_education_title" msgid="3385222165904578710">"チャットを常に前面に表示"</string>
+ <string name="bubbles_user_education_description" msgid="6663205638091146934">"<xliff:g id="APP_NAME">%1$s</xliff:g> からの新しいチャットがバブルとして表示されます。バブルをタップするとチャットが表示されます。ドラッグすると移動します。\n\nバブルをタップしてください"</string>
+ <string name="bubbles_user_education_manage" msgid="1391639189507036423">"このアプリからのバブルをオフにするには、[管理] をタップしてください"</string>
<string name="notification_content_system_nav_changed" msgid="5077913144844684544">"システム ナビゲーションを更新しました。変更するには [設定] に移動してください。"</string>
<string name="notification_content_gesture_nav_available" msgid="4431460803004659888">"システム ナビゲーションを更新するには [設定] に移動してください"</string>
<string name="inattentive_sleep_warning_title" msgid="3891371591713990373">"スタンバイ"</string>
@@ -1004,4 +1002,10 @@
<string name="controls_favorite_header_all" msgid="7507855973418969992">"すべて"</string>
<string name="controls_favorite_load_error" msgid="2533215155804455348">"全コントロールの一覧を読み込めませんでした。"</string>
<string name="controls_favorite_other_zone_header" msgid="9089613266575525252">"その他"</string>
+ <!-- no translation found for controls_dialog_title (8806193219278278442) -->
+ <skip />
+ <!-- no translation found for controls_dialog_ok (7011816381344485651) -->
+ <skip />
+ <!-- no translation found for controls_dialog_message (6292099631702047540) -->
+ <skip />
</resources>
diff --git a/packages/SystemUI/res/values-ka/strings.xml b/packages/SystemUI/res/values-ka/strings.xml
index 07b9e2a1eff1..83656733126f 100644
--- a/packages/SystemUI/res/values-ka/strings.xml
+++ b/packages/SystemUI/res/values-ka/strings.xml
@@ -558,6 +558,7 @@
<string name="monitoring_description_app_personal_work" msgid="6175816356939166101">"თქვენს სამსახურის პროფილს მართავს <xliff:g id="ORGANIZATION">%1$s</xliff:g>. პროფილი დაკავშირებულია <xliff:g id="APPLICATION_WORK">%2$s</xliff:g>-თან, რომელსაც შეუძლია ქსელში თქვენი სამსახურეობრივი აქტივობის (მათ შორის, ელფოსტის, აპებისა და ვებსაიტების) მონიტორინგი.\n\nგარდა ამისა, თქვენ დაკავშირებული ხართ <xliff:g id="APPLICATION_PERSONAL">%3$s</xliff:g>-თან, რომელსაც ქსელში თქვენი პირადი აქტივობის მონიტორინგი შეუძლია."</string>
<string name="keyguard_indication_trust_unlocked" msgid="7395154975733744547">"განბლოკილია TrustAgent-ის მიერ"</string>
<string name="keyguard_indication_trust_disabled" msgid="6820793704816727918">"მოწყობილობის დარჩება ჩაკეტილი, სანამ ხელით არ გახსნით"</string>
+ <string name="keyguard_indication_trust_unlocked_plugged_in" msgid="2323452175329362855">"<xliff:g id="KEYGUARD_INDICATION">%1$s</xliff:g>\n<xliff:g id="POWER_INDICATION">%2$s</xliff:g>"</string>
<string name="hidden_notifications_title" msgid="1782412844777612795">"შეტყობინებების უფრო სწრაფად მიღება"</string>
<string name="hidden_notifications_text" msgid="5899627470450792578">"იხილეთ განბლოკვამდე"</string>
<string name="hidden_notifications_cancel" msgid="4805370226181001278">"არა, გმადლობთ"</string>
@@ -979,12 +980,9 @@
<string name="bubble_accessibility_action_move_bottom_left" msgid="6339015902495504715">"ქვევით და მარცხნივ გადატანა"</string>
<string name="bubble_accessibility_action_move_bottom_right" msgid="7471571700628346212">"გადაანაცვ. ქვემოთ და მარჯვნივ"</string>
<string name="bubble_dismiss_text" msgid="7071770411580452911">"დახურვა"</string>
- <!-- no translation found for bubbles_user_education_title (3385222165904578710) -->
- <skip />
- <!-- no translation found for bubbles_user_education_description (6663205638091146934) -->
- <skip />
- <!-- no translation found for bubbles_user_education_manage (1391639189507036423) -->
- <skip />
+ <string name="bubbles_user_education_title" msgid="3385222165904578710">"ჩეთები წინ იყოს"</string>
+ <string name="bubbles_user_education_description" msgid="6663205638091146934">"<xliff:g id="APP_NAME">%1$s</xliff:g>-ის ახალი ჩეთები ბუშტების სახით გამოჩნდება. გასახსნელად შეეხეთ ბუშტს. გადასატანად ჩაავლეთ.\n\nშეეხეთ ბუშტს"</string>
+ <string name="bubbles_user_education_manage" msgid="1391639189507036423">"ამ აპის ბუშტების გამოსართავად შეეხეთ „მართვას“"</string>
<string name="notification_content_system_nav_changed" msgid="5077913144844684544">"სისტემური ნავიგაცია განახლდა. ცვლილებების შესატანად გადადით პარამეტრებზე."</string>
<string name="notification_content_gesture_nav_available" msgid="4431460803004659888">"სისტემური ნავიგაციის გასაახლებლად გადადით პარამეტრებზე"</string>
<string name="inattentive_sleep_warning_title" msgid="3891371591713990373">"მოლოდინის რეჟიმი"</string>
@@ -1004,4 +1002,10 @@
<string name="controls_favorite_header_all" msgid="7507855973418969992">"ყველა"</string>
<string name="controls_favorite_load_error" msgid="2533215155804455348">"მართვის ყველა საშუალების სია ვერ ჩაიტვირთა."</string>
<string name="controls_favorite_other_zone_header" msgid="9089613266575525252">"სხვა"</string>
+ <!-- no translation found for controls_dialog_title (8806193219278278442) -->
+ <skip />
+ <!-- no translation found for controls_dialog_ok (7011816381344485651) -->
+ <skip />
+ <!-- no translation found for controls_dialog_message (6292099631702047540) -->
+ <skip />
</resources>
diff --git a/packages/SystemUI/res/values-kk/strings.xml b/packages/SystemUI/res/values-kk/strings.xml
index d639189175c3..e7ca4154092c 100644
--- a/packages/SystemUI/res/values-kk/strings.xml
+++ b/packages/SystemUI/res/values-kk/strings.xml
@@ -558,6 +558,7 @@
<string name="monitoring_description_app_personal_work" msgid="6175816356939166101">"Жұмыс профиліңізді <xliff:g id="ORGANIZATION">%1$s</xliff:g> басқарады. Бұл профиль жұмыс желісіндегі белсенділігіңізді, соның ішінде электрондық хабарларды, қолданбаларды және веб-сайттарды бақылай алатын <xliff:g id="APPLICATION_WORK">%2$s</xliff:g> қолданбасына қосылған.\n\nСондай-ақ сіз жеке желідегі белсенділігіңізді бақылай алатын <xliff:g id="APPLICATION_PERSONAL">%3$s</xliff:g> қолданбасына қосылғансыз."</string>
<string name="keyguard_indication_trust_unlocked" msgid="7395154975733744547">"TrustAgent арқылы құлпы ашылды."</string>
<string name="keyguard_indication_trust_disabled" msgid="6820793704816727918">"Қолмен бекітпесін ашқанша құрылғы бекітілген күйде қалады"</string>
+ <string name="keyguard_indication_trust_unlocked_plugged_in" msgid="2323452175329362855">"<xliff:g id="KEYGUARD_INDICATION">%1$s</xliff:g>\n<xliff:g id="POWER_INDICATION">%2$s</xliff:g>"</string>
<string name="hidden_notifications_title" msgid="1782412844777612795">"Хабарландыруларды тезірек алу"</string>
<string name="hidden_notifications_text" msgid="5899627470450792578">"Бекітпесін ашу алдында оларды көру"</string>
<string name="hidden_notifications_cancel" msgid="4805370226181001278">"Жоқ, рақмет"</string>
@@ -979,12 +980,9 @@
<string name="bubble_accessibility_action_move_bottom_left" msgid="6339015902495504715">"Төменгі сол жаққа жылжыту"</string>
<string name="bubble_accessibility_action_move_bottom_right" msgid="7471571700628346212">"Төменгі оң жаққа жылжыту"</string>
<string name="bubble_dismiss_text" msgid="7071770411580452911">"Жабу"</string>
- <!-- no translation found for bubbles_user_education_title (3385222165904578710) -->
- <skip />
- <!-- no translation found for bubbles_user_education_description (6663205638091146934) -->
- <skip />
- <!-- no translation found for bubbles_user_education_manage (1391639189507036423) -->
- <skip />
+ <string name="bubbles_user_education_title" msgid="3385222165904578710">"Чаттарды жоғары жақтан көрсету"</string>
+ <string name="bubbles_user_education_description" msgid="6663205638091146934">"<xliff:g id="APP_NAME">%1$s</xliff:g> қолданбасындағы жаңа чаттар қалқымалы анықтамалар түрінде шығады. Қалқымалы анықтаманы ашу үшін оны түртіңіз. Оны сүйреп жылжытыңыз.\n\nҚалқымалы анықтаманы түртіңіз."</string>
+ <string name="bubbles_user_education_manage" msgid="1391639189507036423">"Бұл қолданбадан қалқымалы анықтамаларды өшіру үшін \"Басқару\" түймесін түртіңіз."</string>
<string name="notification_content_system_nav_changed" msgid="5077913144844684544">"Жүйе навигациясы жаңартылды. Өзгерту енгізу үшін \"Параметрлер\" бөліміне өтіңіз."</string>
<string name="notification_content_gesture_nav_available" msgid="4431460803004659888">"Жүйе навигациясын жаңарту үшін \"Параметрлер\" бөліміне өтіңіз."</string>
<string name="inattentive_sleep_warning_title" msgid="3891371591713990373">"Күту режимі"</string>
@@ -1004,4 +1002,10 @@
<string name="controls_favorite_header_all" msgid="7507855973418969992">"Барлығы"</string>
<string name="controls_favorite_load_error" msgid="2533215155804455348">"Барлық басқару элементі тізімі жүктелмеді."</string>
<string name="controls_favorite_other_zone_header" msgid="9089613266575525252">"Басқа"</string>
+ <!-- no translation found for controls_dialog_title (8806193219278278442) -->
+ <skip />
+ <!-- no translation found for controls_dialog_ok (7011816381344485651) -->
+ <skip />
+ <!-- no translation found for controls_dialog_message (6292099631702047540) -->
+ <skip />
</resources>
diff --git a/packages/SystemUI/res/values-km/strings.xml b/packages/SystemUI/res/values-km/strings.xml
index 8306dfff883f..d8d300f5fb5f 100644
--- a/packages/SystemUI/res/values-km/strings.xml
+++ b/packages/SystemUI/res/values-km/strings.xml
@@ -558,6 +558,7 @@
<string name="monitoring_description_app_personal_work" msgid="6175816356939166101">"កម្រងព័ត៌មាន​ការងារ​របស់អ្នក​ស្ថិតក្រោម​គ្រប់គ្រង​របស់ <xliff:g id="ORGANIZATION">%1$s</xliff:g> ។ កម្រង​ព័ត៌មាននេះ​ត្រូវបាន​ភ្ជាប់​ទៅ <xliff:g id="APPLICATION_WORK">%2$s</xliff:g> ដែលអាច​តាមដាន​សកម្មភាព​បណ្តាញ​របស់អ្នក រួមទាំង​អ៊ីមែល កម្មវិធី និង​គេហទំព័រ​ផងដែរ។\n\nអ្នកក៏ត្រូវបាន​ភ្ជាប់​ទៅ <xliff:g id="APPLICATION_PERSONAL">%3$s</xliff:g> ដែលអាច​តាមដាន​សកម្មភាព​បណ្តាញ​ផ្ទាល់ខ្លួន​របស់​អ្នក។"</string>
<string name="keyguard_indication_trust_unlocked" msgid="7395154975733744547">"បាន​ដោះសោ​ដោយភ្នាក់ងារ​​ទុកចិត្ត"</string>
<string name="keyguard_indication_trust_disabled" msgid="6820793704816727918">"ឧបករណ៍​នឹង​ចាក់​សោ​រហូត​ដល់​អ្នក​ដោះ​សោ​ដោយ​ដៃ"</string>
+ <string name="keyguard_indication_trust_unlocked_plugged_in" msgid="2323452175329362855">"<xliff:g id="KEYGUARD_INDICATION">%1$s</xliff:g>\n<xliff:g id="POWER_INDICATION">%2$s</xliff:g>"</string>
<string name="hidden_notifications_title" msgid="1782412844777612795">"ទទួល​បាន​ការ​ជូន​ដំណឹង​កាន់តែ​លឿន"</string>
<string name="hidden_notifications_text" msgid="5899627470450792578">"ឃើញ​ពួកវា​មុន​ពេល​ដោះ​សោ"</string>
<string name="hidden_notifications_cancel" msgid="4805370226181001278">"ទេ អរគុណ!"</string>
@@ -979,12 +980,9 @@
<string name="bubble_accessibility_action_move_bottom_left" msgid="6339015902495504715">"ផ្លាស់ទីទៅផ្នែកខាងក្រោមខាងឆ្វេង​"</string>
<string name="bubble_accessibility_action_move_bottom_right" msgid="7471571700628346212">"ផ្លាស់ទីទៅផ្នែកខាងក្រោម​ខាងស្ដាំ"</string>
<string name="bubble_dismiss_text" msgid="7071770411580452911">"ច្រានចោល"</string>
- <!-- no translation found for bubbles_user_education_title (3385222165904578710) -->
- <skip />
- <!-- no translation found for bubbles_user_education_description (6663205638091146934) -->
- <skip />
- <!-- no translation found for bubbles_user_education_manage (1391639189507036423) -->
- <skip />
+ <string name="bubbles_user_education_title" msgid="3385222165904578710">"រក្សាទុកការជជែក​នៅផ្នែក​ខាងមុខ"</string>
+ <string name="bubbles_user_education_description" msgid="6663205638091146934">"ការជជែកថ្មីៗពី <xliff:g id="APP_NAME">%1$s</xliff:g> នឹងបង្ហាញ​ជាសារលេចឡើង។ ចុច​សារលេច​ឡើង ដើម្បី​បើកវា។ អូស​ដើម្បីផ្លាស់ទី​សារលេចឡើងនេះ។\n\nចុចសារ​លេចឡើងនេះ"</string>
+ <string name="bubbles_user_education_manage" msgid="1391639189507036423">"ចុច \"គ្រប់គ្រង\" ដើម្បីបិទ​សារលេចឡើង​ពីកម្មវិធីនេះ"</string>
<string name="notification_content_system_nav_changed" msgid="5077913144844684544">"បានធ្វើ​បច្ចុប្បន្នភាព​ការរុករកក្នុង​ប្រព័ន្ធ។ ដើម្បីធ្វើការផ្លាស់ប្ដូរ សូមចូលទៅ​កាន់ការកំណត់។"</string>
<string name="notification_content_gesture_nav_available" msgid="4431460803004659888">"ចូល​ទៅកាន់​ការកំណត់ ដើម្បី​ធ្វើបច្ចុប្បន្នភាព​ការរុករក​ក្នុង​ប្រព័ន្ធ"</string>
<string name="inattentive_sleep_warning_title" msgid="3891371591713990373">"ផ្អាក​ដំណើរការ"</string>
@@ -1004,4 +1002,10 @@
<string name="controls_favorite_header_all" msgid="7507855973418969992">"ទាំងអស់"</string>
<string name="controls_favorite_load_error" msgid="2533215155804455348">"មិនអាច​ផ្ទុក​បញ្ជី​នៃការគ្រប់គ្រង​ទាំងអស់​បានទេ។"</string>
<string name="controls_favorite_other_zone_header" msgid="9089613266575525252">"ផ្សេងៗ"</string>
+ <!-- no translation found for controls_dialog_title (8806193219278278442) -->
+ <skip />
+ <!-- no translation found for controls_dialog_ok (7011816381344485651) -->
+ <skip />
+ <!-- no translation found for controls_dialog_message (6292099631702047540) -->
+ <skip />
</resources>
diff --git a/packages/SystemUI/res/values-kn/strings.xml b/packages/SystemUI/res/values-kn/strings.xml
index 880e083c9614..0165b0858142 100644
--- a/packages/SystemUI/res/values-kn/strings.xml
+++ b/packages/SystemUI/res/values-kn/strings.xml
@@ -558,6 +558,8 @@
<string name="monitoring_description_app_personal_work" msgid="6175816356939166101">"ನಿಮ್ಮ ಉದ್ಯೋಗ ಪ್ರೊಫೈಲ್‌ ಅನ್ನು <xliff:g id="ORGANIZATION">%1$s</xliff:g> ನಿರ್ವಹಿಸುತ್ತಿದೆ. <xliff:g id="APPLICATION_WORK">%2$s</xliff:g> ಗೆ ಪ್ರೊಫೈಲ್ ಸಂಪರ್ಕಗೊಂಡಿರುವ ಕಾರಣ, ಅದು ನಿಮ್ಮ ಇಮೇಲ್‌ಗಳು, ಅಪ್ಲಿಕೇಶನ್‌ಗಳು ಮತ್ತು ವೆಬ್‌ಸೈಟ್‌ಗಳೂ ಸೇರಿದಂತೆ ನೆಟ್‌ವರ್ಕ್ ಚಟುವಟಿಕೆಯನ್ನು ಮೇಲ್ವಿಚಾರಣೆ ಮಾಡಬಹುದು.\n\nನೀವು <xliff:g id="APPLICATION_PERSONAL">%3$s</xliff:g> ಗೆ ಕೂಡಾ ಸಂಪರ್ಕಗೊಂಡಿದ್ದೀರಿ, ಇದು ನಿಮ್ಮ ವೈಯಕ್ತಿಕ ನೆಟ್‌ವರ್ಕ್ ಚಟುವಟಿಕೆಯನ್ನು ಮೇಲ್ವಿಚಾರಣೆ ಮಾಡಬಹುದು."</string>
<string name="keyguard_indication_trust_unlocked" msgid="7395154975733744547">"TrustAgent ನಿಂದ ಅನ್‌ಲಾಕ್ ಮಾಡಲಾಗಿದೆ"</string>
<string name="keyguard_indication_trust_disabled" msgid="6820793704816727918">"ನೀವಾಗಿಯೇ ಅನ್‌ಲಾಕ್‌ ಮಾಡುವವರೆಗೆ ಸಾಧನವು ಲಾಕ್‌ ಆಗಿಯೇ ಇರುತ್ತದೆ"</string>
+ <!-- no translation found for keyguard_indication_trust_unlocked_plugged_in (2323452175329362855) -->
+ <skip />
<string name="hidden_notifications_title" msgid="1782412844777612795">"ವೇಗವಾಗಿ ಅಧಿಸೂಚನೆಗಳನ್ನು ಪಡೆದುಕೊಳ್ಳಿ"</string>
<string name="hidden_notifications_text" msgid="5899627470450792578">"ನೀವು ಅನ್‌ಲಾಕ್‌ ಮಾಡುವ ಮೊದಲೇ ಅವುಗಳನ್ನು ನೋಡಿ"</string>
<string name="hidden_notifications_cancel" msgid="4805370226181001278">"ಧನ್ಯವಾದಗಳು"</string>
@@ -979,12 +981,9 @@
<string name="bubble_accessibility_action_move_bottom_left" msgid="6339015902495504715">"ಸ್ಕ್ರೀನ್‌ನ ಎಡ ಕೆಳಭಾಗಕ್ಕೆ ಸರಿಸಿ"</string>
<string name="bubble_accessibility_action_move_bottom_right" msgid="7471571700628346212">"ಕೆಳಗಿನ ಬಲಭಾಗಕ್ಕೆ ಸರಿಸಿ"</string>
<string name="bubble_dismiss_text" msgid="7071770411580452911">"ವಜಾಗೊಳಿಸಿ"</string>
- <!-- no translation found for bubbles_user_education_title (3385222165904578710) -->
- <skip />
- <!-- no translation found for bubbles_user_education_description (6663205638091146934) -->
- <skip />
- <!-- no translation found for bubbles_user_education_manage (1391639189507036423) -->
- <skip />
+ <string name="bubbles_user_education_title" msgid="3385222165904578710">"ಚಾಟ್‌ಗಳನ್ನು ಮುಂಚೂಣಿಯಲ್ಲಿಡಿ"</string>
+ <string name="bubbles_user_education_description" msgid="6663205638091146934">"<xliff:g id="APP_NAME">%1$s</xliff:g> ನಿಂದ ಹೊಸ ಚಾಟ್‌ಗಳು ಬಬಲ್‌ಗಳಾಗಿ ಕಾಣಿಸುತ್ತದೆ. ಅದನ್ನು ತೆರೆಯಲು ಬಬಲ್ ಅನ್ನು ಟ್ಯಾಪ್ ಮಾಡಿ. ಅದನ್ನು ಸರಿಸಲು ಡ್ರ್ಯಾಗ್ ಮಾಡಿ.\n\nಬಬಲ್ ಅನ್ನು ಟ್ಯಾಪ್ ಮಾಡಿ"</string>
+ <string name="bubbles_user_education_manage" msgid="1391639189507036423">"ಈ ಆ್ಯಪ್‌ನಿಂದ ಬಬಲ್‌ಗಳನ್ನು ಆಫ್ ಮಾಡಲು ನಿರ್ವಹಿಸಿ ಟ್ಯಾಪ್ ಮಾಡಿ"</string>
<string name="notification_content_system_nav_changed" msgid="5077913144844684544">"ಸಿಸ್ಟಂ ನ್ಯಾವಿಗೇಷನ ಅಪ್‌ಡೇಟ್ ಮಾಡಲಾಗಿದೆ ಬದಲಾವಣೆಗಳನ್ನು ಮಾಡಲು, ಸೆಟ್ಟಿಂಗ್‌ಗಳಿಗೆ ಹೋಗಿ."</string>
<string name="notification_content_gesture_nav_available" msgid="4431460803004659888">"ಸಿಸ್ಟಂ ನ್ಯಾವಿಗೇಷನ್ ಅಪ್‌ಡೇಟ್ ಮಾಡಲು ಸೆಟ್ಟಿಂಗ್‌ಗಳಿಗೆ ಹೋಗಿ"</string>
<string name="inattentive_sleep_warning_title" msgid="3891371591713990373">"ಸ್ಟ್ಯಾಂಡ್‌ಬೈ"</string>
@@ -994,12 +993,20 @@
<string name="quick_controls_title" msgid="525285759614231333">"ತ್ವರಿತ ನಿಯಂತ್ರಣಗಳು"</string>
<string name="controls_providers_title" msgid="8844124515157926071">"ನಿಯಂತ್ರಣಗಳನ್ನು ಸೇರಿಸಿ"</string>
<string name="controls_providers_subtitle" msgid="8187768950110836569">"ನಿಯಂತ್ರಣಗಳನ್ನು ಸೇರಿಸಲು ಆ್ಯಪ್ ಅನ್ನು ಆಯ್ಕೆಮಾಡಿ"</string>
- <!-- no translation found for controls_number_of_favorites (1057347832073807380) -->
+ <plurals name="controls_number_of_favorites" formatted="false" msgid="1057347832073807380">
+ <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="controls_favorite_default_title" msgid="967742178688938137">"ನಿಯಂತ್ರಣಗಳು"</string>
<string name="controls_favorite_subtitle" msgid="4049644994401173949">"ತ್ವರಿತ ಪ್ರವೇಶಕ್ಕಾಗಿ ನಿಯಂತ್ರಣಗಳನ್ನು ಆಯ್ಕೆಮಾಡಿ"</string>
<string name="controls_favorite_header_favorites" msgid="3118600046217493471">"ಮೆಚ್ಚಿನವುಗಳು"</string>
<string name="controls_favorite_header_all" msgid="7507855973418969992">"ಎಲ್ಲಾ"</string>
<string name="controls_favorite_load_error" msgid="2533215155804455348">"ಎಲ್ಲಾ ನಿಯಂತ್ರಣಗಳ ಪಟ್ಟಿಯನ್ನು ಲೋಡ್ ಮಾಡಲು ಆಗಲಿಲ್ಲ."</string>
- <!-- no translation found for controls_favorite_other_zone_header (9089613266575525252) -->
+ <string name="controls_favorite_other_zone_header" msgid="9089613266575525252">"ಇತರ"</string>
+ <!-- no translation found for controls_dialog_title (8806193219278278442) -->
+ <skip />
+ <!-- no translation found for controls_dialog_ok (7011816381344485651) -->
+ <skip />
+ <!-- no translation found for controls_dialog_message (6292099631702047540) -->
<skip />
</resources>
diff --git a/packages/SystemUI/res/values-ko/strings.xml b/packages/SystemUI/res/values-ko/strings.xml
index ca8cdb031774..64f5ff849289 100644
--- a/packages/SystemUI/res/values-ko/strings.xml
+++ b/packages/SystemUI/res/values-ko/strings.xml
@@ -558,6 +558,7 @@
<string name="monitoring_description_app_personal_work" msgid="6175816356939166101">"직장 프로필은 <xliff:g id="ORGANIZATION">%1$s</xliff:g>에서 관리합니다. 이 프로필은 <xliff:g id="APPLICATION_WORK">%2$s</xliff:g>에 연결되어 이메일, 앱, 웹사이트와 같은 직장 네트워크 활동을 모니터링할 수 있습니다.\n\n개인 네트워크 활동을 모니터링할 수 있는 <xliff:g id="APPLICATION_PERSONAL">%3$s</xliff:g>에도 연결됩니다."</string>
<string name="keyguard_indication_trust_unlocked" msgid="7395154975733744547">"TrustAgent가 잠금 해제함"</string>
<string name="keyguard_indication_trust_disabled" msgid="6820793704816727918">"수동으로 잠금 해제할 때까지 기기가 잠금 상태로 유지됩니다."</string>
+ <string name="keyguard_indication_trust_unlocked_plugged_in" msgid="2323452175329362855">"<xliff:g id="KEYGUARD_INDICATION">%1$s</xliff:g>\n<xliff:g id="POWER_INDICATION">%2$s</xliff:g>"</string>
<string name="hidden_notifications_title" msgid="1782412844777612795">"알림을 더욱 빠르게 받기"</string>
<string name="hidden_notifications_text" msgid="5899627470450792578">"잠금 해제하기 전에 알림을 봅니다."</string>
<string name="hidden_notifications_cancel" msgid="4805370226181001278">"사용 안함"</string>
@@ -979,12 +980,9 @@
<string name="bubble_accessibility_action_move_bottom_left" msgid="6339015902495504715">"왼쪽 하단으로 이동"</string>
<string name="bubble_accessibility_action_move_bottom_right" msgid="7471571700628346212">"오른쪽 하단으로 이동"</string>
<string name="bubble_dismiss_text" msgid="7071770411580452911">"닫기"</string>
- <!-- no translation found for bubbles_user_education_title (3385222165904578710) -->
- <skip />
- <!-- no translation found for bubbles_user_education_description (6663205638091146934) -->
- <skip />
- <!-- no translation found for bubbles_user_education_manage (1391639189507036423) -->
- <skip />
+ <string name="bubbles_user_education_title" msgid="3385222165904578710">"채팅을 항상 상단에 표시"</string>
+ <string name="bubbles_user_education_description" msgid="6663205638091146934">"<xliff:g id="APP_NAME">%1$s</xliff:g>의 새로운 채팅이 버블로 표시됩니다. 버블을 열려면 탭하세요. 버블을 이동하려면 드래그하세요.\n\n버블을 탭하세요."</string>
+ <string name="bubbles_user_education_manage" msgid="1391639189507036423">"이 앱에서 버블을 사용 중지하려면 관리를 탭하세요."</string>
<string name="notification_content_system_nav_changed" msgid="5077913144844684544">"시스템 탐색이 업데이트되었습니다. 변경하려면 설정으로 이동하세요."</string>
<string name="notification_content_gesture_nav_available" msgid="4431460803004659888">"설정으로 이동하여 시스템 탐색을 업데이트하세요."</string>
<string name="inattentive_sleep_warning_title" msgid="3891371591713990373">"대기"</string>
@@ -1004,4 +1002,10 @@
<string name="controls_favorite_header_all" msgid="7507855973418969992">"전체"</string>
<string name="controls_favorite_load_error" msgid="2533215155804455348">"전체 컨트롤 목록을 로드할 수 없습니다."</string>
<string name="controls_favorite_other_zone_header" msgid="9089613266575525252">"기타"</string>
+ <!-- no translation found for controls_dialog_title (8806193219278278442) -->
+ <skip />
+ <!-- no translation found for controls_dialog_ok (7011816381344485651) -->
+ <skip />
+ <!-- no translation found for controls_dialog_message (6292099631702047540) -->
+ <skip />
</resources>
diff --git a/packages/SystemUI/res/values-ky/strings.xml b/packages/SystemUI/res/values-ky/strings.xml
index 719380e4aba7..00d66992c0ab 100644
--- a/packages/SystemUI/res/values-ky/strings.xml
+++ b/packages/SystemUI/res/values-ky/strings.xml
@@ -558,6 +558,7 @@
<string name="monitoring_description_app_personal_work" msgid="6175816356939166101">"Жумуш профилиңизди <xliff:g id="ORGANIZATION">%1$s</xliff:g> башкарат. Ал электрондук почта, колдонмолор жана вебсайттар сыяктуу жумуш тармагыңыздагы аракеттерди көзөмөлдөй турган <xliff:g id="APPLICATION_WORK">%2$s</xliff:g> колдонмосуна туташкан.\n\nМындан тышкары, тармактагы жеке аракеттериңизди көзөмөлдөгөн <xliff:g id="APPLICATION_PERSONAL">%3$s</xliff:g> колдонмосуна туташып турасыз."</string>
<string name="keyguard_indication_trust_unlocked" msgid="7395154975733744547">"Ишеним агенти кулпусун ачты"</string>
<string name="keyguard_indication_trust_disabled" msgid="6820793704816727918">"Түзмөктүн кулпусу кол менен ачылмайынча кулпуланган бойдон алат"</string>
+ <string name="keyguard_indication_trust_unlocked_plugged_in" msgid="2323452175329362855">"<xliff:g id="KEYGUARD_INDICATION">%1$s</xliff:g>\n<xliff:g id="POWER_INDICATION">%2$s</xliff:g>"</string>
<string name="hidden_notifications_title" msgid="1782412844777612795">"Эскертмелерди тезирээк алуу"</string>
<string name="hidden_notifications_text" msgid="5899627470450792578">"Аларды кулпудан чыгараардан мурун көрүңүз"</string>
<string name="hidden_notifications_cancel" msgid="4805370226181001278">"Жок, рахмат"</string>
@@ -979,12 +980,9 @@
<string name="bubble_accessibility_action_move_bottom_left" msgid="6339015902495504715">"Төмөнкү сол жакка жылдыруу"</string>
<string name="bubble_accessibility_action_move_bottom_right" msgid="7471571700628346212">"Төмөнкү оң жакка жылдырыңыз"</string>
<string name="bubble_dismiss_text" msgid="7071770411580452911">"Жабуу"</string>
- <!-- no translation found for bubbles_user_education_title (3385222165904578710) -->
- <skip />
- <!-- no translation found for bubbles_user_education_description (6663205638091146934) -->
- <skip />
- <!-- no translation found for bubbles_user_education_manage (1391639189507036423) -->
- <skip />
+ <string name="bubbles_user_education_title" msgid="3385222165904578710">"Маектерди ар дайым көрүп туруңуз"</string>
+ <string name="bubbles_user_education_description" msgid="6663205638091146934">"<xliff:g id="APP_NAME">%1$s</xliff:g> колдонмосундагы жаңы маектер калкып чыкма билдирмелер түрүндө көрүнөт. Аны ачуу үчүн калкып чыкма билдирмени таптап коюңуз. Аны сүйрөп жылдырыңыз.\n\nКалкып чыкма билдирмени таптап коюңуз"</string>
+ <string name="bubbles_user_education_manage" msgid="1391639189507036423">"Бул колдонмодогу калкып чыкма билдирмелерди өчүрүү үчүн \"Башкарууну\" басыңыз"</string>
<string name="notification_content_system_nav_changed" msgid="5077913144844684544">"Тутум чабыттоосу жаңырды. Өзгөртүү үчүн, Жөндөөлөргө өтүңүз."</string>
<string name="notification_content_gesture_nav_available" msgid="4431460803004659888">"Тутум чабыттоосун жаңыртуу үчүн Жөндөөлөргө өтүңүз"</string>
<string name="inattentive_sleep_warning_title" msgid="3891371591713990373">"Көшүү режими"</string>
@@ -1004,4 +1002,10 @@
<string name="controls_favorite_header_all" msgid="7507855973418969992">"Баары"</string>
<string name="controls_favorite_load_error" msgid="2533215155804455348">"Бардык көзөмөлдөрдүн тизмеси жүктөлгөн жок."</string>
<string name="controls_favorite_other_zone_header" msgid="9089613266575525252">"Башка"</string>
+ <!-- no translation found for controls_dialog_title (8806193219278278442) -->
+ <skip />
+ <!-- no translation found for controls_dialog_ok (7011816381344485651) -->
+ <skip />
+ <!-- no translation found for controls_dialog_message (6292099631702047540) -->
+ <skip />
</resources>
diff --git a/packages/SystemUI/res/values-land-television/dimens.xml b/packages/SystemUI/res/values-land-television/dimens.xml
new file mode 100644
index 000000000000..499341c662b1
--- /dev/null
+++ b/packages/SystemUI/res/values-land-television/dimens.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2019 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+
+<resources>
+ <!-- Width of volume bar -->
+ <dimen name="volume_dialog_row_width">252dp</dimen>
+ <dimen name="volume_dialog_tap_target_size">36dp</dimen>
+</resources>
diff --git a/packages/SystemUI/res/values-lo/strings.xml b/packages/SystemUI/res/values-lo/strings.xml
index 1737e0c5e360..c93700110f2c 100644
--- a/packages/SystemUI/res/values-lo/strings.xml
+++ b/packages/SystemUI/res/values-lo/strings.xml
@@ -558,6 +558,7 @@
<string name="monitoring_description_app_personal_work" msgid="6175816356939166101">"ໂປຣໄຟລ໌ບ່ອນເຮັດວຽກຂອງທ່ານແມ່ນຖືກຈັດການໂດຍ <xliff:g id="ORGANIZATION">%1$s</xliff:g>. ໂປຣໄຟລ໌ບ່ອນເຮັດວຽກດັ່ງກ່າວເຊື່ອມຕໍ່ຫາ <xliff:g id="APPLICATION_WORK">%2$s</xliff:g>, ເຊິ່ງສາມາດຕິດຕາມການເຄື່ອນໄຫວເຄືອຂ່າຍຂອງທ່ານ, ຮວມທັງອີເມວ, ແອັບ ແລະ ເວັບໄຊໄດ້.\n\nນອກຈາກນັ້ນ, ທ່ານຍັງເຊື່ອມຕໍ່ຫາ <xliff:g id="APPLICATION_PERSONAL">%3$s</xliff:g>, ເຊິ່ງສາມາດຕິດຕາມການເຄື່ອນໄຫວເຄືອຂ່າຍສ່ວນຕົວຂອງທ່ານໄດ້."</string>
<string name="keyguard_indication_trust_unlocked" msgid="7395154975733744547">"ປັອດລັອກປະໄວ້ໂດຍ TrustAgent"</string>
<string name="keyguard_indication_trust_disabled" msgid="6820793704816727918">"Device will stay locked until you manually unlock"</string>
+ <string name="keyguard_indication_trust_unlocked_plugged_in" msgid="2323452175329362855">"<xliff:g id="KEYGUARD_INDICATION">%1$s</xliff:g>\n<xliff:g id="POWER_INDICATION">%2$s</xliff:g>"</string>
<string name="hidden_notifications_title" msgid="1782412844777612795">"ຮັບເອົາການ​ແຈ້ງເຕືອນ​ໄວຂຶ້ນ"</string>
<string name="hidden_notifications_text" msgid="5899627470450792578">"ເບິ່ງພວກ​ມັນກ່ອນ​ທ່ານຈະ​ປົດລັອກ"</string>
<string name="hidden_notifications_cancel" msgid="4805370226181001278">"ບໍ່, ຂອບໃຈ"</string>
@@ -979,12 +980,9 @@
<string name="bubble_accessibility_action_move_bottom_left" msgid="6339015902495504715">"ຍ້າຍຊ້າຍລຸ່ມ"</string>
<string name="bubble_accessibility_action_move_bottom_right" msgid="7471571700628346212">"ຍ້າຍຂວາລຸ່ມ"</string>
<string name="bubble_dismiss_text" msgid="7071770411580452911">"ປິດໄວ້"</string>
- <!-- no translation found for bubbles_user_education_title (3385222165904578710) -->
- <skip />
- <!-- no translation found for bubbles_user_education_description (6663205638091146934) -->
- <skip />
- <!-- no translation found for bubbles_user_education_manage (1391639189507036423) -->
- <skip />
+ <string name="bubbles_user_education_title" msgid="3385222165904578710">"ສະແດງການສົນທະນາໄວ້ໜ້າສະເໝີ"</string>
+ <string name="bubbles_user_education_description" msgid="6663205638091146934">"ການສົນທະນາໃໝ່ຈາກ <xliff:g id="APP_NAME">%1$s</xliff:g> ຈະປາກົດເປັນ bubble. ແຕະໃສ່ bubble ເພື່ອເປີດມັນ ລາກເພື່ອເປີດມັນ.\n\nແຕະໃສ່ bubble"</string>
+ <string name="bubbles_user_education_manage" msgid="1391639189507036423">"ແຕະຈັດການເພື່ອປິດ bubble ຈາກແອັບນີ້"</string>
<string name="notification_content_system_nav_changed" msgid="5077913144844684544">"ອັບເດດການນຳທາງລະບົບແລ້ວ. ເພື່ອປ່ຽນແປງ, ກະລຸນາໄປທີ່ການຕັ້ງຄ່າ."</string>
<string name="notification_content_gesture_nav_available" msgid="4431460803004659888">"ໄປທີ່ການຕັ້ງຄ່າເພື່ອອັບເດດການນຳທາງລະບົບ"</string>
<string name="inattentive_sleep_warning_title" msgid="3891371591713990373">"ສະແຕນບາຍ"</string>
@@ -1004,4 +1002,10 @@
<string name="controls_favorite_header_all" msgid="7507855973418969992">"ທັງໝົດ"</string>
<string name="controls_favorite_load_error" msgid="2533215155804455348">"ບໍ່ສາມາດໂຫຼດລາຍຊື່ການຄວບຄຸມທັງໝົດໄດ້."</string>
<string name="controls_favorite_other_zone_header" msgid="9089613266575525252">"ອື່ນໆ"</string>
+ <!-- no translation found for controls_dialog_title (8806193219278278442) -->
+ <skip />
+ <!-- no translation found for controls_dialog_ok (7011816381344485651) -->
+ <skip />
+ <!-- no translation found for controls_dialog_message (6292099631702047540) -->
+ <skip />
</resources>
diff --git a/packages/SystemUI/res/values-lt/strings.xml b/packages/SystemUI/res/values-lt/strings.xml
index 31fd57ff8e0d..d4988789c737 100644
--- a/packages/SystemUI/res/values-lt/strings.xml
+++ b/packages/SystemUI/res/values-lt/strings.xml
@@ -564,6 +564,7 @@
<string name="monitoring_description_app_personal_work" msgid="6175816356939166101">"Jūsų darbo profilį tvarko „<xliff:g id="ORGANIZATION">%1$s</xliff:g>“. Profilis susietas su programa „<xliff:g id="APPLICATION_WORK">%2$s</xliff:g>“, kuri gali stebėti jūsų tinklo veiklą, įskaitant el. laiškus, programas ir svetaines.\n\nTaip pat esate prisijungę prie programos „<xliff:g id="APPLICATION_PERSONAL">%3$s</xliff:g>“, kuri gali stebėti asmeninio tinklo veiklą."</string>
<string name="keyguard_indication_trust_unlocked" msgid="7395154975733744547">"Atrakinta taikant „TrustAgent“"</string>
<string name="keyguard_indication_trust_disabled" msgid="6820793704816727918">"Įrenginys liks užrakintas, kol neatrakinsite jo neautomatiniu būdu"</string>
+ <string name="keyguard_indication_trust_unlocked_plugged_in" msgid="2323452175329362855">"<xliff:g id="KEYGUARD_INDICATION">%1$s</xliff:g>\n<xliff:g id="POWER_INDICATION">%2$s</xliff:g>"</string>
<string name="hidden_notifications_title" msgid="1782412844777612795">"Greičiau gaukite pranešimus"</string>
<string name="hidden_notifications_text" msgid="5899627470450792578">"Peržiūrėti prieš atrakinant"</string>
<string name="hidden_notifications_cancel" msgid="4805370226181001278">"Ne, ačiū"</string>
@@ -989,12 +990,9 @@
<string name="bubble_accessibility_action_move_bottom_left" msgid="6339015902495504715">"Perkelti į apačią kairėje"</string>
<string name="bubble_accessibility_action_move_bottom_right" msgid="7471571700628346212">"Perkelti į apačią dešinėje"</string>
<string name="bubble_dismiss_text" msgid="7071770411580452911">"Atmesti"</string>
- <!-- no translation found for bubbles_user_education_title (3385222165904578710) -->
- <skip />
- <!-- no translation found for bubbles_user_education_description (6663205638091146934) -->
- <skip />
- <!-- no translation found for bubbles_user_education_manage (1391639189507036423) -->
- <skip />
+ <string name="bubbles_user_education_title" msgid="3385222165904578710">"Rodyti pokalbius priekyje"</string>
+ <string name="bubbles_user_education_description" msgid="6663205638091146934">"Nauji pokalbiai iš programos „<xliff:g id="APP_NAME">%1$s</xliff:g>“ bus rodomi kaip debesėliai. Palieskite debesėlį, kad jį atidarytumėte. Nuvilkite, kad perkeltumėte.\n\nPalieskite debesėlį"</string>
+ <string name="bubbles_user_education_manage" msgid="1391639189507036423">"Palieskite „Tvarkyti“, kad išjungtumėte debesėlius šioje programoje"</string>
<string name="notification_content_system_nav_changed" msgid="5077913144844684544">"Sistemos naršymo funkcijos atnaujintos. Jei norite pakeisti, eikite į skiltį „Nustatymai“."</string>
<string name="notification_content_gesture_nav_available" msgid="4431460803004659888">"Eikite į skiltį „Nustatymai“, kad atnaujintumėte sistemos naršymo funkcijas"</string>
<string name="inattentive_sleep_warning_title" msgid="3891371591713990373">"Budėjimo laikas"</string>
@@ -1016,4 +1014,10 @@
<string name="controls_favorite_header_all" msgid="7507855973418969992">"Visi"</string>
<string name="controls_favorite_load_error" msgid="2533215155804455348">"Nepavyko įkelti visų valdiklių sąrašo."</string>
<string name="controls_favorite_other_zone_header" msgid="9089613266575525252">"Kita"</string>
+ <!-- no translation found for controls_dialog_title (8806193219278278442) -->
+ <skip />
+ <!-- no translation found for controls_dialog_ok (7011816381344485651) -->
+ <skip />
+ <!-- no translation found for controls_dialog_message (6292099631702047540) -->
+ <skip />
</resources>
diff --git a/packages/SystemUI/res/values-lv/strings.xml b/packages/SystemUI/res/values-lv/strings.xml
index 44e15ccb03d4..a25ae2a6deaa 100644
--- a/packages/SystemUI/res/values-lv/strings.xml
+++ b/packages/SystemUI/res/values-lv/strings.xml
@@ -561,6 +561,7 @@
<string name="monitoring_description_app_personal_work" msgid="6175816356939166101">"Jūsu darba profilu pārvalda <xliff:g id="ORGANIZATION">%1$s</xliff:g>. Profils ir saistīts ar lietotni <xliff:g id="APPLICATION_WORK">%2$s</xliff:g>, kura var pārraudzīt jūsu tīklā veiktās darbības, tostarp saņemtos un nosūtītos e-pasta ziņojumus, instalētās lietotnes un apmeklētās tīmekļa vietnes.\n\nIr izveidots savienojums ar lietotni <xliff:g id="APPLICATION_PERSONAL">%3$s</xliff:g>, kas var pārraudzīt jūsu tīklā veiktās privātās darbības, tostarp saņemtos un nosūtītos e-pasta ziņojumus, instalētās lietotnes un apmeklētās tīmekļa vietnes."</string>
<string name="keyguard_indication_trust_unlocked" msgid="7395154975733744547">"Bloķēšanu liedzis TrustAgent"</string>
<string name="keyguard_indication_trust_disabled" msgid="6820793704816727918">"Ierīce būs bloķēta, līdz to manuāli atbloķēsiet."</string>
+ <string name="keyguard_indication_trust_unlocked_plugged_in" msgid="2323452175329362855">"<xliff:g id="KEYGUARD_INDICATION">%1$s</xliff:g>\n<xliff:g id="POWER_INDICATION">%2$s</xliff:g>"</string>
<string name="hidden_notifications_title" msgid="1782412844777612795">"Saņemiet paziņojumus ātrāk"</string>
<string name="hidden_notifications_text" msgid="5899627470450792578">"Skatiet tos pirms atbloķēšanas."</string>
<string name="hidden_notifications_cancel" msgid="4805370226181001278">"Nē"</string>
@@ -984,12 +985,9 @@
<string name="bubble_accessibility_action_move_bottom_left" msgid="6339015902495504715">"Pārvietot apakšpusē pa kreisi"</string>
<string name="bubble_accessibility_action_move_bottom_right" msgid="7471571700628346212">"Pārvietot apakšpusē pa labi"</string>
<string name="bubble_dismiss_text" msgid="7071770411580452911">"Nerādīt"</string>
- <!-- no translation found for bubbles_user_education_title (3385222165904578710) -->
- <skip />
- <!-- no translation found for bubbles_user_education_description (6663205638091146934) -->
- <skip />
- <!-- no translation found for bubbles_user_education_manage (1391639189507036423) -->
- <skip />
+ <string name="bubbles_user_education_title" msgid="3385222165904578710">"Sarunas priekšplānā"</string>
+ <string name="bubbles_user_education_description" msgid="6663205638091146934">"Jaunas sarunas no lietotnes <xliff:g id="APP_NAME">%1$s</xliff:g> tiks parādītas kā burbuļi. Pieskarieties kādam burbulim, lai to atvērtu. Velciet, lai to pārvietotu.\n\nPieskarieties burbulim."</string>
+ <string name="bubbles_user_education_manage" msgid="1391639189507036423">"Pieskarieties pogai “Pārvaldīt”, lai izslēgtu burbuļus no šīs lietotnes."</string>
<string name="notification_content_system_nav_changed" msgid="5077913144844684544">"Sistēmas navigācija ir atjaunināta. Lai veiktu izmaiņas, atveriet iestatījumus."</string>
<string name="notification_content_gesture_nav_available" msgid="4431460803004659888">"Atveriet iestatījumus, lai atjauninātu sistēmas navigāciju"</string>
<string name="inattentive_sleep_warning_title" msgid="3891371591713990373">"Gaidstāve"</string>
@@ -1010,4 +1008,10 @@
<string name="controls_favorite_header_all" msgid="7507855973418969992">"Visas"</string>
<string name="controls_favorite_load_error" msgid="2533215155804455348">"Nevarēja ielādēt sarakstu ar visām vadīklām."</string>
<string name="controls_favorite_other_zone_header" msgid="9089613266575525252">"Cita"</string>
+ <!-- no translation found for controls_dialog_title (8806193219278278442) -->
+ <skip />
+ <!-- no translation found for controls_dialog_ok (7011816381344485651) -->
+ <skip />
+ <!-- no translation found for controls_dialog_message (6292099631702047540) -->
+ <skip />
</resources>
diff --git a/packages/SystemUI/res/values-ml/strings.xml b/packages/SystemUI/res/values-ml/strings.xml
index 2e6f6f537602..47b05582658d 100644
--- a/packages/SystemUI/res/values-ml/strings.xml
+++ b/packages/SystemUI/res/values-ml/strings.xml
@@ -558,6 +558,8 @@
<string name="monitoring_description_app_personal_work" msgid="6175816356939166101">"<xliff:g id="ORGANIZATION">%1$s</xliff:g> ആണ് നിങ്ങളുടെ ഔദ്യോഗിക പ്രൊഫൈൽ മാനേജുചെയ്യുന്നത്. <xliff:g id="APPLICATION_WORK">%2$s</xliff:g> ആപ്പിലേക്ക് പ്രൊഫൈൽ കണക്റ്റുചെയ്‌തിരിക്കുന്നു, അതിന് ഇമെയിലുകൾ, ആപ്പുകൾ, വെബ്‌സൈറ്റുകൾ എന്നിവ ഉൾപ്പെടെ നിങ്ങളുടെ ഔദ്യോഗിക നെറ്റ്‌വർക്ക് ആക്റ്റിവിറ്റി നിരീക്ഷിക്കാനാകും.\n\n<xliff:g id="APPLICATION_PERSONAL">%3$s</xliff:g> ആപ്പിലേക്കും നിങ്ങൾ കണക്റ്റുചെയ്‌തിരിക്കുന്നു, അതിന് നിങ്ങളുടെ വ്യക്തിഗത നെറ്റ്‌വർക്ക് ആക്റ്റിവിറ്റി നിരീക്ഷിക്കാനാകും."</string>
<string name="keyguard_indication_trust_unlocked" msgid="7395154975733744547">"TrustAgent ഉപയോഗിച്ച് അൺലോക്ക് ചെയ്‌തത്"</string>
<string name="keyguard_indication_trust_disabled" msgid="6820793704816727918">"നിങ്ങൾ സ്വമേധയാ അൺലോക്കുചെയ്യുന്നതുവരെ ഉപകരണം ലോക്കുചെയ്‌തതായി തുടരും"</string>
+ <!-- no translation found for keyguard_indication_trust_unlocked_plugged_in (2323452175329362855) -->
+ <skip />
<string name="hidden_notifications_title" msgid="1782412844777612795">"അറിയിപ്പുകൾ വേഗത്തിൽ സ്വീകരിക്കുക"</string>
<string name="hidden_notifications_text" msgid="5899627470450792578">"അൺലോക്കുചെയ്യുന്നതിന് മുമ്പ് അവ കാണുക"</string>
<string name="hidden_notifications_cancel" msgid="4805370226181001278">"വേണ്ട, നന്ദി"</string>
@@ -979,12 +981,9 @@
<string name="bubble_accessibility_action_move_bottom_left" msgid="6339015902495504715">"ചുവടെ ഇടതുഭാഗത്തേക്ക് നീക്കുക"</string>
<string name="bubble_accessibility_action_move_bottom_right" msgid="7471571700628346212">"ചുവടെ വലതുഭാഗത്തേക്ക് നീക്കുക"</string>
<string name="bubble_dismiss_text" msgid="7071770411580452911">"ഡിസ്‌മിസ് ചെയ്യുക"</string>
- <!-- no translation found for bubbles_user_education_title (3385222165904578710) -->
- <skip />
- <!-- no translation found for bubbles_user_education_description (6663205638091146934) -->
- <skip />
- <!-- no translation found for bubbles_user_education_manage (1391639189507036423) -->
- <skip />
+ <string name="bubbles_user_education_title" msgid="3385222165904578710">"ചാറ്റുകൾ ഏറ്റവും ആദ്യം കാണുന്ന രീതിയിൽ വയ്ക്കുക"</string>
+ <string name="bubbles_user_education_description" msgid="6663205638091146934">"<xliff:g id="APP_NAME">%1$s</xliff:g> എന്നതിൽ നിന്നുള്ള പുതിയ ചാറ്റുകൾ ബബിളുകളായി ദൃശ്യമാവും. ഇത് തുറക്കാൻ ബബിൾ ടാപ്പ് ചെയ്യുക. ഇത് നീക്കാൻ വലിച്ചിടുക.\n\nബബിൾ ടാപ്പ് ചെയ്യുക"</string>
+ <string name="bubbles_user_education_manage" msgid="1391639189507036423">"ഈ ആപ്പിൽ നിന്നുള്ള ബബിളുകൾ ഓഫാക്കാൻ \'മാനേജ് ചെയ്യുക\' ടാപ്പ് ചെയ്യുക"</string>
<string name="notification_content_system_nav_changed" msgid="5077913144844684544">"സിസ്‌റ്റം നാവിഗേഷൻ അപ്‌ഡേറ്റ് ചെയ്‌തു. മാറ്റങ്ങൾ വരുത്താൻ ക്രമീകരണത്തിലേക്ക് പോവുക."</string>
<string name="notification_content_gesture_nav_available" msgid="4431460803004659888">"സിസ്‌റ്റം നാവിഗേഷൻ അപ്‌ഡേറ്റ് ചെയ്യാൻ ക്രമീകരണത്തിലേക്ക് പോവുക"</string>
<string name="inattentive_sleep_warning_title" msgid="3891371591713990373">"സ്‌റ്റാൻഡ്‌ബൈ"</string>
@@ -994,12 +993,20 @@
<string name="quick_controls_title" msgid="525285759614231333">"ദ്രുത നിയന്ത്രണങ്ങൾ"</string>
<string name="controls_providers_title" msgid="8844124515157926071">"നിയന്ത്രണങ്ങൾ ചേർക്കുക"</string>
<string name="controls_providers_subtitle" msgid="8187768950110836569">"നിയന്ത്രണങ്ങൾ ചേർക്കാൻ ഒരു ആപ്പ് തിരഞ്ഞെടുക്കുക"</string>
- <!-- no translation found for controls_number_of_favorites (1057347832073807380) -->
+ <plurals name="controls_number_of_favorites" formatted="false" msgid="1057347832073807380">
+ <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="controls_favorite_default_title" msgid="967742178688938137">"നിയന്ത്രണങ്ങൾ"</string>
<string name="controls_favorite_subtitle" msgid="4049644994401173949">"അതിവേഗ ആക്‌സസിനുള്ള നിയന്ത്രണങ്ങൾ തിരഞ്ഞെടുക്കുക"</string>
<string name="controls_favorite_header_favorites" msgid="3118600046217493471">"പ്രിയപ്പെട്ടവ"</string>
<string name="controls_favorite_header_all" msgid="7507855973418969992">"എല്ലാം"</string>
<string name="controls_favorite_load_error" msgid="2533215155804455348">"എല്ലാ നിയന്ത്രണങ്ങളുടെയും ലിസ്റ്റ് ലോഡ് ചെയ്യാനായില്ല."</string>
- <!-- no translation found for controls_favorite_other_zone_header (9089613266575525252) -->
+ <string name="controls_favorite_other_zone_header" msgid="9089613266575525252">"മറ്റുള്ളവ"</string>
+ <!-- no translation found for controls_dialog_title (8806193219278278442) -->
+ <skip />
+ <!-- no translation found for controls_dialog_ok (7011816381344485651) -->
+ <skip />
+ <!-- no translation found for controls_dialog_message (6292099631702047540) -->
<skip />
</resources>
diff --git a/packages/SystemUI/res/values-mn/strings.xml b/packages/SystemUI/res/values-mn/strings.xml
index ea93816a89e4..247a81db5e13 100644
--- a/packages/SystemUI/res/values-mn/strings.xml
+++ b/packages/SystemUI/res/values-mn/strings.xml
@@ -558,6 +558,7 @@
<string name="monitoring_description_app_personal_work" msgid="6175816356939166101">"Таны ажлын профайлыг <xliff:g id="ORGANIZATION">%1$s</xliff:g> удирддаг. Энэ нь таны имэйл, апп, вэб хуудас зэрэг сүлжээний үйл ажиллагааг хянах боломжтой <xliff:g id="APPLICATION_WORK">%2$s</xliff:g>-тай холбогдсон. \n\nМөн таны сүлжээний хувийн үйл ажиллагааг хянах боломжтой <xliff:g id="APPLICATION_PERSONAL">%3$s</xliff:g>-д холбогдсон байна."</string>
<string name="keyguard_indication_trust_unlocked" msgid="7395154975733744547">"TrustAgent-р түгжээгүй байлгасан"</string>
<string name="keyguard_indication_trust_disabled" msgid="6820793704816727918">"Таныг гараар нээх хүртэл төхөөрөмж түгжээтэй байх болно"</string>
+ <string name="keyguard_indication_trust_unlocked_plugged_in" msgid="2323452175329362855">"<xliff:g id="KEYGUARD_INDICATION">%1$s</xliff:g>\n<xliff:g id="POWER_INDICATION">%2$s</xliff:g>"</string>
<string name="hidden_notifications_title" msgid="1782412844777612795">"Мэдэгдлийг хурдан авах"</string>
<string name="hidden_notifications_text" msgid="5899627470450792578">"Түгжээг тайлахын өмнө үзнэ үү"</string>
<string name="hidden_notifications_cancel" msgid="4805370226181001278">"Үгүй"</string>
@@ -979,12 +980,9 @@
<string name="bubble_accessibility_action_move_bottom_left" msgid="6339015902495504715">"Зүүн доош зөөх"</string>
<string name="bubble_accessibility_action_move_bottom_right" msgid="7471571700628346212">"Баруун доош зөөх"</string>
<string name="bubble_dismiss_text" msgid="7071770411580452911">"Үл хэрэгсэх"</string>
- <!-- no translation found for bubbles_user_education_title (3385222165904578710) -->
- <skip />
- <!-- no translation found for bubbles_user_education_description (6663205638091146934) -->
- <skip />
- <!-- no translation found for bubbles_user_education_manage (1391639189507036423) -->
- <skip />
+ <string name="bubbles_user_education_title" msgid="3385222165904578710">"Чатуудыг дэлгэцийн дээд талд байлгах"</string>
+ <string name="bubbles_user_education_description" msgid="6663205638091146934">"<xliff:g id="APP_NAME">%1$s</xliff:g>-н шинэ чатууд нь бөмбөлөг маягаар харагдана. Бөмбөлгийг нээхийн тулд түүнийг товшино уу. Түүнийг зөөхийн тулд чирнэ үү.\n\nБөмбөлгийг товшино уу"</string>
+ <string name="bubbles_user_education_manage" msgid="1391639189507036423">"Энэ аппын бөмбөлгүүдийг унтраахын тулд Удирдах дээр товшино уу"</string>
<string name="notification_content_system_nav_changed" msgid="5077913144844684544">"Системийн навигацыг шинэчиллээ. Өөрчлөхийн тулд Тохиргоо руу очно уу."</string>
<string name="notification_content_gesture_nav_available" msgid="4431460803004659888">"Системийн навигацыг шинэчлэхийн тулд Тохиргоо руу очно уу"</string>
<string name="inattentive_sleep_warning_title" msgid="3891371591713990373">"Зогсолтын горим"</string>
@@ -1004,4 +1002,10 @@
<string name="controls_favorite_header_all" msgid="7507855973418969992">"Бүх"</string>
<string name="controls_favorite_load_error" msgid="2533215155804455348">"Бүх хяналтын жагсаалтыг ачаалж чадсангүй."</string>
<string name="controls_favorite_other_zone_header" msgid="9089613266575525252">"Бусад"</string>
+ <!-- no translation found for controls_dialog_title (8806193219278278442) -->
+ <skip />
+ <!-- no translation found for controls_dialog_ok (7011816381344485651) -->
+ <skip />
+ <!-- no translation found for controls_dialog_message (6292099631702047540) -->
+ <skip />
</resources>
diff --git a/packages/SystemUI/res/values-mr/strings.xml b/packages/SystemUI/res/values-mr/strings.xml
index 3c7e18e75874..118627acb91b 100644
--- a/packages/SystemUI/res/values-mr/strings.xml
+++ b/packages/SystemUI/res/values-mr/strings.xml
@@ -558,6 +558,8 @@
<string name="monitoring_description_app_personal_work" msgid="6175816356939166101">"तुमचे कार्य प्रोफाइल <xliff:g id="ORGANIZATION">%1$s</xliff:g> द्वारे व्यवस्थापित केले जाते. प्रोफाइल <xliff:g id="APPLICATION_WORK">%2$s</xliff:g> शी कनेक्‍ट केले आहे, जे ईमेल, अ‍ॅप्स आणि वेबसाइटसह आपल्‍या कार्य नेटवर्क क्रियाकलापाचे परीक्षण करू शकते.\n\nतुम्ही <xliff:g id="APPLICATION_PERSONAL">%3$s</xliff:g> शीदेखील कनेक्‍ट केले आहे, जे आपल्या वैयक्तिक नेटवर्क क्रियाकलापाचे परीक्षण करू शकते."</string>
<string name="keyguard_indication_trust_unlocked" msgid="7395154975733744547">"TrustAgent ने अनलॉक ठेवले"</string>
<string name="keyguard_indication_trust_disabled" msgid="6820793704816727918">"तुम्ही मॅन्युअली अनलॉक करेपर्यंत डिव्हाइस लॉक राहील"</string>
+ <!-- no translation found for keyguard_indication_trust_unlocked_plugged_in (2323452175329362855) -->
+ <skip />
<string name="hidden_notifications_title" msgid="1782412844777612795">"सूचना अधिक जलद मिळवा"</string>
<string name="hidden_notifications_text" msgid="5899627470450792578">"तुम्ही अनलॉक करण्‍यापूर्वी त्यांना पहा"</string>
<string name="hidden_notifications_cancel" msgid="4805370226181001278">"नाही, नको"</string>
@@ -979,12 +981,9 @@
<string name="bubble_accessibility_action_move_bottom_left" msgid="6339015902495504715">"तळाशी डावीकडे हलवा"</string>
<string name="bubble_accessibility_action_move_bottom_right" msgid="7471571700628346212">"तळाशी उजवीकडे हलवा"</string>
<string name="bubble_dismiss_text" msgid="7071770411580452911">"डिसमिस करा"</string>
- <!-- no translation found for bubbles_user_education_title (3385222165904578710) -->
- <skip />
- <!-- no translation found for bubbles_user_education_description (6663205638091146934) -->
- <skip />
- <!-- no translation found for bubbles_user_education_manage (1391639189507036423) -->
- <skip />
+ <string name="bubbles_user_education_title" msgid="3385222165904578710">"चॅट दिसतील असे ठेवा"</string>
+ <string name="bubbles_user_education_description" msgid="6663205638091146934">"<xliff:g id="APP_NAME">%1$s</xliff:g> वरील नवीन चॅट बुडबुडे म्हणून दिसतील. बुडबुडे उघडण्यासाठी त्यावर टॅप करा. तो हलवण्यासाठी ड्रॅग करा.\n\nबुडबुड्यावर टॅप करा"</string>
+ <string name="bubbles_user_education_manage" msgid="1391639189507036423">"या अ‍ॅपमधून बुडबुडे बंद करण्यासाठी व्यवस्थापित करा वर टॅप करा"</string>
<string name="notification_content_system_nav_changed" msgid="5077913144844684544">"सिस्टम नेव्हिगेशन अपडेट केले. बदल करण्यासाठी, सेटिंग्जवर जा."</string>
<string name="notification_content_gesture_nav_available" msgid="4431460803004659888">"सिस्टम नेव्हिगेशन अपडेट करण्यासाठी सेटिंग्जवर जा"</string>
<string name="inattentive_sleep_warning_title" msgid="3891371591713990373">"स्टँडबाय"</string>
@@ -994,12 +993,20 @@
<string name="quick_controls_title" msgid="525285759614231333">"क्विक नियंत्रणे"</string>
<string name="controls_providers_title" msgid="8844124515157926071">"नियंत्रणे जोडा"</string>
<string name="controls_providers_subtitle" msgid="8187768950110836569">"ज्यामधून नियंत्रणे जोडायची आहेत ते ॲप निवडा"</string>
- <!-- no translation found for controls_number_of_favorites (1057347832073807380) -->
+ <plurals name="controls_number_of_favorites" formatted="false" msgid="1057347832073807380">
+ <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="controls_favorite_default_title" msgid="967742178688938137">"नियंत्रणे"</string>
<string name="controls_favorite_subtitle" msgid="4049644994401173949">"झटपट अ‍ॅक्सेससाठी नियंत्रणे निवडा"</string>
<string name="controls_favorite_header_favorites" msgid="3118600046217493471">"आवडते"</string>
<string name="controls_favorite_header_all" msgid="7507855973418969992">"सर्व"</string>
<string name="controls_favorite_load_error" msgid="2533215155804455348">"सर्व नियंत्रणांची सूची लोड करता आली नाही."</string>
- <!-- no translation found for controls_favorite_other_zone_header (9089613266575525252) -->
+ <string name="controls_favorite_other_zone_header" msgid="9089613266575525252">"इतर"</string>
+ <!-- no translation found for controls_dialog_title (8806193219278278442) -->
+ <skip />
+ <!-- no translation found for controls_dialog_ok (7011816381344485651) -->
+ <skip />
+ <!-- no translation found for controls_dialog_message (6292099631702047540) -->
<skip />
</resources>
diff --git a/packages/SystemUI/res/values-ms/strings.xml b/packages/SystemUI/res/values-ms/strings.xml
index 6d2667371f5e..454ebfb26345 100644
--- a/packages/SystemUI/res/values-ms/strings.xml
+++ b/packages/SystemUI/res/values-ms/strings.xml
@@ -558,6 +558,7 @@
<string name="monitoring_description_app_personal_work" msgid="6175816356939166101">"Profil kerja anda diurus oleh <xliff:g id="ORGANIZATION">%1$s</xliff:g>. Profil itu dihubungkan ke <xliff:g id="APPLICATION_WORK">%2$s</xliff:g>, yang boleh memantau aktiviti rangkaian kerja anda, termasuk e-mel, apl dan tapak web.\n\nAnda turut dihubungkan ke <xliff:g id="APPLICATION_PERSONAL">%3$s</xliff:g>, yang boleh memantau aktiviti rangkaian peribadi anda."</string>
<string name="keyguard_indication_trust_unlocked" msgid="7395154975733744547">"Dibiarkan tidak berkunci oleh TrustAgent"</string>
<string name="keyguard_indication_trust_disabled" msgid="6820793704816727918">"Peranti akan kekal terkunci sehingga anda membuka kunci secara manual"</string>
+ <string name="keyguard_indication_trust_unlocked_plugged_in" msgid="2323452175329362855">"<xliff:g id="KEYGUARD_INDICATION">%1$s</xliff:g>\n<xliff:g id="POWER_INDICATION">%2$s</xliff:g>"</string>
<string name="hidden_notifications_title" msgid="1782412844777612795">"Dapatkan pemberitahuan lebih cepat"</string>
<string name="hidden_notifications_text" msgid="5899627470450792578">"Lihat sebelum anda membuka kunci"</string>
<string name="hidden_notifications_cancel" msgid="4805370226181001278">"Tidak"</string>
@@ -979,12 +980,9 @@
<string name="bubble_accessibility_action_move_bottom_left" msgid="6339015902495504715">"Alihkan ke bawah sebelah kiri"</string>
<string name="bubble_accessibility_action_move_bottom_right" msgid="7471571700628346212">"Alihkan ke bawah sebelah kanan"</string>
<string name="bubble_dismiss_text" msgid="7071770411580452911">"Ketepikan"</string>
- <!-- no translation found for bubbles_user_education_title (3385222165904578710) -->
- <skip />
- <!-- no translation found for bubbles_user_education_description (6663205638091146934) -->
- <skip />
- <!-- no translation found for bubbles_user_education_manage (1391639189507036423) -->
- <skip />
+ <string name="bubbles_user_education_title" msgid="3385222165904578710">"Pastikan sembang sentiasa di hadapan"</string>
+ <string name="bubbles_user_education_description" msgid="6663205638091146934">"Sembang baharu daripada <xliff:g id="APP_NAME">%1$s</xliff:g> akan dipaparkan sebagai gelembung. Ketik gelembung untuk membuka. Seret untuk mengalihkan gelembung.\n\nKetik gelembung itu"</string>
+ <string name="bubbles_user_education_manage" msgid="1391639189507036423">"Ketik Urus untuk mematikan gelembung daripada apl ini"</string>
<string name="notification_content_system_nav_changed" msgid="5077913144844684544">"Navigasi sistem dikemas kini. Untuk membuat perubahan, pergi ke Tetapan."</string>
<string name="notification_content_gesture_nav_available" msgid="4431460803004659888">"Pergi ke Tetapan untuk mengemas kini navigasi sistem"</string>
<string name="inattentive_sleep_warning_title" msgid="3891371591713990373">"Tunggu sedia"</string>
@@ -1004,4 +1002,10 @@
<string name="controls_favorite_header_all" msgid="7507855973418969992">"Semua"</string>
<string name="controls_favorite_load_error" msgid="2533215155804455348">"Senarai semua kawalan tidak dapat dimuatkan."</string>
<string name="controls_favorite_other_zone_header" msgid="9089613266575525252">"Lain-lain"</string>
+ <!-- no translation found for controls_dialog_title (8806193219278278442) -->
+ <skip />
+ <!-- no translation found for controls_dialog_ok (7011816381344485651) -->
+ <skip />
+ <!-- no translation found for controls_dialog_message (6292099631702047540) -->
+ <skip />
</resources>
diff --git a/packages/SystemUI/res/values-my/strings.xml b/packages/SystemUI/res/values-my/strings.xml
index dd3e6c16b74e..c65f9490b4b8 100644
--- a/packages/SystemUI/res/values-my/strings.xml
+++ b/packages/SystemUI/res/values-my/strings.xml
@@ -558,6 +558,7 @@
<string name="monitoring_description_app_personal_work" msgid="6175816356939166101">"သင်၏ အလုပ်ပရိုဖိုင်ကို <xliff:g id="ORGANIZATION">%1$s</xliff:g> က စီမံခန့်ခွဲထားသည်။ ပရိုဖိုင်သည် အီးမေး၊ အက်ပ်နှင့် ဝဘ်ဆိုက်များအပါအဝင် သင်၏ကွန်ရက် လုပ်ဆောင်ချက်များကို စောင့်ကြည့်နိုင်သည့် <xliff:g id="APPLICATION_WORK">%2$s</xliff:g> သို့ ချိတ်ဆက်ထားပါသည်။\n\nသင်၏ ကိုယ်ရေးကိုယ်တာ ကွန်ရက်လုပ်ဆောင်ချက်များကို စောင့်ကြည့်နိုင်သည့် <xliff:g id="APPLICATION_PERSONAL">%3$s</xliff:g> သို့လည်း ချိတ်ဆက်ထားပါသည်။"</string>
<string name="keyguard_indication_trust_unlocked" msgid="7395154975733744547">"TrustAgent ဖြင့် ဆက်ဖွင့်ထားရန်"</string>
<string name="keyguard_indication_trust_disabled" msgid="6820793704816727918">"သင်က လက်ဖြင့် သော့မဖွင့်မချင်း ကိရိယာမှာ သော့ပိတ်လျက် ရှိနေမည်"</string>
+ <string name="keyguard_indication_trust_unlocked_plugged_in" msgid="2323452175329362855">"<xliff:g id="KEYGUARD_INDICATION">%1$s</xliff:g>\n<xliff:g id="POWER_INDICATION">%2$s</xliff:g>"</string>
<string name="hidden_notifications_title" msgid="1782412844777612795">"အကြောင်းကြားချက်များ မြန်မြန်ရရန်"</string>
<string name="hidden_notifications_text" msgid="5899627470450792578">"မဖွင့်ခင် ၎င်းတို့ကို ကြည့်ပါ"</string>
<string name="hidden_notifications_cancel" msgid="4805370226181001278">"မလိုအပ်ပါ"</string>
@@ -1001,4 +1002,10 @@
<string name="controls_favorite_header_all" msgid="7507855973418969992">"အားလုံး"</string>
<string name="controls_favorite_load_error" msgid="2533215155804455348">"ထိန်းချုပ်မှုအားလုံး၏ စာရင်းကို ဖွင့်၍မရပါ။"</string>
<string name="controls_favorite_other_zone_header" msgid="9089613266575525252">"အခြား"</string>
+ <!-- no translation found for controls_dialog_title (8806193219278278442) -->
+ <skip />
+ <!-- no translation found for controls_dialog_ok (7011816381344485651) -->
+ <skip />
+ <!-- no translation found for controls_dialog_message (6292099631702047540) -->
+ <skip />
</resources>
diff --git a/packages/SystemUI/res/values-nb/strings.xml b/packages/SystemUI/res/values-nb/strings.xml
index 574321538eb5..d8f62946912e 100644
--- a/packages/SystemUI/res/values-nb/strings.xml
+++ b/packages/SystemUI/res/values-nb/strings.xml
@@ -558,6 +558,7 @@
<string name="monitoring_description_app_personal_work" msgid="6175816356939166101">"Jobbprofilen din administreres av <xliff:g id="ORGANIZATION">%1$s</xliff:g>. Profilen er koblet til <xliff:g id="APPLICATION_WORK">%2$s</xliff:g>, som kan overvåke nettverksaktiviteten din på jobben, inkludert e-poster, apper og nettsteder.\n\nDu er også koblet til <xliff:g id="APPLICATION_PERSONAL">%3$s</xliff:g>, som kan overvåke den personlige nettverksaktiviteten din."</string>
<string name="keyguard_indication_trust_unlocked" msgid="7395154975733744547">"Holdes opplåst med TrustAgent"</string>
<string name="keyguard_indication_trust_disabled" msgid="6820793704816727918">"Enheten forblir låst til du låser den opp manuelt"</string>
+ <string name="keyguard_indication_trust_unlocked_plugged_in" msgid="2323452175329362855">"<xliff:g id="KEYGUARD_INDICATION">%1$s</xliff:g>\n<xliff:g id="POWER_INDICATION">%2$s</xliff:g>"</string>
<string name="hidden_notifications_title" msgid="1782412844777612795">"Motta varsler raskere"</string>
<string name="hidden_notifications_text" msgid="5899627470450792578">"Se dem før du låser opp"</string>
<string name="hidden_notifications_cancel" msgid="4805370226181001278">"Nei takk"</string>
@@ -979,12 +980,9 @@
<string name="bubble_accessibility_action_move_bottom_left" msgid="6339015902495504715">"Flytt til nederst til venstre"</string>
<string name="bubble_accessibility_action_move_bottom_right" msgid="7471571700628346212">"Flytt til nederst til høyre"</string>
<string name="bubble_dismiss_text" msgid="7071770411580452911">"Avvis"</string>
- <!-- no translation found for bubbles_user_education_title (3385222165904578710) -->
- <skip />
- <!-- no translation found for bubbles_user_education_description (6663205638091146934) -->
- <skip />
- <!-- no translation found for bubbles_user_education_manage (1391639189507036423) -->
- <skip />
+ <string name="bubbles_user_education_title" msgid="3385222165904578710">"Ha chatter i forgrunnen"</string>
+ <string name="bubbles_user_education_description" msgid="6663205638091146934">"Nye chatter fra <xliff:g id="APP_NAME">%1$s</xliff:g> vises som bobler. Trykk på en boble for å åpne den. Dra for å flytte den.\n\nTrykk på boblen"</string>
+ <string name="bubbles_user_education_manage" msgid="1391639189507036423">"Trykk på Administrer for å slå av bobler for denne appen"</string>
<string name="notification_content_system_nav_changed" msgid="5077913144844684544">"Systemnavigeringen er oppdatert. For å gjøre endringer, gå til Innstillinger."</string>
<string name="notification_content_gesture_nav_available" msgid="4431460803004659888">"Gå til Innstillinger for å oppdatere systemnavigeringen"</string>
<string name="inattentive_sleep_warning_title" msgid="3891371591713990373">"Ventemodus"</string>
@@ -1004,4 +1002,10 @@
<string name="controls_favorite_header_all" msgid="7507855973418969992">"Alle"</string>
<string name="controls_favorite_load_error" msgid="2533215155804455348">"Listen over alle kontroller kunne ikke lastes inn."</string>
<string name="controls_favorite_other_zone_header" msgid="9089613266575525252">"Annet"</string>
+ <!-- no translation found for controls_dialog_title (8806193219278278442) -->
+ <skip />
+ <!-- no translation found for controls_dialog_ok (7011816381344485651) -->
+ <skip />
+ <!-- no translation found for controls_dialog_message (6292099631702047540) -->
+ <skip />
</resources>
diff --git a/packages/SystemUI/res/values-ne/strings.xml b/packages/SystemUI/res/values-ne/strings.xml
index ef80cdcb360c..73564a13e431 100644
--- a/packages/SystemUI/res/values-ne/strings.xml
+++ b/packages/SystemUI/res/values-ne/strings.xml
@@ -558,6 +558,8 @@
<string name="monitoring_description_app_personal_work" msgid="6175816356939166101">"<xliff:g id="ORGANIZATION">%1$s</xliff:g> ले तपाईंको कार्य प्रोफाइलको व्यवस्थापन गर्छ। उक्त प्रोफाइल तपाईंका इमेल, अनुप्रयोग र वेवसाइटहरू लगायत तपाईंको नेटवर्कको गतिविधिको अनुगमन गर्नसक्ने <xliff:g id="APPLICATION_WORK">%2$s</xliff:g> मा जडान छ। \n\nतपाईं आफ्नो व्यक्तिगत नेटवर्कको गतिविधिको अनुगमन गर्नसक्ने <xliff:g id="APPLICATION_PERSONAL">%3$s</xliff:g> मा पनि जडान हुनुहुन्छ।"</string>
<string name="keyguard_indication_trust_unlocked" msgid="7395154975733744547">"TrustAgent ले खुला राखेको"</string>
<string name="keyguard_indication_trust_disabled" msgid="6820793704816727918">"तपाईँले नखोले सम्म उपकरण बन्द रहनेछ"</string>
+ <!-- no translation found for keyguard_indication_trust_unlocked_plugged_in (2323452175329362855) -->
+ <skip />
<string name="hidden_notifications_title" msgid="1782412844777612795">"छिटो सूचनाहरू प्राप्त गर्नुहोस्"</string>
<string name="hidden_notifications_text" msgid="5899627470450792578">"तपाईँले अनलक गर्नअघि तिनीहरूलाई हेर्नुहोस्"</string>
<string name="hidden_notifications_cancel" msgid="4805370226181001278">"धन्यवाद पर्दैन"</string>
@@ -979,12 +981,9 @@
<string name="bubble_accessibility_action_move_bottom_left" msgid="6339015902495504715">"पुछारमा बायाँतिर सार्नुहोस्"</string>
<string name="bubble_accessibility_action_move_bottom_right" msgid="7471571700628346212">"पुछारमा दायाँतिर सार्नुहोस्"</string>
<string name="bubble_dismiss_text" msgid="7071770411580452911">"हटाउनुहोस्"</string>
- <!-- no translation found for bubbles_user_education_title (3385222165904578710) -->
- <skip />
- <!-- no translation found for bubbles_user_education_description (6663205638091146934) -->
- <skip />
- <!-- no translation found for bubbles_user_education_manage (1391639189507036423) -->
- <skip />
+ <string name="bubbles_user_education_title" msgid="3385222165904578710">"कुराकानीलाई अग्रभूमिमा राख्नुहोस्"</string>
+ <string name="bubbles_user_education_description" msgid="6663205638091146934">"<xliff:g id="APP_NAME">%1$s</xliff:g> का नयाँ कुराकानीहरू बबलका रूपमा देखा पर्ने छन्। बबल खोल्न त्यसमा ट्याप गर्नुहोस्। बबल सार्न त्यसलाई घिसार्नुहोस्।\n\nबबलमा ट्याप गर्नुहोस्"</string>
+ <string name="bubbles_user_education_manage" msgid="1391639189507036423">"यो अनुप्रयोगमा बबल निष्क्रिय पार्न व्यवस्थापन गर्नुहोस् नामक बटन ट्याप गर्नुहोस्"</string>
<string name="notification_content_system_nav_changed" msgid="5077913144844684544">"प्रणालीको नेभिगेसन अद्यावधिक गरियो। परिवर्तन गर्न सेटिङमा जानुहोस्।"</string>
<string name="notification_content_gesture_nav_available" msgid="4431460803004659888">"प्रणालीको नेभिगेसन अद्यावधिक गर्न सेटिङमा जानुहोस्"</string>
<string name="inattentive_sleep_warning_title" msgid="3891371591713990373">"स्ट्यान्डबाई"</string>
@@ -994,12 +993,20 @@
<string name="quick_controls_title" msgid="525285759614231333">"द्रुत नियन्त्रणहरू"</string>
<string name="controls_providers_title" msgid="8844124515157926071">"नियन्त्रणहरू थप्नुहोस्"</string>
<string name="controls_providers_subtitle" msgid="8187768950110836569">"नियन्त्रणहरू जुन अनुप्रयोगबाट थप्ने हो त्यो अनुप्रयोग छनौट गर्नुहोस्"</string>
- <!-- no translation found for controls_number_of_favorites (1057347832073807380) -->
+ <plurals name="controls_number_of_favorites" formatted="false" msgid="1057347832073807380">
+ <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="controls_favorite_default_title" msgid="967742178688938137">"नियन्त्रणहरू"</string>
<string name="controls_favorite_subtitle" msgid="4049644994401173949">"द्रुत पहुँचका लागि नियन्त्रणहरू छनौट गर्नुहोस्"</string>
<string name="controls_favorite_header_favorites" msgid="3118600046217493471">"मन पर्ने कुराहरू"</string>
<string name="controls_favorite_header_all" msgid="7507855973418969992">"सबै"</string>
<string name="controls_favorite_load_error" msgid="2533215155804455348">"सबै नियन्त्रणहरूको सूची लोड गर्न सकिएन।"</string>
- <!-- no translation found for controls_favorite_other_zone_header (9089613266575525252) -->
+ <string name="controls_favorite_other_zone_header" msgid="9089613266575525252">"अन्य"</string>
+ <!-- no translation found for controls_dialog_title (8806193219278278442) -->
+ <skip />
+ <!-- no translation found for controls_dialog_ok (7011816381344485651) -->
+ <skip />
+ <!-- no translation found for controls_dialog_message (6292099631702047540) -->
<skip />
</resources>
diff --git a/packages/SystemUI/res/values-nl/strings.xml b/packages/SystemUI/res/values-nl/strings.xml
index ae9b82916220..86f0f8f4b4a2 100644
--- a/packages/SystemUI/res/values-nl/strings.xml
+++ b/packages/SystemUI/res/values-nl/strings.xml
@@ -558,6 +558,7 @@
<string name="monitoring_description_app_personal_work" msgid="6175816356939166101">"Je werkprofiel wordt beheerd door <xliff:g id="ORGANIZATION">%1$s</xliff:g>. Het profiel is verbonden met <xliff:g id="APPLICATION_WORK">%2$s</xliff:g>, waarmee je werkgerelateerde netwerkactiviteit (waaronder e-mails, apps en websites) kan worden bijgehouden.\n\nJe bent ook verbonden met <xliff:g id="APPLICATION_PERSONAL">%3$s</xliff:g>, waarmee je persoonlijke netwerkactiviteit kan worden bijgehouden."</string>
<string name="keyguard_indication_trust_unlocked" msgid="7395154975733744547">"Ontgrendeld gehouden door TrustAgent"</string>
<string name="keyguard_indication_trust_disabled" msgid="6820793704816727918">"Het apparaat blijft vergrendeld totdat u het handmatig ontgrendelt"</string>
+ <string name="keyguard_indication_trust_unlocked_plugged_in" msgid="2323452175329362855">"<xliff:g id="KEYGUARD_INDICATION">%1$s</xliff:g>\n<xliff:g id="POWER_INDICATION">%2$s</xliff:g>"</string>
<string name="hidden_notifications_title" msgid="1782412844777612795">"Sneller meldingen ontvangen"</string>
<string name="hidden_notifications_text" msgid="5899627470450792578">"Weergeven voordat u ontgrendelt"</string>
<string name="hidden_notifications_cancel" msgid="4805370226181001278">"Nee, bedankt"</string>
@@ -979,12 +980,9 @@
<string name="bubble_accessibility_action_move_bottom_left" msgid="6339015902495504715">"Naar linksonder verplaatsen"</string>
<string name="bubble_accessibility_action_move_bottom_right" msgid="7471571700628346212">"Naar rechtsonder verplaatsen"</string>
<string name="bubble_dismiss_text" msgid="7071770411580452911">"Sluiten"</string>
- <!-- no translation found for bubbles_user_education_title (3385222165904578710) -->
- <skip />
- <!-- no translation found for bubbles_user_education_description (6663205638091146934) -->
- <skip />
- <!-- no translation found for bubbles_user_education_manage (1391639189507036423) -->
- <skip />
+ <string name="bubbles_user_education_title" msgid="3385222165904578710">"Chats op de voorgrond houden"</string>
+ <string name="bubbles_user_education_description" msgid="6663205638091146934">"Nieuwe chats van <xliff:g id="APP_NAME">%1$s</xliff:g> worden weergegeven als bubbels. Tik op een bubbel om deze te openen. Sleep om deze te verplaatsen.\n\nTik op de bubbel"</string>
+ <string name="bubbles_user_education_manage" msgid="1391639189507036423">"Tik op Beheren om bubbels van deze app uit te schakelen"</string>
<string name="notification_content_system_nav_changed" msgid="5077913144844684544">"Systeemnavigatie geüpdatet. Als je wijzigingen wilt aanbrengen, ga je naar Instellingen."</string>
<string name="notification_content_gesture_nav_available" msgid="4431460803004659888">"Ga naar Instellingen om de systeemnavigatie te updaten"</string>
<string name="inattentive_sleep_warning_title" msgid="3891371591713990373">"Stand-by"</string>
@@ -1004,4 +1002,10 @@
<string name="controls_favorite_header_all" msgid="7507855973418969992">"Alle"</string>
<string name="controls_favorite_load_error" msgid="2533215155804455348">"Kan lijst met alle bedieningselementen niet laden."</string>
<string name="controls_favorite_other_zone_header" msgid="9089613266575525252">"Overig"</string>
+ <!-- no translation found for controls_dialog_title (8806193219278278442) -->
+ <skip />
+ <!-- no translation found for controls_dialog_ok (7011816381344485651) -->
+ <skip />
+ <!-- no translation found for controls_dialog_message (6292099631702047540) -->
+ <skip />
</resources>
diff --git a/packages/SystemUI/res/values-or/strings.xml b/packages/SystemUI/res/values-or/strings.xml
index 9aad495f28bc..f46036ec24d6 100644
--- a/packages/SystemUI/res/values-or/strings.xml
+++ b/packages/SystemUI/res/values-or/strings.xml
@@ -558,6 +558,8 @@
<string name="monitoring_description_app_personal_work" msgid="6175816356939166101">"ଆପଣଙ୍କ ୱର୍କ ପ୍ରୋଫାଇଲ୍‍ <xliff:g id="ORGANIZATION">%1$s</xliff:g> ଦ୍ୱାରା ପରିଚାଳନା କରାଯାଉଛି। ପ୍ରୋଫାଇଲଟି <xliff:g id="APPLICATION_WORK">%2$s</xliff:g> ସହ ସଂଯୁକ୍ତ ଅଛି, ଯାହା ଇମେଲ୍‍, ଆପ୍‌ ଓ ୱେବସାଇଟ୍‍ ସମେତ ଆପଣଙ୍କ ନେଟୱର୍କ ଗତିବିଧିକୁ ନିରୀକ୍ଷଣ କରିପାରେ।\n\nଆପଣ <xliff:g id="APPLICATION_PERSONAL">%3$s</xliff:g>ରେ ମଧ୍ୟ ସଂଯୁକ୍ତ, ଯାହା ଆପଣଙ୍କ ବ୍ୟକ୍ତିଗତ ନେଟୱର୍କ ଗତିବିଧିକୁ ନିରୀକ୍ଷଣ କରିପାରେ।"</string>
<string name="keyguard_indication_trust_unlocked" msgid="7395154975733744547">"TrustAgent ଦ୍ୱାରା ଅନ୍‌ଲକ୍ ରହିଛି"</string>
<string name="keyguard_indication_trust_disabled" msgid="6820793704816727918">"ଯେତେବେଳ ପର୍ଯ୍ୟନ୍ତ ଆପଣ ମାନୁଆଲୀ ଅନଲକ୍‌ କରିନାହାନ୍ତି, ସେତେବେଳ ପର୍ଯ୍ୟନ୍ତ ଡିଭାଇସ୍‌ ଲକ୍‌ ରହିବ"</string>
+ <!-- no translation found for keyguard_indication_trust_unlocked_plugged_in (2323452175329362855) -->
+ <skip />
<string name="hidden_notifications_title" msgid="1782412844777612795">"ବିଜ୍ଞପ୍ତିକୁ ଶୀଘ୍ର ପ୍ରାପ୍ତ କରନ୍ତୁ"</string>
<string name="hidden_notifications_text" msgid="5899627470450792578">"ଅନଲକ୍‌ କରିବା ପୁର୍ବରୁ ସେମାନଙ୍କୁ ଦେଖନ୍ତୁ"</string>
<string name="hidden_notifications_cancel" msgid="4805370226181001278">"ନାହିଁ, ଥାଉ"</string>
@@ -979,12 +981,9 @@
<string name="bubble_accessibility_action_move_bottom_left" msgid="6339015902495504715">"ତଳ ବାମକୁ ନିଅନ୍ତୁ"</string>
<string name="bubble_accessibility_action_move_bottom_right" msgid="7471571700628346212">"ତଳ ଡାହାଣକୁ ନିଅନ୍ତୁ"</string>
<string name="bubble_dismiss_text" msgid="7071770411580452911">"ଖାରଜ କରନ୍ତୁ"</string>
- <!-- no translation found for bubbles_user_education_title (3385222165904578710) -->
- <skip />
- <!-- no translation found for bubbles_user_education_description (6663205638091146934) -->
- <skip />
- <!-- no translation found for bubbles_user_education_manage (1391639189507036423) -->
- <skip />
+ <string name="bubbles_user_education_title" msgid="3385222165904578710">"ଚାଟଗୁଡ଼ିକ ଆଗ ପଟେ ରଖନ୍ତୁ"</string>
+ <string name="bubbles_user_education_description" msgid="6663205638091146934">"<xliff:g id="APP_NAME">%1$s</xliff:g>ର ନୂଆ ଚାଟଗୁଡ଼ିକ ବବଲ୍‍ ଭାବରେ ଦେଖାଯିବ। ଏହାକୁ ଖୋଲିବା ପାଇଁ ଏକ ବବଲରେ ଟାପ୍ କରନ୍ତୁ। ଏହାକୁ ମୁଭ୍ କରିବା ପାଇଁ ଟାଣନ୍ତୁ। \n\nବବଲରେ ଟାପ୍ କରନ୍ତୁ"</string>
+ <string name="bubbles_user_education_manage" msgid="1391639189507036423">"ଏହି ଆପର ବବଲଗୁଡ଼ିକ ବନ୍ଦ କରିବା ପାଇଁ \'ପରିଚାଳନା କରନ୍ତୁ\' ବଟନରେ ଟାପ୍ କରନ୍ତୁ"</string>
<string name="notification_content_system_nav_changed" msgid="5077913144844684544">"ସିଷ୍ଟମ୍ ନାଭିଗେସନ୍ ଅପ୍‌ଡେଟ୍ ହୋଇଛି। ପରିବର୍ତ୍ତନ କରିବା ପାଇଁ, ସେଟିଂସ୍‌କୁ ଯାଆନ୍ତୁ।"</string>
<string name="notification_content_gesture_nav_available" msgid="4431460803004659888">"ସିଷ୍ଟମ୍ ନାଭିଗେସନ୍ ଅପ୍‌ଡେଟ୍ କରିବା ପାଇଁ ସେଟିଂସ୍‍କୁ ଯାଆନ୍ତୁ"</string>
<string name="inattentive_sleep_warning_title" msgid="3891371591713990373">"ଷ୍ଟାଣ୍ଡବାଏ"</string>
@@ -994,12 +993,20 @@
<string name="quick_controls_title" msgid="525285759614231333">"ଦ୍ରୁତ ନିୟନ୍ତ୍ରଣଗୁଡ଼ିକ"</string>
<string name="controls_providers_title" msgid="8844124515157926071">"ନିୟନ୍ତ୍ରଣଗୁଡ଼ିକ ଯୋଗ କରନ୍ତୁ"</string>
<string name="controls_providers_subtitle" msgid="8187768950110836569">"କେଉଁ ଆପରୁ ନିୟନ୍ତ୍ରଣଗୁଡ଼ିକ ଯୋଗ କରିବେ ତାହା ଚୟନ କରନ୍ତୁ"</string>
- <!-- no translation found for controls_number_of_favorites (1057347832073807380) -->
+ <plurals name="controls_number_of_favorites" formatted="false" msgid="1057347832073807380">
+ <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="controls_favorite_default_title" msgid="967742178688938137">"ନିୟନ୍ତ୍ରଣଗୁଡ଼ିକ"</string>
<string name="controls_favorite_subtitle" msgid="4049644994401173949">"ଶୀଘ୍ର ଆକ୍ସେସ୍ ପାଇଁ ନିୟନ୍ତ୍ରଣଗୁଡ଼ିକୁ ଚୟନ କରନ୍ତୁ"</string>
<string name="controls_favorite_header_favorites" msgid="3118600046217493471">"ପସନ୍ଦଗୁଡ଼ିକ"</string>
<string name="controls_favorite_header_all" msgid="7507855973418969992">"ସବୁ"</string>
<string name="controls_favorite_load_error" msgid="2533215155804455348">"ସବୁ ନିୟନ୍ତ୍ରଣର ତାଲିକା ଲୋଡ୍ କରିପାରିଲା ନାହିଁ।"</string>
- <!-- no translation found for controls_favorite_other_zone_header (9089613266575525252) -->
+ <string name="controls_favorite_other_zone_header" msgid="9089613266575525252">"ଅନ୍ୟ"</string>
+ <!-- no translation found for controls_dialog_title (8806193219278278442) -->
+ <skip />
+ <!-- no translation found for controls_dialog_ok (7011816381344485651) -->
+ <skip />
+ <!-- no translation found for controls_dialog_message (6292099631702047540) -->
<skip />
</resources>
diff --git a/packages/SystemUI/res/values-pa/strings.xml b/packages/SystemUI/res/values-pa/strings.xml
index cbd278e9675c..3a43f0fa135e 100644
--- a/packages/SystemUI/res/values-pa/strings.xml
+++ b/packages/SystemUI/res/values-pa/strings.xml
@@ -558,6 +558,8 @@
<string name="monitoring_description_app_personal_work" msgid="6175816356939166101">"ਤੁਹਾਡੇ ਕਾਰਜ ਪ੍ਰੋਫਾਈਲ ਦਾ ਪ੍ਰਬੰਧਨ <xliff:g id="ORGANIZATION">%1$s</xliff:g> ਵੱਲੋਂ ਕੀਤਾ ਜਾਂਦਾ ਹੈ। ਪ੍ਰੋਫਾਈਲ <xliff:g id="APPLICATION_WORK">%2$s</xliff:g> ਨਾਲ ਕਨੈਕਟ ਕੀਤਾ ਗਿਆ ਹੈ, ਜੋ ਈਮੇਲਾਂ, ਐਪਾਂ, ਅਤੇ ਵੈੱਬਸਾਈਟਾਂ ਸਮੇਤ ਤੁਹਾਡੀ ਕਾਰਜ ਨੈੱਟਵਰਕ ਸਰਗਰਮੀ ਦੀ ਨਿਗਰਾਨੀ ਕਰ ਸਕਦੀ ਹੈ।\n\nਤੁਸੀਂ <xliff:g id="APPLICATION_PERSONAL">%3$s</xliff:g> ਨਾਲ ਵੀ ਕਨੈਕਟ ਹੋਂ, ਜੋ ਤੁਹਾਡੀ ਨਿੱਜੀ ਨੈੱਟਵਰਕ ਸਰਗਰਮੀ ਦੀ ਨਿਗਰਾਨੀ ਕਰ ਸਕਦੀ ਹੈ।"</string>
<string name="keyguard_indication_trust_unlocked" msgid="7395154975733744547">"ਟਰੱਸਟ-ਏਜੰਟ ਵੱਲੋਂ ਅਣਲਾਕ ਰੱਖਿਆ ਗਿਆ"</string>
<string name="keyguard_indication_trust_disabled" msgid="6820793704816727918">"ਡੀਵਾਈਸ ਲਾਕ ਰਹੇਗਾ ਜਦੋਂ ਤੱਕ ਤੁਸੀਂ ਮੈਨੂਅਲੀ ਅਣਲਾਕ ਨਹੀਂ ਕਰਦੇ"</string>
+ <!-- no translation found for keyguard_indication_trust_unlocked_plugged_in (2323452175329362855) -->
+ <skip />
<string name="hidden_notifications_title" msgid="1782412844777612795">"ਤੇਜ਼ੀ ਨਾਲ ਸੂਚਨਾਵਾਂ ਪ੍ਰਾਪਤ ਕਰੋ"</string>
<string name="hidden_notifications_text" msgid="5899627470450792578">"ਅਣਲਾਕ ਕਰਨ ਤੋਂ ਪਹਿਲਾਂ ਉਹਨਾਂ ਨੂੰ ਦੇਖੋ"</string>
<string name="hidden_notifications_cancel" msgid="4805370226181001278">"ਨਹੀਂ ਧੰਨਵਾਦ"</string>
@@ -979,12 +981,9 @@
<string name="bubble_accessibility_action_move_bottom_left" msgid="6339015902495504715">"ਹੇਠਾਂ ਵੱਲ ਖੱਬੇ ਲਿਜਾਓ"</string>
<string name="bubble_accessibility_action_move_bottom_right" msgid="7471571700628346212">"ਹੇਠਾਂ ਵੱਲ ਸੱਜੇ ਲਿਜਾਓ"</string>
<string name="bubble_dismiss_text" msgid="7071770411580452911">"ਖਾਰਜ ਕਰੋ"</string>
- <!-- no translation found for bubbles_user_education_title (3385222165904578710) -->
- <skip />
- <!-- no translation found for bubbles_user_education_description (6663205638091146934) -->
- <skip />
- <!-- no translation found for bubbles_user_education_manage (1391639189507036423) -->
- <skip />
+ <string name="bubbles_user_education_title" msgid="3385222165904578710">"ਚੈਟਾਂ ਨੂੰ ਪਹਿਲਾਂ ਤੋਂ ਤਿਆਰ ਰੱਖੋ"</string>
+ <string name="bubbles_user_education_description" msgid="6663205638091146934">"<xliff:g id="APP_NAME">%1$s</xliff:g> ਦੀਆਂ ਨਵੀਆਂ ਚੈਟਾਂ ਬੁਲਬੁਲਿਆਂ ਵਾਂਗ ਦਿਸਣਗੀਆਂ। ਇਸ ਨੂੰ ਖੋਲ੍ਹਣ ਲਈ ਕਿਸੇ ਬੁਲਬੁਲੇ \'ਤੇ ਟੈਪ ਕਰੋ। ਇਸ ਨੂੰ ਇੱਕ ਥਾਂ ਤੋਂ ਦੂਜੀ ਥਾਂ \'ਤੇ ਲਿਜਾਣ ਲਈ ਘਸੀਟੋ।\n\nਬੁਲਬੁਲੇ \'ਤੇ ਟੈਪ ਕਰੋ"</string>
+ <string name="bubbles_user_education_manage" msgid="1391639189507036423">"ਇਸ ਐਪ \'ਤੇ ਬੁਲਬੁਲੇ ਬੰਦ ਕਰਨ ਲਈ \'ਪ੍ਰਬੰਧਨ ਕਰੋ\' \'ਤੇ ਟੈਪ ਕਰੋ"</string>
<string name="notification_content_system_nav_changed" msgid="5077913144844684544">"ਸਿਸਟਮ ਨੈਵੀਗੇਸ਼ਨ ਅੱਪਡੇਟ ਹੋ ਗਿਆ। ਤਬਦੀਲੀਆਂ ਕਰਨ ਲਈ, ਸੈਟਿੰਗਾਂ \'ਤੇ ਜਾਓ।"</string>
<string name="notification_content_gesture_nav_available" msgid="4431460803004659888">"ਸਿਸਟਮ ਨੈਵੀਗੇਸ਼ਨ ਨੂੰ ਅੱਪਡੇਟ ਕਰਨ ਲਈ ਸੈਟਿੰਗਾਂ \'ਤੇ ਜਾਓ"</string>
<string name="inattentive_sleep_warning_title" msgid="3891371591713990373">"ਸਟੈਂਡਬਾਈ"</string>
@@ -994,12 +993,20 @@
<string name="quick_controls_title" msgid="525285759614231333">"ਤਤਕਾਲ ਕੰਟਰੋਲ"</string>
<string name="controls_providers_title" msgid="8844124515157926071">"ਕੰਟਰੋਲ ਸ਼ਾਮਲ ਕਰੋ"</string>
<string name="controls_providers_subtitle" msgid="8187768950110836569">"ਉਹ ਐਪ ਚੁਣੋ ਜਿੱਥੋਂ ਕੰਟਰੋਲ ਸ਼ਾਮਲ ਕਰਨੇ ਹਨ"</string>
- <!-- no translation found for controls_number_of_favorites (1057347832073807380) -->
+ <plurals name="controls_number_of_favorites" formatted="false" msgid="1057347832073807380">
+ <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="controls_favorite_default_title" msgid="967742178688938137">"ਕੰਟਰੋਲ"</string>
<string name="controls_favorite_subtitle" msgid="4049644994401173949">"ਤਤਕਾਲ ਪਹੁੰਚ ਲਈ ਕੰਟਰੋਲ ਚੁਣੋ"</string>
<string name="controls_favorite_header_favorites" msgid="3118600046217493471">"ਮਨਪਸੰਦ"</string>
<string name="controls_favorite_header_all" msgid="7507855973418969992">"ਸਭ"</string>
<string name="controls_favorite_load_error" msgid="2533215155804455348">"ਸਾਰੇ ਕੰਟਰੋਲਾਂ ਦੀ ਸੂਚੀ ਨੂੰ ਲੋਡ ਨਹੀਂ ਕੀਤਾ ਜਾ ਸਕਿਆ।"</string>
- <!-- no translation found for controls_favorite_other_zone_header (9089613266575525252) -->
+ <string name="controls_favorite_other_zone_header" msgid="9089613266575525252">"ਹੋਰ"</string>
+ <!-- no translation found for controls_dialog_title (8806193219278278442) -->
+ <skip />
+ <!-- no translation found for controls_dialog_ok (7011816381344485651) -->
+ <skip />
+ <!-- no translation found for controls_dialog_message (6292099631702047540) -->
<skip />
</resources>
diff --git a/packages/SystemUI/res/values-pl/strings.xml b/packages/SystemUI/res/values-pl/strings.xml
index ad54bc9ccecf..1bbe80a13b10 100644
--- a/packages/SystemUI/res/values-pl/strings.xml
+++ b/packages/SystemUI/res/values-pl/strings.xml
@@ -564,6 +564,7 @@
<string name="monitoring_description_app_personal_work" msgid="6175816356939166101">"Organizacja <xliff:g id="ORGANIZATION">%1$s</xliff:g> zarządza Twoim profilem do pracy. Profil jest połączony z aplikacją <xliff:g id="APPLICATION_WORK">%2$s</xliff:g>, która może monitorować Twoją aktywność w sieci, w tym e-maile, aplikacje i strony internetowe.\n\nMasz też połączenie z aplikacją <xliff:g id="APPLICATION_PERSONAL">%3$s</xliff:g>, która może monitorować Twoją osobistą aktywność w sieci."</string>
<string name="keyguard_indication_trust_unlocked" msgid="7395154975733744547">"Blokada anulowana przez agenta zaufania"</string>
<string name="keyguard_indication_trust_disabled" msgid="6820793704816727918">"Urządzenie pozostanie zablokowane, aż odblokujesz je ręcznie"</string>
+ <string name="keyguard_indication_trust_unlocked_plugged_in" msgid="2323452175329362855">"<xliff:g id="KEYGUARD_INDICATION">%1$s</xliff:g>\n<xliff:g id="POWER_INDICATION">%2$s</xliff:g>"</string>
<string name="hidden_notifications_title" msgid="1782412844777612795">"Szybszy dostęp do powiadomień"</string>
<string name="hidden_notifications_text" msgid="5899627470450792578">"Zobacz powiadomienia, jeszcze zanim odblokujesz ekran"</string>
<string name="hidden_notifications_cancel" msgid="4805370226181001278">"Nie, dziękuję"</string>
@@ -989,12 +990,9 @@
<string name="bubble_accessibility_action_move_bottom_left" msgid="6339015902495504715">"Przenieś w lewy dolny róg"</string>
<string name="bubble_accessibility_action_move_bottom_right" msgid="7471571700628346212">"Przenieś w prawy dolny róg"</string>
<string name="bubble_dismiss_text" msgid="7071770411580452911">"Zamknij"</string>
- <!-- no translation found for bubbles_user_education_title (3385222165904578710) -->
- <skip />
- <!-- no translation found for bubbles_user_education_description (6663205638091146934) -->
- <skip />
- <!-- no translation found for bubbles_user_education_manage (1391639189507036423) -->
- <skip />
+ <string name="bubbles_user_education_title" msgid="3385222165904578710">"Wyświetlaj czaty na wierzchu"</string>
+ <string name="bubbles_user_education_description" msgid="6663205638091146934">"Nowe czaty z aplikacji <xliff:g id="APP_NAME">%1$s</xliff:g> będą pojawiać się jako dymki. Kliknij dymek, aby go otworzyć. Przeciągnij dymek, jeśli chcesz go przenieść.\n\nKliknij dymek"</string>
+ <string name="bubbles_user_education_manage" msgid="1391639189507036423">"Kliknij Zarządzaj, aby wyłączyć dymki z tej aplikacji"</string>
<string name="notification_content_system_nav_changed" msgid="5077913144844684544">"Nawigacja w systemie została zaktualizowana. Aby wprowadzić zmiany, otwórz Ustawienia."</string>
<string name="notification_content_gesture_nav_available" msgid="4431460803004659888">"Otwórz Ustawienia, by zaktualizować nawigację w systemie"</string>
<string name="inattentive_sleep_warning_title" msgid="3891371591713990373">"Tryb gotowości"</string>
@@ -1016,4 +1014,10 @@
<string name="controls_favorite_header_all" msgid="7507855973418969992">"Wszystko"</string>
<string name="controls_favorite_load_error" msgid="2533215155804455348">"Nie udało się wczytać listy elementów sterujących."</string>
<string name="controls_favorite_other_zone_header" msgid="9089613266575525252">"Inne"</string>
+ <!-- no translation found for controls_dialog_title (8806193219278278442) -->
+ <skip />
+ <!-- no translation found for controls_dialog_ok (7011816381344485651) -->
+ <skip />
+ <!-- no translation found for controls_dialog_message (6292099631702047540) -->
+ <skip />
</resources>
diff --git a/packages/SystemUI/res/values-pt-rBR/strings.xml b/packages/SystemUI/res/values-pt-rBR/strings.xml
index 300461d48dbf..61ac664e9f08 100644
--- a/packages/SystemUI/res/values-pt-rBR/strings.xml
+++ b/packages/SystemUI/res/values-pt-rBR/strings.xml
@@ -558,6 +558,7 @@
<string name="monitoring_description_app_personal_work" msgid="6175816356939166101">"Seu perfil de trabalho é gerenciado por <xliff:g id="ORGANIZATION">%1$s</xliff:g>. O perfil está conectado a <xliff:g id="APPLICATION_WORK">%2$s</xliff:g>, que pode monitorar sua atividade profissional de rede, incluindo e-mails, apps e websites.\n\nVocê também está conectado a <xliff:g id="APPLICATION_PERSONAL">%3$s</xliff:g>, que pode monitorar sua atividade pessoal de rede."</string>
<string name="keyguard_indication_trust_unlocked" msgid="7395154975733744547">"Desbloqueado pelo TrustAgent"</string>
<string name="keyguard_indication_trust_disabled" msgid="6820793704816727918">"O dispositivo permanecerá bloqueado até que você o desbloqueie manualmente"</string>
+ <string name="keyguard_indication_trust_unlocked_plugged_in" msgid="2323452175329362855">"<xliff:g id="KEYGUARD_INDICATION">%1$s</xliff:g>\n<xliff:g id="POWER_INDICATION">%2$s</xliff:g>"</string>
<string name="hidden_notifications_title" msgid="1782412844777612795">"Receba notificações mais rápido"</string>
<string name="hidden_notifications_text" msgid="5899627470450792578">"Veja-as antes de desbloquear"</string>
<string name="hidden_notifications_cancel" msgid="4805370226181001278">"Não, obrigado"</string>
@@ -979,12 +980,9 @@
<string name="bubble_accessibility_action_move_bottom_left" msgid="6339015902495504715">"Mover para canto inferior esquerdo"</string>
<string name="bubble_accessibility_action_move_bottom_right" msgid="7471571700628346212">"Mover para canto inferior direito"</string>
<string name="bubble_dismiss_text" msgid="7071770411580452911">"Dispensar"</string>
- <!-- no translation found for bubbles_user_education_title (3385222165904578710) -->
- <skip />
- <!-- no translation found for bubbles_user_education_description (6663205638091146934) -->
- <skip />
- <!-- no translation found for bubbles_user_education_manage (1391639189507036423) -->
- <skip />
+ <string name="bubbles_user_education_title" msgid="3385222165904578710">"Manter chats em primeiro plano"</string>
+ <string name="bubbles_user_education_description" msgid="6663205638091146934">"Novos chats do app <xliff:g id="APP_NAME">%1$s</xliff:g> aparecerão como balões. Toque em um balão para abrir o chat. Arraste para mover.\n\nToque no balão"</string>
+ <string name="bubbles_user_education_manage" msgid="1391639189507036423">"Toque em \"Gerenciar\" para desativar os balões desse app"</string>
<string name="notification_content_system_nav_changed" msgid="5077913144844684544">"Navegação no sistema atualizada. Se quiser alterá-la, acesse as configurações."</string>
<string name="notification_content_gesture_nav_available" msgid="4431460803004659888">"Acesse as configurações para atualizar a navegação no sistema"</string>
<string name="inattentive_sleep_warning_title" msgid="3891371591713990373">"Em espera"</string>
@@ -1004,4 +1002,10 @@
<string name="controls_favorite_header_all" msgid="7507855973418969992">"Todos"</string>
<string name="controls_favorite_load_error" msgid="2533215155804455348">"Não foi possível carregar a lista de controles."</string>
<string name="controls_favorite_other_zone_header" msgid="9089613266575525252">"Outro"</string>
+ <!-- no translation found for controls_dialog_title (8806193219278278442) -->
+ <skip />
+ <!-- no translation found for controls_dialog_ok (7011816381344485651) -->
+ <skip />
+ <!-- no translation found for controls_dialog_message (6292099631702047540) -->
+ <skip />
</resources>
diff --git a/packages/SystemUI/res/values-pt-rPT/strings.xml b/packages/SystemUI/res/values-pt-rPT/strings.xml
index 9d7fb35e196e..199da1554244 100644
--- a/packages/SystemUI/res/values-pt-rPT/strings.xml
+++ b/packages/SystemUI/res/values-pt-rPT/strings.xml
@@ -558,6 +558,7 @@
<string name="monitoring_description_app_personal_work" msgid="6175816356939166101">"O seu perfil de trabalho é gerido pela <xliff:g id="ORGANIZATION">%1$s</xliff:g>. O perfil está associado à aplicação <xliff:g id="APPLICATION_WORK">%2$s</xliff:g>, que pode monitorizar a atividade da rede de trabalho, incluindo emails, aplicações e Sites.\n\nTambém está associado à aplicação <xliff:g id="APPLICATION_PERSONAL">%3$s</xliff:g>, que pode monitorizar a atividade da rede pessoal."</string>
<string name="keyguard_indication_trust_unlocked" msgid="7395154975733744547">"Mantido desbloqueado pelo TrustAgent"</string>
<string name="keyguard_indication_trust_disabled" msgid="6820793704816727918">"O dispositivo permanecerá bloqueado até ser desbloqueado manualmente"</string>
+ <string name="keyguard_indication_trust_unlocked_plugged_in" msgid="2323452175329362855">"<xliff:g id="KEYGUARD_INDICATION">%1$s</xliff:g>\n<xliff:g id="POWER_INDICATION">%2$s</xliff:g>"</string>
<string name="hidden_notifications_title" msgid="1782412844777612795">"Receber notificações mais rapidamente"</string>
<string name="hidden_notifications_text" msgid="5899627470450792578">"Ver antes de desbloquear"</string>
<string name="hidden_notifications_cancel" msgid="4805370226181001278">"Não, obrigado"</string>
@@ -979,12 +980,9 @@
<string name="bubble_accessibility_action_move_bottom_left" msgid="6339015902495504715">"Mover p/ parte infer. esquerda"</string>
<string name="bubble_accessibility_action_move_bottom_right" msgid="7471571700628346212">"Mover parte inferior direita"</string>
<string name="bubble_dismiss_text" msgid="7071770411580452911">"Ignorar"</string>
- <!-- no translation found for bubbles_user_education_title (3385222165904578710) -->
- <skip />
- <!-- no translation found for bubbles_user_education_description (6663205638091146934) -->
- <skip />
- <!-- no translation found for bubbles_user_education_manage (1391639189507036423) -->
- <skip />
+ <string name="bubbles_user_education_title" msgid="3385222165904578710">"Mantenha os chats em primeiro plano"</string>
+ <string name="bubbles_user_education_description" msgid="6663205638091146934">"Os novos chats da app <xliff:g id="APP_NAME">%1$s</xliff:g> serão apresentados como balões. Toque num balão para o abrir. Arraste para o mover.\n\nToque no balão."</string>
+ <string name="bubbles_user_education_manage" msgid="1391639189507036423">"Toque em Gerir para desativar os balões desta app."</string>
<string name="notification_content_system_nav_changed" msgid="5077913144844684544">"A navegação no sistema foi atualizada. Para efetuar alterações, aceda às Definições."</string>
<string name="notification_content_gesture_nav_available" msgid="4431460803004659888">"Aceda às Definições para atualizar a navegação no sistema."</string>
<string name="inattentive_sleep_warning_title" msgid="3891371591713990373">"Modo de espera"</string>
@@ -1004,4 +1002,10 @@
<string name="controls_favorite_header_all" msgid="7507855973418969992">"Tudo"</string>
<string name="controls_favorite_load_error" msgid="2533215155804455348">"Não foi possível carregar a lista dos controlos."</string>
<string name="controls_favorite_other_zone_header" msgid="9089613266575525252">"Outro"</string>
+ <!-- no translation found for controls_dialog_title (8806193219278278442) -->
+ <skip />
+ <!-- no translation found for controls_dialog_ok (7011816381344485651) -->
+ <skip />
+ <!-- no translation found for controls_dialog_message (6292099631702047540) -->
+ <skip />
</resources>
diff --git a/packages/SystemUI/res/values-pt/strings.xml b/packages/SystemUI/res/values-pt/strings.xml
index 300461d48dbf..61ac664e9f08 100644
--- a/packages/SystemUI/res/values-pt/strings.xml
+++ b/packages/SystemUI/res/values-pt/strings.xml
@@ -558,6 +558,7 @@
<string name="monitoring_description_app_personal_work" msgid="6175816356939166101">"Seu perfil de trabalho é gerenciado por <xliff:g id="ORGANIZATION">%1$s</xliff:g>. O perfil está conectado a <xliff:g id="APPLICATION_WORK">%2$s</xliff:g>, que pode monitorar sua atividade profissional de rede, incluindo e-mails, apps e websites.\n\nVocê também está conectado a <xliff:g id="APPLICATION_PERSONAL">%3$s</xliff:g>, que pode monitorar sua atividade pessoal de rede."</string>
<string name="keyguard_indication_trust_unlocked" msgid="7395154975733744547">"Desbloqueado pelo TrustAgent"</string>
<string name="keyguard_indication_trust_disabled" msgid="6820793704816727918">"O dispositivo permanecerá bloqueado até que você o desbloqueie manualmente"</string>
+ <string name="keyguard_indication_trust_unlocked_plugged_in" msgid="2323452175329362855">"<xliff:g id="KEYGUARD_INDICATION">%1$s</xliff:g>\n<xliff:g id="POWER_INDICATION">%2$s</xliff:g>"</string>
<string name="hidden_notifications_title" msgid="1782412844777612795">"Receba notificações mais rápido"</string>
<string name="hidden_notifications_text" msgid="5899627470450792578">"Veja-as antes de desbloquear"</string>
<string name="hidden_notifications_cancel" msgid="4805370226181001278">"Não, obrigado"</string>
@@ -979,12 +980,9 @@
<string name="bubble_accessibility_action_move_bottom_left" msgid="6339015902495504715">"Mover para canto inferior esquerdo"</string>
<string name="bubble_accessibility_action_move_bottom_right" msgid="7471571700628346212">"Mover para canto inferior direito"</string>
<string name="bubble_dismiss_text" msgid="7071770411580452911">"Dispensar"</string>
- <!-- no translation found for bubbles_user_education_title (3385222165904578710) -->
- <skip />
- <!-- no translation found for bubbles_user_education_description (6663205638091146934) -->
- <skip />
- <!-- no translation found for bubbles_user_education_manage (1391639189507036423) -->
- <skip />
+ <string name="bubbles_user_education_title" msgid="3385222165904578710">"Manter chats em primeiro plano"</string>
+ <string name="bubbles_user_education_description" msgid="6663205638091146934">"Novos chats do app <xliff:g id="APP_NAME">%1$s</xliff:g> aparecerão como balões. Toque em um balão para abrir o chat. Arraste para mover.\n\nToque no balão"</string>
+ <string name="bubbles_user_education_manage" msgid="1391639189507036423">"Toque em \"Gerenciar\" para desativar os balões desse app"</string>
<string name="notification_content_system_nav_changed" msgid="5077913144844684544">"Navegação no sistema atualizada. Se quiser alterá-la, acesse as configurações."</string>
<string name="notification_content_gesture_nav_available" msgid="4431460803004659888">"Acesse as configurações para atualizar a navegação no sistema"</string>
<string name="inattentive_sleep_warning_title" msgid="3891371591713990373">"Em espera"</string>
@@ -1004,4 +1002,10 @@
<string name="controls_favorite_header_all" msgid="7507855973418969992">"Todos"</string>
<string name="controls_favorite_load_error" msgid="2533215155804455348">"Não foi possível carregar a lista de controles."</string>
<string name="controls_favorite_other_zone_header" msgid="9089613266575525252">"Outro"</string>
+ <!-- no translation found for controls_dialog_title (8806193219278278442) -->
+ <skip />
+ <!-- no translation found for controls_dialog_ok (7011816381344485651) -->
+ <skip />
+ <!-- no translation found for controls_dialog_message (6292099631702047540) -->
+ <skip />
</resources>
diff --git a/packages/SystemUI/res/values-ro/strings.xml b/packages/SystemUI/res/values-ro/strings.xml
index 845714e13599..e72f68c348aa 100644
--- a/packages/SystemUI/res/values-ro/strings.xml
+++ b/packages/SystemUI/res/values-ro/strings.xml
@@ -561,6 +561,7 @@
<string name="monitoring_description_app_personal_work" msgid="6175816356939166101">"Profilul de serviciu este gestionat de <xliff:g id="ORGANIZATION">%1$s</xliff:g>. Profilul este conectat la <xliff:g id="APPLICATION_WORK">%2$s</xliff:g>, care vă poate monitoriza activitatea în rețeaua de serviciu, inclusiv e-mailurile, aplicațiile și site-urile accesate.\n\nDe asemenea, v-ați conectat la <xliff:g id="APPLICATION_PERSONAL">%3$s</xliff:g>, care vă poate monitoriza activitatea în rețeaua personală."</string>
<string name="keyguard_indication_trust_unlocked" msgid="7395154975733744547">"Deblocat de TrustAgent"</string>
<string name="keyguard_indication_trust_disabled" msgid="6820793704816727918">"Dispozitivul va rămâne blocat până când îl deblocați manual"</string>
+ <string name="keyguard_indication_trust_unlocked_plugged_in" msgid="2323452175329362855">"<xliff:g id="KEYGUARD_INDICATION">%1$s</xliff:g>\n<xliff:g id="POWER_INDICATION">%2$s</xliff:g>"</string>
<string name="hidden_notifications_title" msgid="1782412844777612795">"Obțineți notificări mai rapid"</string>
<string name="hidden_notifications_text" msgid="5899627470450792578">"Doresc să se afișeze înainte de deblocare"</string>
<string name="hidden_notifications_cancel" msgid="4805370226181001278">"Nu, mulț."</string>
@@ -984,12 +985,9 @@
<string name="bubble_accessibility_action_move_bottom_left" msgid="6339015902495504715">"Mutați în stânga jos"</string>
<string name="bubble_accessibility_action_move_bottom_right" msgid="7471571700628346212">"Mutați în dreapta jos"</string>
<string name="bubble_dismiss_text" msgid="7071770411580452911">"Închideți"</string>
- <!-- no translation found for bubbles_user_education_title (3385222165904578710) -->
- <skip />
- <!-- no translation found for bubbles_user_education_description (6663205638091146934) -->
- <skip />
- <!-- no translation found for bubbles_user_education_manage (1391639189507036423) -->
- <skip />
+ <string name="bubbles_user_education_title" msgid="3385222165904578710">"Mențineți conversațiile prin chat în prim-plan"</string>
+ <string name="bubbles_user_education_description" msgid="6663205638091146934">"Conversațiile noi prin chat din <xliff:g id="APP_NAME">%1$s</xliff:g> vor apărea sub forma unor baloane. Atingeți un balon pentru a deschide o conversație. Trageți-l pentru a-l muta.\n\nAtingeți balonul."</string>
+ <string name="bubbles_user_education_manage" msgid="1391639189507036423">"Atingeți Gestionați pentru a dezactiva baloanele din această aplicație"</string>
<string name="notification_content_system_nav_changed" msgid="5077913144844684544">"Navigarea în sistem a fost actualizată. Pentru a face modificări, accesați Setările."</string>
<string name="notification_content_gesture_nav_available" msgid="4431460803004659888">"Accesați Setările pentru a actualiza navigarea în sistem"</string>
<string name="inattentive_sleep_warning_title" msgid="3891371591713990373">"Standby"</string>
@@ -1010,4 +1008,10 @@
<string name="controls_favorite_header_all" msgid="7507855973418969992">"Toate"</string>
<string name="controls_favorite_load_error" msgid="2533215155804455348">"Lista cu toate comenzile nu a putut fi încărcată."</string>
<string name="controls_favorite_other_zone_header" msgid="9089613266575525252">"Altul"</string>
+ <!-- no translation found for controls_dialog_title (8806193219278278442) -->
+ <skip />
+ <!-- no translation found for controls_dialog_ok (7011816381344485651) -->
+ <skip />
+ <!-- no translation found for controls_dialog_message (6292099631702047540) -->
+ <skip />
</resources>
diff --git a/packages/SystemUI/res/values-ru/strings.xml b/packages/SystemUI/res/values-ru/strings.xml
index c32627d36112..85b1bb3c2b4e 100644
--- a/packages/SystemUI/res/values-ru/strings.xml
+++ b/packages/SystemUI/res/values-ru/strings.xml
@@ -564,6 +564,7 @@
<string name="monitoring_description_app_personal_work" msgid="6175816356939166101">"Вашим рабочим профилем управляет организация \"<xliff:g id="ORGANIZATION">%1$s</xliff:g>\". Приложение \"<xliff:g id="APPLICATION_WORK">%2$s</xliff:g>\" может отслеживать ваши действия в корпоративной сети, включая работу с электронной почтой, приложениями и веб-сайтами.\n\nТакже запущено приложение \"<xliff:g id="APPLICATION_PERSONAL">%3$s</xliff:g>\", которое может отслеживать ваши действия в сети, выполняемые в личном профиле."</string>
<string name="keyguard_indication_trust_unlocked" msgid="7395154975733744547">"Разблокировано агентом доверия"</string>
<string name="keyguard_indication_trust_disabled" msgid="6820793704816727918">"Устройство необходимо будет разблокировать вручную"</string>
+ <string name="keyguard_indication_trust_unlocked_plugged_in" msgid="2323452175329362855">"<xliff:g id="KEYGUARD_INDICATION">%1$s</xliff:g>\n<xliff:g id="POWER_INDICATION">%2$s</xliff:g>"</string>
<string name="hidden_notifications_title" msgid="1782412844777612795">"Быстрый доступ к уведомлениям"</string>
<string name="hidden_notifications_text" msgid="5899627470450792578">"Просматривайте уведомления на заблокированном экране."</string>
<string name="hidden_notifications_cancel" msgid="4805370226181001278">"Закрыть"</string>
@@ -989,12 +990,9 @@
<string name="bubble_accessibility_action_move_bottom_left" msgid="6339015902495504715">"Перенести в левый нижний угол"</string>
<string name="bubble_accessibility_action_move_bottom_right" msgid="7471571700628346212">"Перенести в правый нижний угол"</string>
<string name="bubble_dismiss_text" msgid="7071770411580452911">"Закрыть"</string>
- <!-- no translation found for bubbles_user_education_title (3385222165904578710) -->
- <skip />
- <!-- no translation found for bubbles_user_education_description (6663205638091146934) -->
- <skip />
- <!-- no translation found for bubbles_user_education_manage (1391639189507036423) -->
- <skip />
+ <string name="bubbles_user_education_title" msgid="3385222165904578710">"Чаты на первом плане"</string>
+ <string name="bubbles_user_education_description" msgid="6663205638091146934">"Новые чаты из приложения \"<xliff:g id="APP_NAME">%1$s</xliff:g>\" будут появляться в виде всплывающих уведомлений. Чтобы открыть такое уведомление, нажмите на него. Чтобы переместить всплывающее уведомление, перетащите его.\n\nНажмите на всплывающее уведомление"</string>
+ <string name="bubbles_user_education_manage" msgid="1391639189507036423">"Чтобы отключить всплывающие уведомления от приложения, нажмите \"Настроить\"."</string>
<string name="notification_content_system_nav_changed" msgid="5077913144844684544">"Параметры навигации в системе обновлены. Чтобы изменить их, перейдите в настройки."</string>
<string name="notification_content_gesture_nav_available" msgid="4431460803004659888">"Чтобы обновить параметры навигации в системе, перейдите в настройки."</string>
<string name="inattentive_sleep_warning_title" msgid="3891371591713990373">"Переход в режим ожидания"</string>
@@ -1016,4 +1014,10 @@
<string name="controls_favorite_header_all" msgid="7507855973418969992">"Все"</string>
<string name="controls_favorite_load_error" msgid="2533215155804455348">"Не удалось загрузить список элементов управления."</string>
<string name="controls_favorite_other_zone_header" msgid="9089613266575525252">"Другое"</string>
+ <!-- no translation found for controls_dialog_title (8806193219278278442) -->
+ <skip />
+ <!-- no translation found for controls_dialog_ok (7011816381344485651) -->
+ <skip />
+ <!-- no translation found for controls_dialog_message (6292099631702047540) -->
+ <skip />
</resources>
diff --git a/packages/SystemUI/res/values-si/strings.xml b/packages/SystemUI/res/values-si/strings.xml
index ec78baacab72..17db52296b2f 100644
--- a/packages/SystemUI/res/values-si/strings.xml
+++ b/packages/SystemUI/res/values-si/strings.xml
@@ -558,6 +558,7 @@
<string name="monitoring_description_app_personal_work" msgid="6175816356939166101">"ඔබේ කාර්යාල පැතිකඩ කළමනාකරණය කරන්නේ <xliff:g id="ORGANIZATION">%1$s</xliff:g> විසිනි. ඊ-තැපැල්, යෙදුම් සහ වෙබ් අඩවි ඇතුළු ඔබේ කාර්යාල ජාල ක්‍රියාකාරකම් නිරීක්ෂණය කළ හැකි, <xliff:g id="APPLICATION_WORK">%2$s</xliff:g>, වෙත පැතිකඩ සම්බන්ධ වී ඇත.\n\nඔබ ඔබේ පෞද්ගලික ජාල ක්‍රියාකාරකම් නිරීක්ෂණය කළ හැකි, <xliff:g id="APPLICATION_PERSONAL">%3$s</xliff:g> වෙතද සම්බන්ධ වී ඇත."</string>
<string name="keyguard_indication_trust_unlocked" msgid="7395154975733744547">"TrustAgent මඟින් අඟුලු දමා තබා ගන්න"</string>
<string name="keyguard_indication_trust_disabled" msgid="6820793704816727918">"ඔබ අතින් අගුළු අරින තුරු උපකරණය අගුළු වැටි තිබේ"</string>
+ <string name="keyguard_indication_trust_unlocked_plugged_in" msgid="2323452175329362855">"<xliff:g id="KEYGUARD_INDICATION">%1$s</xliff:g>\n<xliff:g id="POWER_INDICATION">%2$s</xliff:g>"</string>
<string name="hidden_notifications_title" msgid="1782412844777612795">"දැනුම්දීම් ඉක්මනින් ලබාගන්න"</string>
<string name="hidden_notifications_text" msgid="5899627470450792578">"ඔබ අඟුළු හැරීමට කලින් ඒවා බලන්න"</string>
<string name="hidden_notifications_cancel" msgid="4805370226181001278">"එපා ස්තූතියි"</string>
@@ -979,12 +980,9 @@
<string name="bubble_accessibility_action_move_bottom_left" msgid="6339015902495504715">"පහළ වමට ගෙන යන්න"</string>
<string name="bubble_accessibility_action_move_bottom_right" msgid="7471571700628346212">"පහළ දකුණට ගෙන යන්න"</string>
<string name="bubble_dismiss_text" msgid="7071770411580452911">"ඉවතලන්න"</string>
- <!-- no translation found for bubbles_user_education_title (3385222165904578710) -->
- <skip />
- <!-- no translation found for bubbles_user_education_description (6663205638091146934) -->
- <skip />
- <!-- no translation found for bubbles_user_education_manage (1391639189507036423) -->
- <skip />
+ <string name="bubbles_user_education_title" msgid="3385222165904578710">"කල් තියා කතාබස් කර ගෙන යන්න"</string>
+ <string name="bubbles_user_education_description" msgid="6663205638091146934">"<xliff:g id="APP_NAME">%1$s</xliff:g> වෙතින් නව කතාබස් බුබුලු ලෙස දිස් වනු ඇත. බුබුලක් විවෘත කිරීමට එය තට්ටු කරන්න. එය ගෙන යාමට අදින්න.\n\nබුබුල තට්ටු කරන්න"</string>
+ <string name="bubbles_user_education_manage" msgid="1391639189507036423">"මෙම යෙදුමෙන් බුබුලු ක්‍රියාවිරහිත කිරීමට කළමනාකරණය කරන්න තට්ටු කරන්න"</string>
<string name="notification_content_system_nav_changed" msgid="5077913144844684544">"පද්ධති සංචලනය යාවත්කාලීන කළා. වෙනස්කම් සිදු කිරීමට, සැකසීම් වෙත යන්න."</string>
<string name="notification_content_gesture_nav_available" msgid="4431460803004659888">"පද්ධති සංචලනය යාවත්කාලීන කිරීමට සැකසීම් වෙත යන්න"</string>
<string name="inattentive_sleep_warning_title" msgid="3891371591713990373">"පොරොත්තු"</string>
@@ -1004,4 +1002,10 @@
<string name="controls_favorite_header_all" msgid="7507855973418969992">"සියලු"</string>
<string name="controls_favorite_load_error" msgid="2533215155804455348">"සියලු පාලනවල ලැයිස්තුව පූරණය කළ නොහැකි විය."</string>
<string name="controls_favorite_other_zone_header" msgid="9089613266575525252">"වෙනත්"</string>
+ <!-- no translation found for controls_dialog_title (8806193219278278442) -->
+ <skip />
+ <!-- no translation found for controls_dialog_ok (7011816381344485651) -->
+ <skip />
+ <!-- no translation found for controls_dialog_message (6292099631702047540) -->
+ <skip />
</resources>
diff --git a/packages/SystemUI/res/values-sk/strings.xml b/packages/SystemUI/res/values-sk/strings.xml
index bb6ac469526a..295e700af097 100644
--- a/packages/SystemUI/res/values-sk/strings.xml
+++ b/packages/SystemUI/res/values-sk/strings.xml
@@ -564,6 +564,7 @@
<string name="monitoring_description_app_personal_work" msgid="6175816356939166101">"Váš pracovný profil spravuje organizácia <xliff:g id="ORGANIZATION">%1$s</xliff:g>. Je pripojený k aplikácii <xliff:g id="APPLICATION_WORK">%2$s</xliff:g>, ktorá môže sledovať vašu pracovnú aktivitu v sieti vrátane správ, aplikácií a webových stránok.\n\nPripojili ste sa k aplikácii <xliff:g id="APPLICATION_PERSONAL">%3$s</xliff:g>, ktorá môže sledovať vašu osobnú aktivitu v sieti."</string>
<string name="keyguard_indication_trust_unlocked" msgid="7395154975733744547">"Odomknutie udržiava TrustAgent"</string>
<string name="keyguard_indication_trust_disabled" msgid="6820793704816727918">"Zariadenie zostane uzamknuté, dokým ho ručne neodomknete."</string>
+ <string name="keyguard_indication_trust_unlocked_plugged_in" msgid="2323452175329362855">"<xliff:g id="KEYGUARD_INDICATION">%1$s</xliff:g>\n<xliff:g id="POWER_INDICATION">%2$s</xliff:g>"</string>
<string name="hidden_notifications_title" msgid="1782412844777612795">"Získavať upozornenia rýchlejšie"</string>
<string name="hidden_notifications_text" msgid="5899627470450792578">"Zobraziť pred odomknutím"</string>
<string name="hidden_notifications_cancel" msgid="4805370226181001278">"Nie, vďaka"</string>
@@ -989,12 +990,9 @@
<string name="bubble_accessibility_action_move_bottom_left" msgid="6339015902495504715">"Presunúť doľava nadol"</string>
<string name="bubble_accessibility_action_move_bottom_right" msgid="7471571700628346212">"Presunúť doprava nadol"</string>
<string name="bubble_dismiss_text" msgid="7071770411580452911">"Zavrieť"</string>
- <!-- no translation found for bubbles_user_education_title (3385222165904578710) -->
- <skip />
- <!-- no translation found for bubbles_user_education_description (6663205638091146934) -->
- <skip />
- <!-- no translation found for bubbles_user_education_manage (1391639189507036423) -->
- <skip />
+ <string name="bubbles_user_education_title" msgid="3385222165904578710">"Zobrazovať čety na popredí"</string>
+ <string name="bubbles_user_education_description" msgid="6663205638091146934">"Nové čety z aplikácie <xliff:g id="APP_NAME">%1$s</xliff:g> sa budú zobrazovať ako bubliny. Bubliny otvoríte klepnutím na ne. Premiestnite ich presunutím.\n\nKlepnite na bublinu."</string>
+ <string name="bubbles_user_education_manage" msgid="1391639189507036423">"Klepnutím na Spravovať vypnite bubliny z tejto aplikácie"</string>
<string name="notification_content_system_nav_changed" msgid="5077913144844684544">"Navigácia v systéme bola aktualizovaná. Ak chcete vykonať zmeny, prejdite do Nastavení."</string>
<string name="notification_content_gesture_nav_available" msgid="4431460803004659888">"Prejdite do Nastavení a aktualizujte navigáciu v systéme"</string>
<string name="inattentive_sleep_warning_title" msgid="3891371591713990373">"Pohotovostný režim"</string>
@@ -1016,4 +1014,10 @@
<string name="controls_favorite_header_all" msgid="7507855973418969992">"Všetko"</string>
<string name="controls_favorite_load_error" msgid="2533215155804455348">"Zoznam všetkých ovl. prvkov sa nepodarilo načítať."</string>
<string name="controls_favorite_other_zone_header" msgid="9089613266575525252">"Iné"</string>
+ <!-- no translation found for controls_dialog_title (8806193219278278442) -->
+ <skip />
+ <!-- no translation found for controls_dialog_ok (7011816381344485651) -->
+ <skip />
+ <!-- no translation found for controls_dialog_message (6292099631702047540) -->
+ <skip />
</resources>
diff --git a/packages/SystemUI/res/values-sl/strings.xml b/packages/SystemUI/res/values-sl/strings.xml
index 5280f6e31de4..b524749fdc5c 100644
--- a/packages/SystemUI/res/values-sl/strings.xml
+++ b/packages/SystemUI/res/values-sl/strings.xml
@@ -564,6 +564,7 @@
<string name="monitoring_description_app_personal_work" msgid="6175816356939166101">"Delovni profil upravlja organizacija <xliff:g id="ORGANIZATION">%1$s</xliff:g>. Profil je povezan z aplikacijo <xliff:g id="APPLICATION_WORK">%2$s</xliff:g>, ki lahko nadzira vašo delovno omrežno dejavnost, vključno z e-pošto, aplikacijami in spletnimi mesti.\n\nPovezani ste tudi z aplikacijo <xliff:g id="APPLICATION_PERSONAL">%3$s</xliff:g>, ki lahko nadzira vašo osebno omrežno dejavnost."</string>
<string name="keyguard_indication_trust_unlocked" msgid="7395154975733744547">"TrustAgent ohranja odklenjeno"</string>
<string name="keyguard_indication_trust_disabled" msgid="6820793704816727918">"Naprava bo ostala zaklenjena, dokler je ročno ne odklenete."</string>
+ <string name="keyguard_indication_trust_unlocked_plugged_in" msgid="2323452175329362855">"<xliff:g id="KEYGUARD_INDICATION">%1$s</xliff:g>\n<xliff:g id="POWER_INDICATION">%2$s</xliff:g>"</string>
<string name="hidden_notifications_title" msgid="1782412844777612795">"Hitrejše prejemanje obvestil"</string>
<string name="hidden_notifications_text" msgid="5899627470450792578">"Oglejte si jih pred odklepanjem"</string>
<string name="hidden_notifications_cancel" msgid="4805370226181001278">"Ne, hvala"</string>
@@ -989,12 +990,9 @@
<string name="bubble_accessibility_action_move_bottom_left" msgid="6339015902495504715">"Premakni spodaj levo"</string>
<string name="bubble_accessibility_action_move_bottom_right" msgid="7471571700628346212">"Premakni spodaj desno"</string>
<string name="bubble_dismiss_text" msgid="7071770411580452911">"Opusti"</string>
- <!-- no translation found for bubbles_user_education_title (3385222165904578710) -->
- <skip />
- <!-- no translation found for bubbles_user_education_description (6663205638091146934) -->
- <skip />
- <!-- no translation found for bubbles_user_education_manage (1391639189507036423) -->
- <skip />
+ <string name="bubbles_user_education_title" msgid="3385222165904578710">"Klepete obdrži v ospredju"</string>
+ <string name="bubbles_user_education_description" msgid="6663205638091146934">"Novi klepeti v aplikaciji <xliff:g id="APP_NAME">%1$s</xliff:g> bodo prikazani kot oblački. Dotaknite se oblačka, da ga odprete. Povlecite, da ga premaknete.\n\nDotaknite se oblačka"</string>
+ <string name="bubbles_user_education_manage" msgid="1391639189507036423">"Dotaknite se »Upravljanje«, da izklopite oblačke iz te aplikacije"</string>
<string name="notification_content_system_nav_changed" msgid="5077913144844684544">"Krmarjenje po sistemu je posodobljeno. Če želite opraviti spremembe, odprite nastavitve."</string>
<string name="notification_content_gesture_nav_available" msgid="4431460803004659888">"Če želite posodobiti krmarjenje po sistemu, odprite nastavitve"</string>
<string name="inattentive_sleep_warning_title" msgid="3891371591713990373">"Stanje pripravljenosti"</string>
@@ -1016,4 +1014,10 @@
<string name="controls_favorite_header_all" msgid="7507855973418969992">"Vse"</string>
<string name="controls_favorite_load_error" msgid="2533215155804455348">"Seznama vseh kontrolnikov ni bilo mogoče naložiti."</string>
<string name="controls_favorite_other_zone_header" msgid="9089613266575525252">"Drugo"</string>
+ <!-- no translation found for controls_dialog_title (8806193219278278442) -->
+ <skip />
+ <!-- no translation found for controls_dialog_ok (7011816381344485651) -->
+ <skip />
+ <!-- no translation found for controls_dialog_message (6292099631702047540) -->
+ <skip />
</resources>
diff --git a/packages/SystemUI/res/values-sq/strings.xml b/packages/SystemUI/res/values-sq/strings.xml
index c1a32c54950d..2e83d25d97b7 100644
--- a/packages/SystemUI/res/values-sq/strings.xml
+++ b/packages/SystemUI/res/values-sq/strings.xml
@@ -558,6 +558,7 @@
<string name="monitoring_description_app_personal_work" msgid="6175816356939166101">"Profili yt i punës menaxhohet nga <xliff:g id="ORGANIZATION">%1$s</xliff:g>. Profili është i lidhur me <xliff:g id="APPLICATION_WORK">%2$s</xliff:g>, i cili mund të monitorojë aktivitetin tënd të punës në rrjet, duke përfshirë mail-et, aplikacionet dhe sajtet e uebit.\n\nJe lidhur gjithashtu edhe me <xliff:g id="APPLICATION_PERSONAL">%3$s</xliff:g>, i cili mund të monitorojë aktivitetin tënd personal në rrjet."</string>
<string name="keyguard_indication_trust_unlocked" msgid="7395154975733744547">"Mbajtur shkyçur nga TrustAgent"</string>
<string name="keyguard_indication_trust_disabled" msgid="6820793704816727918">"Pajisje do të qëndrojë e kyçur derisa ta shkyçësh manualisht"</string>
+ <string name="keyguard_indication_trust_unlocked_plugged_in" msgid="2323452175329362855">"<xliff:g id="KEYGUARD_INDICATION">%1$s</xliff:g>\n<xliff:g id="POWER_INDICATION">%2$s</xliff:g>"</string>
<string name="hidden_notifications_title" msgid="1782412844777612795">"Merr njoftime më shpejt"</string>
<string name="hidden_notifications_text" msgid="5899627470450792578">"Shikoji para se t\'i shkyçësh"</string>
<string name="hidden_notifications_cancel" msgid="4805370226181001278">"Jo, faleminderit!"</string>
@@ -979,12 +980,9 @@
<string name="bubble_accessibility_action_move_bottom_left" msgid="6339015902495504715">"Zhvendos poshtë majtas"</string>
<string name="bubble_accessibility_action_move_bottom_right" msgid="7471571700628346212">"Lëvize poshtë djathtas"</string>
<string name="bubble_dismiss_text" msgid="7071770411580452911">"Hiq"</string>
- <!-- no translation found for bubbles_user_education_title (3385222165904578710) -->
- <skip />
- <!-- no translation found for bubbles_user_education_description (6663205638091146934) -->
- <skip />
- <!-- no translation found for bubbles_user_education_manage (1391639189507036423) -->
- <skip />
+ <string name="bubbles_user_education_title" msgid="3385222165904578710">"Mbaji bisedat në plan të parë"</string>
+ <string name="bubbles_user_education_description" msgid="6663205638091146934">"Bisedat e reja nga <xliff:g id="APP_NAME">%1$s</xliff:g> do të shfaqen si flluska. Trokit mbi një flluskë për ta hapur atë. Zvarrit për ta zhvendosur atë.\n\nTrokit mbi flluskë"</string>
+ <string name="bubbles_user_education_manage" msgid="1391639189507036423">"Trokit \"Menaxho\" për të çaktivizuar flluskat nga ky aplikacion"</string>
<string name="notification_content_system_nav_changed" msgid="5077913144844684544">"Navigimi i sistemit u përditësua. Për të bërë ndryshime, shko te \"Cilësimet\"."</string>
<string name="notification_content_gesture_nav_available" msgid="4431460803004659888">"Shko te \"Cilësimet\" për të përditësuar navigimin e sistemit"</string>
<string name="inattentive_sleep_warning_title" msgid="3891371591713990373">"Në gatishmëri"</string>
@@ -1004,4 +1002,10 @@
<string name="controls_favorite_header_all" msgid="7507855973418969992">"Të gjitha"</string>
<string name="controls_favorite_load_error" msgid="2533215155804455348">"Lista e të gjitha kontrolleve nuk mund të ngarkohej."</string>
<string name="controls_favorite_other_zone_header" msgid="9089613266575525252">"Tjetër"</string>
+ <!-- no translation found for controls_dialog_title (8806193219278278442) -->
+ <skip />
+ <!-- no translation found for controls_dialog_ok (7011816381344485651) -->
+ <skip />
+ <!-- no translation found for controls_dialog_message (6292099631702047540) -->
+ <skip />
</resources>
diff --git a/packages/SystemUI/res/values-sr/strings.xml b/packages/SystemUI/res/values-sr/strings.xml
index 87c9d3fdf3ff..f77d4a259312 100644
--- a/packages/SystemUI/res/values-sr/strings.xml
+++ b/packages/SystemUI/res/values-sr/strings.xml
@@ -561,6 +561,7 @@
<string name="monitoring_description_app_personal_work" msgid="6175816356939166101">"Профилом за Work управља <xliff:g id="ORGANIZATION">%1$s</xliff:g>. Повезан је са апликацијом <xliff:g id="APPLICATION_WORK">%2$s</xliff:g>, која може да надгледа активности на пословној мрежи, укључујући имејлове, апликације и веб-сајтове.\n\nПовезани сте и са апликацијом <xliff:g id="APPLICATION_PERSONAL">%3$s</xliff:g>, која може да надгледа активности на личној мрежи."</string>
<string name="keyguard_indication_trust_unlocked" msgid="7395154975733744547">"Поуздани агент спречава закључавање"</string>
<string name="keyguard_indication_trust_disabled" msgid="6820793704816727918">"Уређај ће остати закључан док га не откључате ручно"</string>
+ <string name="keyguard_indication_trust_unlocked_plugged_in" msgid="2323452175329362855">"<xliff:g id="KEYGUARD_INDICATION">%1$s</xliff:g>\n<xliff:g id="POWER_INDICATION">%2$s</xliff:g>"</string>
<string name="hidden_notifications_title" msgid="1782412844777612795">"Брже добијајте обавештења"</string>
<string name="hidden_notifications_text" msgid="5899627470450792578">"Прегледајте их пре откључавања"</string>
<string name="hidden_notifications_cancel" msgid="4805370226181001278">"Не, хвала"</string>
@@ -984,12 +985,9 @@
<string name="bubble_accessibility_action_move_bottom_left" msgid="6339015902495504715">"Премести доле лево"</string>
<string name="bubble_accessibility_action_move_bottom_right" msgid="7471571700628346212">"Премести доле десно"</string>
<string name="bubble_dismiss_text" msgid="7071770411580452911">"Одбаци"</string>
- <!-- no translation found for bubbles_user_education_title (3385222165904578710) -->
- <skip />
- <!-- no translation found for bubbles_user_education_description (6663205638091146934) -->
- <skip />
- <!-- no translation found for bubbles_user_education_manage (1391639189507036423) -->
- <skip />
+ <string name="bubbles_user_education_title" msgid="3385222165904578710">"Нека поруке ћаскања остану у првом плану"</string>
+ <string name="bubbles_user_education_description" msgid="6663205638091146934">"Нове поруке ћаскања из апликације <xliff:g id="APP_NAME">%1$s</xliff:g> ће се приказати као облачићи. Додирните облачић да бисте га отворили. Превуците да бисте га преместили.\n\nДодирните облачић"</string>
+ <string name="bubbles_user_education_manage" msgid="1391639189507036423">"Додирните Управљајте да бисте искључили облачиће из ове апликације"</string>
<string name="notification_content_system_nav_changed" msgid="5077913144844684544">"Навигација система је ажурирана. Да бисте унели измене, идите у Подешавања."</string>
<string name="notification_content_gesture_nav_available" msgid="4431460803004659888">"Идите у Подешавања да бисте ажурирали навигацију система"</string>
<string name="inattentive_sleep_warning_title" msgid="3891371591713990373">"Стање приправности"</string>
@@ -1010,4 +1008,10 @@
<string name="controls_favorite_header_all" msgid="7507855973418969992">"Све"</string>
<string name="controls_favorite_load_error" msgid="2533215155804455348">"Учитавање листе свих контрола није успело."</string>
<string name="controls_favorite_other_zone_header" msgid="9089613266575525252">"Друго"</string>
+ <!-- no translation found for controls_dialog_title (8806193219278278442) -->
+ <skip />
+ <!-- no translation found for controls_dialog_ok (7011816381344485651) -->
+ <skip />
+ <!-- no translation found for controls_dialog_message (6292099631702047540) -->
+ <skip />
</resources>
diff --git a/packages/SystemUI/res/values-sv/strings.xml b/packages/SystemUI/res/values-sv/strings.xml
index c4975740824b..76635eeb028b 100644
--- a/packages/SystemUI/res/values-sv/strings.xml
+++ b/packages/SystemUI/res/values-sv/strings.xml
@@ -558,6 +558,7 @@
<string name="monitoring_description_app_personal_work" msgid="6175816356939166101">"Jobbprofilen hanteras av <xliff:g id="ORGANIZATION">%1$s</xliff:g>. Profilen är ansluten till <xliff:g id="APPLICATION_WORK">%2$s</xliff:g> som kan bevaka din nätverksaktivitet på jobbet, exempelvis e-post, appar och webbplatser.\n\nDu är även ansluten till <xliff:g id="APPLICATION_PERSONAL">%3$s</xliff:g> som kan bevaka din privata nätverksaktivitet."</string>
<string name="keyguard_indication_trust_unlocked" msgid="7395154975733744547">"Hålls olåst med TrustAgent"</string>
<string name="keyguard_indication_trust_disabled" msgid="6820793704816727918">"Enheten förblir låst tills du låser upp den manuellt"</string>
+ <string name="keyguard_indication_trust_unlocked_plugged_in" msgid="2323452175329362855">"<xliff:g id="KEYGUARD_INDICATION">%1$s</xliff:g>\n<xliff:g id="POWER_INDICATION">%2$s</xliff:g>"</string>
<string name="hidden_notifications_title" msgid="1782412844777612795">"Få aviseringar snabbare"</string>
<string name="hidden_notifications_text" msgid="5899627470450792578">"Visa dem innan du låser upp"</string>
<string name="hidden_notifications_cancel" msgid="4805370226181001278">"Nej tack"</string>
@@ -979,12 +980,9 @@
<string name="bubble_accessibility_action_move_bottom_left" msgid="6339015902495504715">"Flytta längst ned till vänster"</string>
<string name="bubble_accessibility_action_move_bottom_right" msgid="7471571700628346212">"Flytta längst ned till höger"</string>
<string name="bubble_dismiss_text" msgid="7071770411580452911">"Stäng"</string>
- <!-- no translation found for bubbles_user_education_title (3385222165904578710) -->
- <skip />
- <!-- no translation found for bubbles_user_education_description (6663205638091146934) -->
- <skip />
- <!-- no translation found for bubbles_user_education_manage (1391639189507036423) -->
- <skip />
+ <string name="bubbles_user_education_title" msgid="3385222165904578710">"Håll chattar i förgrunden"</string>
+ <string name="bubbles_user_education_description" msgid="6663205638091146934">"Nya chattar från <xliff:g id="APP_NAME">%1$s</xliff:g> visas som bubblor. Tryck på en bubbla som du vill öppna. Flytta den genom att dra.\n\nTryck på bubblan"</string>
+ <string name="bubbles_user_education_manage" msgid="1391639189507036423">"Tryck på Hantera för att stänga av bubblor från den här appen"</string>
<string name="notification_content_system_nav_changed" msgid="5077913144844684544">"Systemnavigeringen har uppdaterats. Öppna inställningarna om du vill ändra något."</string>
<string name="notification_content_gesture_nav_available" msgid="4431460803004659888">"Öppna inställningarna och uppdatera systemnavigeringen"</string>
<string name="inattentive_sleep_warning_title" msgid="3891371591713990373">"Viloläge"</string>
@@ -1004,4 +1002,10 @@
<string name="controls_favorite_header_all" msgid="7507855973418969992">"Alla"</string>
<string name="controls_favorite_load_error" msgid="2533215155804455348">"Listan med alla kontroller kunde inte läsas in."</string>
<string name="controls_favorite_other_zone_header" msgid="9089613266575525252">"Övrigt"</string>
+ <!-- no translation found for controls_dialog_title (8806193219278278442) -->
+ <skip />
+ <!-- no translation found for controls_dialog_ok (7011816381344485651) -->
+ <skip />
+ <!-- no translation found for controls_dialog_message (6292099631702047540) -->
+ <skip />
</resources>
diff --git a/packages/SystemUI/res/values-sw/strings.xml b/packages/SystemUI/res/values-sw/strings.xml
index 8d2b13780c52..3a5d6ce3f4a4 100644
--- a/packages/SystemUI/res/values-sw/strings.xml
+++ b/packages/SystemUI/res/values-sw/strings.xml
@@ -558,6 +558,7 @@
<string name="monitoring_description_app_personal_work" msgid="6175816356939166101">"Wasifu wako wa kazini unasimamiwa na <xliff:g id="ORGANIZATION">%1$s</xliff:g>. Wasifu umeunganishwa kwenye <xliff:g id="APPLICATION_WORK">%2$s</xliff:g>, ambayo inaweza kufuatilia shughuli zako kwenye mtandao wa kazini, ikiwa ni pamoja na barua pepe, programu na tovuti.\n\n Umeunganishwa pia kwenye <xliff:g id="APPLICATION_PERSONAL">%3$s</xliff:g>, ambayo inaweza kufuatilia shughuli zako kwenye mtandao wa binafsi."</string>
<string name="keyguard_indication_trust_unlocked" msgid="7395154975733744547">"Imefunguliwa na kipengele cha kutathmini hali ya kuaminika"</string>
<string name="keyguard_indication_trust_disabled" msgid="6820793704816727918">"Kifaa kitaendelea kuwa katika hali ya kufungwa hadi utakapokifungua mwenyewe"</string>
+ <string name="keyguard_indication_trust_unlocked_plugged_in" msgid="2323452175329362855">"<xliff:g id="KEYGUARD_INDICATION">%1$s</xliff:g>\n<xliff:g id="POWER_INDICATION">%2$s</xliff:g>"</string>
<string name="hidden_notifications_title" msgid="1782412844777612795">"Pata arifa kwa haraka"</string>
<string name="hidden_notifications_text" msgid="5899627470450792578">"Zitazame kabla hujafungua"</string>
<string name="hidden_notifications_cancel" msgid="4805370226181001278">"Hapana"</string>
@@ -979,12 +980,9 @@
<string name="bubble_accessibility_action_move_bottom_left" msgid="6339015902495504715">"Sogeza chini kushoto"</string>
<string name="bubble_accessibility_action_move_bottom_right" msgid="7471571700628346212">"Sogeza chini kulia"</string>
<string name="bubble_dismiss_text" msgid="7071770411580452911">"Ondoa"</string>
- <!-- no translation found for bubbles_user_education_title (3385222165904578710) -->
- <skip />
- <!-- no translation found for bubbles_user_education_description (6663205638091146934) -->
- <skip />
- <!-- no translation found for bubbles_user_education_manage (1391639189507036423) -->
- <skip />
+ <string name="bubbles_user_education_title" msgid="3385222165904578710">"Zipe gumzo kipaumbele"</string>
+ <string name="bubbles_user_education_description" msgid="6663205638091146934">"Gumzo mpya kutoka <xliff:g id="APP_NAME">%1$s</xliff:g> zitaonekana kama viputo. Gusa kiputo ili ukifungue. Buruta ili ukisogeze.\n\nGusa kiputo"</string>
+ <string name="bubbles_user_education_manage" msgid="1391639189507036423">"Gusa Dhibiti ili uzime viputo kwenye programu hii"</string>
<string name="notification_content_system_nav_changed" msgid="5077913144844684544">"Umesasisha usogezaji kwenye mfumo. Ili ubadilishe, nenda kwenye Mipangilio."</string>
<string name="notification_content_gesture_nav_available" msgid="4431460803004659888">"Nenda kwenye mipangilio ili usasishe usogezaji kwenye mfumo"</string>
<string name="inattentive_sleep_warning_title" msgid="3891371591713990373">"Hali tuli"</string>
@@ -1004,4 +1002,10 @@
<string name="controls_favorite_header_all" msgid="7507855973418969992">"Vyote"</string>
<string name="controls_favorite_load_error" msgid="2533215155804455348">"Imeshindwa kupakia orodha ya vidhibiti vyote."</string>
<string name="controls_favorite_other_zone_header" msgid="9089613266575525252">"Nyingine"</string>
+ <!-- no translation found for controls_dialog_title (8806193219278278442) -->
+ <skip />
+ <!-- no translation found for controls_dialog_ok (7011816381344485651) -->
+ <skip />
+ <!-- no translation found for controls_dialog_message (6292099631702047540) -->
+ <skip />
</resources>
diff --git a/packages/SystemUI/res/values-ta/strings.xml b/packages/SystemUI/res/values-ta/strings.xml
index 3f1ddbd776c1..1583bf847ecb 100644
--- a/packages/SystemUI/res/values-ta/strings.xml
+++ b/packages/SystemUI/res/values-ta/strings.xml
@@ -63,18 +63,12 @@
<string name="usb_debugging_allow" msgid="1722643858015321328">"அனுமதி"</string>
<string name="usb_debugging_secondary_user_title" msgid="7843050591380107998">"USB பிழைதிருத்தம் அனுமதிக்கப்படவில்லை"</string>
<string name="usb_debugging_secondary_user_message" msgid="3740347841470403244">"தற்போது இந்தச் சாதனத்தில் உள்நுழைந்துள்ள பயனரால் USB பிழைதிருத்தத்தை இயக்க முடியாது. இந்த அம்சத்தை இயக்க, முதன்மைப் பயனருக்கு மாறவும்."</string>
- <!-- no translation found for wifi_debugging_title (7300007687492186076) -->
- <skip />
- <!-- no translation found for wifi_debugging_message (5461204211731802995) -->
- <skip />
- <!-- no translation found for wifi_debugging_always (2968383799517975155) -->
- <skip />
- <!-- no translation found for wifi_debugging_allow (4573224609684957886) -->
- <skip />
- <!-- no translation found for wifi_debugging_secondary_user_title (2493201475880517725) -->
- <skip />
- <!-- no translation found for wifi_debugging_secondary_user_message (4492383073970079751) -->
- <skip />
+ <string name="wifi_debugging_title" msgid="7300007687492186076">"இந்த நெட்வொர்க்கில் வயர்லெஸ் பிழைதிருத்தத்தை அனுமதிக்கவா?"</string>
+ <string name="wifi_debugging_message" msgid="5461204211731802995">"நெட்வொர்க் பெயர் (SSID)\n<xliff:g id="SSID_0">%1$s</xliff:g>\n\nவைஃபை முகவரி (BSSID)\n<xliff:g id="BSSID_1">%2$s</xliff:g>"</string>
+ <string name="wifi_debugging_always" msgid="2968383799517975155">"இந்த நெட்வொர்க்கில் எப்போதும் அனுமதி"</string>
+ <string name="wifi_debugging_allow" msgid="4573224609684957886">"அனுமதி"</string>
+ <string name="wifi_debugging_secondary_user_title" msgid="2493201475880517725">"வயர்லெஸ் பிழைதிருத்தம் அனுமதிக்கப்படவில்லை"</string>
+ <string name="wifi_debugging_secondary_user_message" msgid="4492383073970079751">"தற்போது இந்தச் சாதனத்தில் உள்நுழைந்துள்ள பயனரால் வயர்லெஸ் பிழைதிருத்தத்தை இயக்க முடியாது. இந்த அம்சத்தை இயக்க முதன்மைப் பயனருக்கு மாறவும்."</string>
<string name="usb_contaminant_title" msgid="894052515034594113">"USB போர்ட் முடக்கப்பட்டது"</string>
<string name="usb_contaminant_message" msgid="7730476585174719805">"தேவையற்றவையில் இருந்து உங்கள் சாதனத்தைப் பாதுகாக்க USB போர்ட் முடக்கப்பட்டுள்ளது. மேலும் எந்தத் துணைக் கருவிகளையும் அது கண்டறியாது.\n\nUSB போர்ட்டை மீண்டும் எப்போது பயன்படுத்தலாம் என்பதைப் பற்றி உங்களுக்குத் தெரிவிக்கப்படும்."</string>
<string name="usb_port_enabled" msgid="531823867664717018">"சார்ஜர்களையும் துணைக்கருவிகளையும் கண்டறிவதற்காக USB போர்ட் இயக்கப்பட்டுள்ளது"</string>
@@ -500,8 +494,7 @@
<string name="manage_notifications_text" msgid="6885645344647733116">"அறிவிப்புகளை நிர்வகி"</string>
<string name="manage_notifications_history_text" msgid="57055985396576230">"வரலாறு"</string>
<string name="notification_section_header_gentle" msgid="3044910806569985386">"ஒலியில்லாத அறிவிப்புகள்"</string>
- <!-- no translation found for notification_section_header_alerting (3168140660646863240) -->
- <skip />
+ <string name="notification_section_header_alerting" msgid="3168140660646863240">"விழிப்பூட்டல் அறிவிப்புகள்"</string>
<string name="notification_section_header_conversations" msgid="821834744538345661">"உரையாடல்கள்"</string>
<string name="accessibility_notification_section_header_gentle_clear_all" msgid="6490207897764933919">"ஒலியில்லாத அழைப்புகள் அனைத்தையும் அழிக்கும்"</string>
<string name="dnd_suppressing_shade_text" msgid="5588252250634464042">"\'தொந்தரவு செய்ய வேண்டாம்\' அம்சத்தின் மூலம் அறிவிப்புகள் இடைநிறுத்தப்பட்டுள்ளன"</string>
@@ -565,6 +558,8 @@
<string name="monitoring_description_app_personal_work" msgid="6175816356939166101">"உங்கள் பணிக் கணக்கை <xliff:g id="ORGANIZATION">%1$s</xliff:g> நிர்வகிக்கிறது. மின்னஞ்சல்கள், ஆப்ஸ், இணையதளங்கள் உட்பட உங்கள் பணி நெட்வொர்க் செயல்பாட்டைக் கண்காணிக்கக்கூடிய <xliff:g id="APPLICATION_WORK">%2$s</xliff:g> உடன் அது இணைக்கப்பட்டுள்ளது.\n\nஉங்கள் தனிப்பட்ட நெட்வொர்க் செயல்பாட்டைக் கண்காணிக்கக்கூடிய <xliff:g id="APPLICATION_PERSONAL">%3$s</xliff:g> உடனும் இணைக்கப்பட்டுள்ளீர்கள்."</string>
<string name="keyguard_indication_trust_unlocked" msgid="7395154975733744547">"TrustAgent இதைத் திறந்தே வைத்துள்ளது"</string>
<string name="keyguard_indication_trust_disabled" msgid="6820793704816727918">"நீங்கள் கைமுறையாகத் திறக்கும் வரை, சாதனம் பூட்டப்பட்டிருக்கும்"</string>
+ <!-- no translation found for keyguard_indication_trust_unlocked_plugged_in (2323452175329362855) -->
+ <skip />
<string name="hidden_notifications_title" msgid="1782412844777612795">"விரைவாக அறிவிப்புகளைப் பெறுதல்"</string>
<string name="hidden_notifications_text" msgid="5899627470450792578">"திறக்கும் முன் அவற்றைப் பார்க்கவும்"</string>
<string name="hidden_notifications_cancel" msgid="4805370226181001278">"வேண்டாம்"</string>
@@ -700,10 +695,8 @@
<string name="notification_channel_summary_low" msgid="7300447764759926720">"ஒலியோ அதிர்வோ இல்லாமல் முழு கவனம் செலுத்த உதவும்."</string>
<string name="notification_channel_summary_default" msgid="3539949463907902037">"ஒலியோ அதிர்வோ ஏற்படுத்தி உங்கள் கவனத்தை ஈர்க்கும்."</string>
<string name="notification_channel_summary_bubble" msgid="7235935211580860537">"இந்த உள்ளடக்கத்திற்கான மிதக்கும் ஷார்ட்கட் மூலம் உங்கள் கவனத்தைப் பெற்றிருக்கும்."</string>
- <!-- no translation found for bubble_overflow_empty_title (3120029421991510842) -->
- <skip />
- <!-- no translation found for bubble_overflow_empty_subtitle (198257239740933131) -->
- <skip />
+ <string name="bubble_overflow_empty_title" msgid="3120029421991510842">"சமீபத்திய குமிழ்கள் இல்லை"</string>
+ <string name="bubble_overflow_empty_subtitle" msgid="198257239740933131">"சமீபத்திய குமிழ்களும் நிராகரிக்கப்பட்ட குமிழ்களும் இங்கே தோன்றும்."</string>
<string name="notification_unblockable_desc" msgid="2073030886006190804">"இந்த அறிவிப்புகளை மாற்ற இயலாது."</string>
<string name="notification_multichannel_desc" msgid="7414593090056236179">"இந்த அறிவுப்புக் குழுக்களை இங்கே உள்ளமைக்க இயலாது"</string>
<string name="notification_delegate_header" msgid="1264510071031479920">"ப்ராக்ஸியான அறிவிப்பு"</string>
@@ -1003,15 +996,20 @@
<string name="quick_controls_title" msgid="525285759614231333">"விரைவுக் கட்டுப்பாடுகள்"</string>
<string name="controls_providers_title" msgid="8844124515157926071">"கட்டுப்பாடுகளைச் சேர்த்தல்"</string>
<string name="controls_providers_subtitle" msgid="8187768950110836569">"எந்த ஆப்ஸிலிருந்து கட்டுப்பாடுகளைச் சேர்க்க வேண்டும் என்பதைத் தேர்ந்தெடுங்கள்"</string>
- <!-- no translation found for controls_number_of_favorites (1057347832073807380) -->
+ <plurals name="controls_number_of_favorites" formatted="false" msgid="1057347832073807380">
+ <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="controls_favorite_default_title" msgid="967742178688938137">"கட்டுப்பாடுகள்"</string>
<string name="controls_favorite_subtitle" msgid="4049644994401173949">"விரைவு அணுகலுக்கான கட்டுப்பாடுகளைத் தேர்ந்தெடுங்கள்"</string>
- <!-- no translation found for controls_favorite_header_favorites (3118600046217493471) -->
- <skip />
- <!-- no translation found for controls_favorite_header_all (7507855973418969992) -->
+ <string name="controls_favorite_header_favorites" msgid="3118600046217493471">"பிடித்தவை"</string>
+ <string name="controls_favorite_header_all" msgid="7507855973418969992">"எல்லாம்"</string>
+ <string name="controls_favorite_load_error" msgid="2533215155804455348">"எல்லா கட்டுப்பாடுகளின் பட்டியலை ஏற்ற முடியவில்லை."</string>
+ <string name="controls_favorite_other_zone_header" msgid="9089613266575525252">"பிற"</string>
+ <!-- no translation found for controls_dialog_title (8806193219278278442) -->
<skip />
- <!-- no translation found for controls_favorite_load_error (2533215155804455348) -->
+ <!-- no translation found for controls_dialog_ok (7011816381344485651) -->
<skip />
- <!-- no translation found for controls_favorite_other_zone_header (9089613266575525252) -->
+ <!-- no translation found for controls_dialog_message (6292099631702047540) -->
<skip />
</resources>
diff --git a/packages/SystemUI/res/values-te/strings.xml b/packages/SystemUI/res/values-te/strings.xml
index dd8dcdfb77a1..2442eff4b07d 100644
--- a/packages/SystemUI/res/values-te/strings.xml
+++ b/packages/SystemUI/res/values-te/strings.xml
@@ -558,6 +558,8 @@
<string name="monitoring_description_app_personal_work" msgid="6175816356939166101">"మీ కార్యాలయ ప్రొఫైల్ <xliff:g id="ORGANIZATION">%1$s</xliff:g> నిర్వహణలో ఉంది. ఇమెయిల్‌లు, అనువర్తనాలు మరియు వెబ్‌సైట్‌లతో సహా మీ కార్యాలయ నెట్‌వర్క్ కార్యాచరణను పర్యవేక్షించగల <xliff:g id="APPLICATION_WORK">%2$s</xliff:g>కి ప్రొఫైల్ కనెక్ట్ చేయబడింది.\n\nమీ వ్యక్తిగత నెట్‌వర్క్ కార్యాచరణను పర్యవేక్షించగల <xliff:g id="APPLICATION_PERSONAL">%3$s</xliff:g>కి కూడా మీరు కనెక్ట్ చేయబడ్డారు."</string>
<string name="keyguard_indication_trust_unlocked" msgid="7395154975733744547">"TrustAgent ద్వారా అన్‌లాక్ చేయబడింది"</string>
<string name="keyguard_indication_trust_disabled" msgid="6820793704816727918">"మీరు మాన్యువల్‌గా అన్‌లాక్ చేస్తే మినహా పరికరం లాక్ చేయబడి ఉంటుంది"</string>
+ <!-- no translation found for keyguard_indication_trust_unlocked_plugged_in (2323452175329362855) -->
+ <skip />
<string name="hidden_notifications_title" msgid="1782412844777612795">"నోటిఫికేషన్‌లను వేగంగా పొందండి"</string>
<string name="hidden_notifications_text" msgid="5899627470450792578">"వీటిని మీరు అన్‌లాక్ చేయకముందే చూడండి"</string>
<string name="hidden_notifications_cancel" msgid="4805370226181001278">"వద్దు, ధన్యవాదాలు"</string>
@@ -979,12 +981,9 @@
<string name="bubble_accessibility_action_move_bottom_left" msgid="6339015902495504715">"దిగువ ఎడమవైపునకు తరలించు"</string>
<string name="bubble_accessibility_action_move_bottom_right" msgid="7471571700628346212">"దిగవు కుడివైపునకు జరుపు"</string>
<string name="bubble_dismiss_text" msgid="7071770411580452911">"విస్మరించు"</string>
- <!-- no translation found for bubbles_user_education_title (3385222165904578710) -->
- <skip />
- <!-- no translation found for bubbles_user_education_description (6663205638091146934) -->
- <skip />
- <!-- no translation found for bubbles_user_education_manage (1391639189507036423) -->
- <skip />
+ <string name="bubbles_user_education_title" msgid="3385222165904578710">"చాట్‌లను ముందుగా ఉంచండి"</string>
+ <string name="bubbles_user_education_description" msgid="6663205638091146934">"<xliff:g id="APP_NAME">%1$s</xliff:g> నుండి వచ్చే కొత్త చాట్‌లు బబుల్‌లుగా కనిపిస్తాయి. దానిని తెరవడానికి బబుల్‌ను ట్యాప్ చేయండి. దానిని తరలించడానికి లాగండి.\n\nబబుల్‌ను ట్యాప్ చేయండి"</string>
+ <string name="bubbles_user_education_manage" msgid="1391639189507036423">"ఈ యాప్ నుండి వచ్చే బబుల్‌లను ఆఫ్ చేయడానికి మేనేజ్ బటన్‌ను ట్యాప్ చేయండి"</string>
<string name="notification_content_system_nav_changed" msgid="5077913144844684544">"సిస్టమ్ నావిగేషన్ అప్‌డేట్ చేయబడింది. మార్పులు చేయడానికి, సెట్టింగ్‌లకు వెళ్లండి."</string>
<string name="notification_content_gesture_nav_available" msgid="4431460803004659888">"సిస్టమ్ నావిగేషన్‌ను అప్‌డేట్ చేయడానికి సెట్టింగ్‌లకు వెళ్లండి"</string>
<string name="inattentive_sleep_warning_title" msgid="3891371591713990373">"స్టాండ్‌బై"</string>
@@ -994,12 +993,20 @@
<string name="quick_controls_title" msgid="525285759614231333">"త్వరిత నియంత్రణలు"</string>
<string name="controls_providers_title" msgid="8844124515157926071">"నియంత్రణలను జోడించండి"</string>
<string name="controls_providers_subtitle" msgid="8187768950110836569">"దాని నుండి నియంత్రణలను జోడించేలా ఒక యాప్‌ను ఎంచుకోండి"</string>
- <!-- no translation found for controls_number_of_favorites (1057347832073807380) -->
+ <plurals name="controls_number_of_favorites" formatted="false" msgid="1057347832073807380">
+ <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="controls_favorite_default_title" msgid="967742178688938137">"నియంత్రణలు"</string>
<string name="controls_favorite_subtitle" msgid="4049644994401173949">"త్వరిత యాక్సెస్ కోసం నియంత్రణలను ఎంచుకోండి"</string>
<string name="controls_favorite_header_favorites" msgid="3118600046217493471">"ఇష్టమైనవి"</string>
<string name="controls_favorite_header_all" msgid="7507855973418969992">"అన్ని"</string>
<string name="controls_favorite_load_error" msgid="2533215155804455348">"అన్ని నియంత్రణలు గల జాబితాను లోడ్ చేయలేకపోయాము."</string>
- <!-- no translation found for controls_favorite_other_zone_header (9089613266575525252) -->
+ <string name="controls_favorite_other_zone_header" msgid="9089613266575525252">"ఇతరం"</string>
+ <!-- no translation found for controls_dialog_title (8806193219278278442) -->
+ <skip />
+ <!-- no translation found for controls_dialog_ok (7011816381344485651) -->
+ <skip />
+ <!-- no translation found for controls_dialog_message (6292099631702047540) -->
<skip />
</resources>
diff --git a/packages/SystemUI/res/values-television/integers.xml b/packages/SystemUI/res/values-television/integers.xml
new file mode 100644
index 000000000000..91e83ccbbe79
--- /dev/null
+++ b/packages/SystemUI/res/values-television/integers.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ ~ Copyright (C) 2020 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License
+ -->
+<resources>
+ <!-- The position of the volume dialog on the screen.
+ See com.android.systemui.volume.VolumeDialogImpl.
+ Value 81 corresponds to BOTTOM|CENTER_HORIZONTAL. -->
+ <integer name="volume_dialog_gravity">81</integer>
+</resources> \ No newline at end of file
diff --git a/packages/SystemUI/res/values-th/strings.xml b/packages/SystemUI/res/values-th/strings.xml
index d45b7dc0be4f..866eb59d6f03 100644
--- a/packages/SystemUI/res/values-th/strings.xml
+++ b/packages/SystemUI/res/values-th/strings.xml
@@ -558,6 +558,7 @@
<string name="monitoring_description_app_personal_work" msgid="6175816356939166101">"<xliff:g id="ORGANIZATION">%1$s</xliff:g> เป็นผู้จัดการโปรไฟล์งานของคุณ โปรไฟล์ดังกล่าวเชื่อมต่ออยู่กับ <xliff:g id="APPLICATION_WORK">%2$s</xliff:g> ซึ่งสามารถตรวจสอบกิจกรรมในเครือข่ายของคุณ รวมถึงอีเมล แอป และเว็บไซต์\n\nคุณยังเชื่อมต่ออยู่กับ <xliff:g id="APPLICATION_PERSONAL">%3$s</xliff:g> ด้วย ซึ่งสามารถตรวจสอบกิจกรรมในเครือข่ายส่วนตัวของคุณ"</string>
<string name="keyguard_indication_trust_unlocked" msgid="7395154975733744547">"ปลดล็อกไว้โดย TrustAgent"</string>
<string name="keyguard_indication_trust_disabled" msgid="6820793704816727918">"อุปกรณ์จะล็อกจนกว่าคุณจะปลดล็อกด้วยตนเอง"</string>
+ <string name="keyguard_indication_trust_unlocked_plugged_in" msgid="2323452175329362855">"<xliff:g id="KEYGUARD_INDICATION">%1$s</xliff:g>\n<xliff:g id="POWER_INDICATION">%2$s</xliff:g>"</string>
<string name="hidden_notifications_title" msgid="1782412844777612795">"รับการแจ้งเตือนเร็วขึ้น"</string>
<string name="hidden_notifications_text" msgid="5899627470450792578">"ดูก่อนปลดล็อก"</string>
<string name="hidden_notifications_cancel" msgid="4805370226181001278">"ไม่เป็นไร"</string>
@@ -979,12 +980,9 @@
<string name="bubble_accessibility_action_move_bottom_left" msgid="6339015902495504715">"ย้ายไปด้านซ้ายล่าง"</string>
<string name="bubble_accessibility_action_move_bottom_right" msgid="7471571700628346212">"ย้ายไปด้านขาวล่าง"</string>
<string name="bubble_dismiss_text" msgid="7071770411580452911">"ปิด"</string>
- <!-- no translation found for bubbles_user_education_title (3385222165904578710) -->
- <skip />
- <!-- no translation found for bubbles_user_education_description (6663205638091146934) -->
- <skip />
- <!-- no translation found for bubbles_user_education_manage (1391639189507036423) -->
- <skip />
+ <string name="bubbles_user_education_title" msgid="3385222165904578710">"เข้าถึงแชทได้ง่ายๆ"</string>
+ <string name="bubbles_user_education_description" msgid="6663205638091146934">"แชทใหม่จาก <xliff:g id="APP_NAME">%1$s</xliff:g> จะปรากฏเป็นบับเบิล แตะบับเบิลเพื่อเปิดแชท ลากเพื่อย้ายตำแหน่ง\n\nแตะบับเบิล"</string>
+ <string name="bubbles_user_education_manage" msgid="1391639189507036423">"แตะ \"จัดการ\" เพื่อปิดบับเบิลจากแอปนี้"</string>
<string name="notification_content_system_nav_changed" msgid="5077913144844684544">"อัปเดตการไปยังส่วนต่างๆ ของระบบแล้ว หากต้องการเปลี่ยนแปลง ให้ไปที่การตั้งค่า"</string>
<string name="notification_content_gesture_nav_available" msgid="4431460803004659888">"ไปที่การตั้งค่าเพื่ออัปเดตการไปยังส่วนต่างๆ ของระบบ"</string>
<string name="inattentive_sleep_warning_title" msgid="3891371591713990373">"สแตนด์บาย"</string>
@@ -1004,4 +1002,10 @@
<string name="controls_favorite_header_all" msgid="7507855973418969992">"ทั้งหมด"</string>
<string name="controls_favorite_load_error" msgid="2533215155804455348">"โหลดรายการตัวควบคุมทั้งหมดไม่ได้"</string>
<string name="controls_favorite_other_zone_header" msgid="9089613266575525252">"อื่นๆ"</string>
+ <!-- no translation found for controls_dialog_title (8806193219278278442) -->
+ <skip />
+ <!-- no translation found for controls_dialog_ok (7011816381344485651) -->
+ <skip />
+ <!-- no translation found for controls_dialog_message (6292099631702047540) -->
+ <skip />
</resources>
diff --git a/packages/SystemUI/res/values-tl/strings.xml b/packages/SystemUI/res/values-tl/strings.xml
index 7cecf13d448d..cdfe73269ff9 100644
--- a/packages/SystemUI/res/values-tl/strings.xml
+++ b/packages/SystemUI/res/values-tl/strings.xml
@@ -558,6 +558,7 @@
<string name="monitoring_description_app_personal_work" msgid="6175816356939166101">"Pinamamahalaan ng <xliff:g id="ORGANIZATION">%1$s</xliff:g> ang iyong profile sa trabaho. Nakakonekta ang profile sa <xliff:g id="APPLICATION_WORK">%2$s</xliff:g>, na maaaring sumubaybay sa aktibidad sa iyong network sa trabaho, kasama ang mga email, app, at website.\n\nNakakonekta ka rin sa <xliff:g id="APPLICATION_PERSONAL">%3$s</xliff:g>, na maaaring sumubaybay sa aktibidad sa iyong personal na network."</string>
<string name="keyguard_indication_trust_unlocked" msgid="7395154975733744547">"Pinanatiling naka-unlock ng TrustAgent"</string>
<string name="keyguard_indication_trust_disabled" msgid="6820793704816727918">"Mananatiling naka-lock ang device hanggang sa manual mong i-unlock"</string>
+ <string name="keyguard_indication_trust_unlocked_plugged_in" msgid="2323452175329362855">"<xliff:g id="KEYGUARD_INDICATION">%1$s</xliff:g>\n<xliff:g id="POWER_INDICATION">%2$s</xliff:g>"</string>
<string name="hidden_notifications_title" msgid="1782412844777612795">"Kunin ang notification nang mas mabilis"</string>
<string name="hidden_notifications_text" msgid="5899627470450792578">"Tingnan ang mga ito bago ka mag-unlock"</string>
<string name="hidden_notifications_cancel" msgid="4805370226181001278">"Hindi"</string>
@@ -979,12 +980,9 @@
<string name="bubble_accessibility_action_move_bottom_left" msgid="6339015902495504715">"Ilipat sa kaliwa sa ibaba"</string>
<string name="bubble_accessibility_action_move_bottom_right" msgid="7471571700628346212">"Ilipat sa kanan sa ibaba"</string>
<string name="bubble_dismiss_text" msgid="7071770411580452911">"I-dismiss"</string>
- <!-- no translation found for bubbles_user_education_title (3385222165904578710) -->
- <skip />
- <!-- no translation found for bubbles_user_education_description (6663205638091146934) -->
- <skip />
- <!-- no translation found for bubbles_user_education_manage (1391639189507036423) -->
- <skip />
+ <string name="bubbles_user_education_title" msgid="3385222165904578710">"Panatilihing nasa harap ang mga chat"</string>
+ <string name="bubbles_user_education_description" msgid="6663205638091146934">"Lalabas ang mga bagong chat mula sa <xliff:g id="APP_NAME">%1$s</xliff:g> bilang mga bubble. I-tap ang isang bubble para buksan ito. I-drag ito para ilipat ito.\n\nI-tap ang bubble"</string>
+ <string name="bubbles_user_education_manage" msgid="1391639189507036423">"I-tap ang Pamahalaan para i-off ang mga bubble mula sa app na ito"</string>
<string name="notification_content_system_nav_changed" msgid="5077913144844684544">"Na-update na ang pag-navigate ng system. Para gumawa ng mga pagbabago, pumunta sa Mga Setting."</string>
<string name="notification_content_gesture_nav_available" msgid="4431460803004659888">"Pumunta sa Mga Setting para i-update ang pag-navigate sa system"</string>
<string name="inattentive_sleep_warning_title" msgid="3891371591713990373">"Naka-standby"</string>
@@ -1004,4 +1002,10 @@
<string name="controls_favorite_header_all" msgid="7507855973418969992">"Lahat"</string>
<string name="controls_favorite_load_error" msgid="2533215155804455348">"Hindi ma-load ang listahan ng lahat ng control."</string>
<string name="controls_favorite_other_zone_header" msgid="9089613266575525252">"Iba pa"</string>
+ <!-- no translation found for controls_dialog_title (8806193219278278442) -->
+ <skip />
+ <!-- no translation found for controls_dialog_ok (7011816381344485651) -->
+ <skip />
+ <!-- no translation found for controls_dialog_message (6292099631702047540) -->
+ <skip />
</resources>
diff --git a/packages/SystemUI/res/values-tr/strings.xml b/packages/SystemUI/res/values-tr/strings.xml
index 150363e5a61c..8d2d98b762a3 100644
--- a/packages/SystemUI/res/values-tr/strings.xml
+++ b/packages/SystemUI/res/values-tr/strings.xml
@@ -558,6 +558,7 @@
<string name="monitoring_description_app_personal_work" msgid="6175816356939166101">"İş profiliniz <xliff:g id="ORGANIZATION">%1$s</xliff:g> tarafından yönetiliyor. Profil; e-postalar, uygulamalar ve web siteleri de dahil olmak üzere iş ağı etkinliğinizi izleyebilen <xliff:g id="APPLICATION_WORK">%2$s</xliff:g> uygulamasına bağlı.\n\nAyrıca, kişisel ağ etkinliğinizi izleyebilen <xliff:g id="APPLICATION_PERSONAL">%3$s</xliff:g> uygulamasına bağlısınız."</string>
<string name="keyguard_indication_trust_unlocked" msgid="7395154975733744547">"TrustAgent tarafından kilit açık tutuldu"</string>
<string name="keyguard_indication_trust_disabled" msgid="6820793704816727918">"Cihazınızın kilidini manuel olarak açmadıkça cihaz kilitli kalacak"</string>
+ <string name="keyguard_indication_trust_unlocked_plugged_in" msgid="2323452175329362855">"<xliff:g id="KEYGUARD_INDICATION">%1$s</xliff:g>\n<xliff:g id="POWER_INDICATION">%2$s</xliff:g>"</string>
<string name="hidden_notifications_title" msgid="1782412844777612795">"Bildirimleri daha hızlı alın"</string>
<string name="hidden_notifications_text" msgid="5899627470450792578">"Kilidi açmadan bildirimleri görün"</string>
<string name="hidden_notifications_cancel" msgid="4805370226181001278">"Hayır, teşekkürler"</string>
@@ -979,12 +980,9 @@
<string name="bubble_accessibility_action_move_bottom_left" msgid="6339015902495504715">"Sol alta taşı"</string>
<string name="bubble_accessibility_action_move_bottom_right" msgid="7471571700628346212">"Sağ alta taşı"</string>
<string name="bubble_dismiss_text" msgid="7071770411580452911">"Kapat"</string>
- <!-- no translation found for bubbles_user_education_title (3385222165904578710) -->
- <skip />
- <!-- no translation found for bubbles_user_education_description (6663205638091146934) -->
- <skip />
- <!-- no translation found for bubbles_user_education_manage (1391639189507036423) -->
- <skip />
+ <string name="bubbles_user_education_title" msgid="3385222165904578710">"Sohbetleri önde tutma"</string>
+ <string name="bubbles_user_education_description" msgid="6663205638091146934">"<xliff:g id="APP_NAME">%1$s</xliff:g> adlı kişi ile yeni sohbetler balon olarak görünür. Açmak için balona dokunun. Taşımak için sürükleyin.\n\nBalona dokunun"</string>
+ <string name="bubbles_user_education_manage" msgid="1391639189507036423">"Bu uygulamanın balonlarını kapatmak için Yönet\'e dokunun"</string>
<string name="notification_content_system_nav_changed" msgid="5077913144844684544">"Sistemde gezinme yöntemi güncellendi. Değişiklik yapmak için Ayarlar\'a gidin."</string>
<string name="notification_content_gesture_nav_available" msgid="4431460803004659888">"Sistemde gezinme yöntemini güncellemek için Ayarlar\'a gidin"</string>
<string name="inattentive_sleep_warning_title" msgid="3891371591713990373">"Beklemeye alınıyor"</string>
@@ -1004,4 +1002,10 @@
<string name="controls_favorite_header_all" msgid="7507855973418969992">"Tümü"</string>
<string name="controls_favorite_load_error" msgid="2533215155804455348">"Tüm kontrollerin listesi yüklenemedi."</string>
<string name="controls_favorite_other_zone_header" msgid="9089613266575525252">"Diğer"</string>
+ <!-- no translation found for controls_dialog_title (8806193219278278442) -->
+ <skip />
+ <!-- no translation found for controls_dialog_ok (7011816381344485651) -->
+ <skip />
+ <!-- no translation found for controls_dialog_message (6292099631702047540) -->
+ <skip />
</resources>
diff --git a/packages/SystemUI/res/values-uk/strings.xml b/packages/SystemUI/res/values-uk/strings.xml
index 347532decd39..c6bec40bf912 100644
--- a/packages/SystemUI/res/values-uk/strings.xml
+++ b/packages/SystemUI/res/values-uk/strings.xml
@@ -564,6 +564,7 @@
<string name="monitoring_description_app_personal_work" msgid="6175816356939166101">"Вашим робочим профілем керує адміністратор організації <xliff:g id="ORGANIZATION">%1$s</xliff:g>. Цей профіль під’єднано до додатка <xliff:g id="APPLICATION_WORK">%2$s</xliff:g>, який може відстежувати вашу активність у мережі, зокрема а електронній пошті, додатках і на веб-сайтах.\n\nВаш профіль також під’єднано до додатка <xliff:g id="APPLICATION_PERSONAL">%3$s</xliff:g>, який може відстежувати вашу особисту активність у мережі."</string>
<string name="keyguard_indication_trust_unlocked" msgid="7395154975733744547">"Розблоковує довірчий агент"</string>
<string name="keyguard_indication_trust_disabled" msgid="6820793704816727918">"Пристрій залишатиметься заблокованим, доки ви не розблокуєте його вручну"</string>
+ <string name="keyguard_indication_trust_unlocked_plugged_in" msgid="2323452175329362855">"<xliff:g id="KEYGUARD_INDICATION">%1$s</xliff:g>\n<xliff:g id="POWER_INDICATION">%2$s</xliff:g>"</string>
<string name="hidden_notifications_title" msgid="1782412844777612795">"Швидше отримуйте сповіщення"</string>
<string name="hidden_notifications_text" msgid="5899627470450792578">"Переглядайте сповіщення, перш ніж розблокувати екран"</string>
<string name="hidden_notifications_cancel" msgid="4805370226181001278">"Ні, дякую"</string>
@@ -989,12 +990,9 @@
<string name="bubble_accessibility_action_move_bottom_left" msgid="6339015902495504715">"Перемістити ліворуч униз"</string>
<string name="bubble_accessibility_action_move_bottom_right" msgid="7471571700628346212">"Перемістити праворуч униз"</string>
<string name="bubble_dismiss_text" msgid="7071770411580452911">"Закрити"</string>
- <!-- no translation found for bubbles_user_education_title (3385222165904578710) -->
- <skip />
- <!-- no translation found for bubbles_user_education_description (6663205638091146934) -->
- <skip />
- <!-- no translation found for bubbles_user_education_manage (1391639189507036423) -->
- <skip />
+ <string name="bubbles_user_education_title" msgid="3385222165904578710">"Чати завжди під рукою"</string>
+ <string name="bubbles_user_education_description" msgid="6663205638091146934">"Нові чати з додатка <xliff:g id="APP_NAME">%1$s</xliff:g> з\'являтимуться як спливаючі сповіщення. Щоб відкрити чат, натисніть сповіщення. Щоб перемістити сповіщення, потягніть його.\n\nНатисніть спливаюче сповіщення"</string>
+ <string name="bubbles_user_education_manage" msgid="1391639189507036423">"Натисніть \"Керувати\", щоб вимкнути спливаючі сповіщення для цього додатка"</string>
<string name="notification_content_system_nav_changed" msgid="5077913144844684544">"Навігацію в системі оновлено. Щоб внести зміни, перейдіть у налаштування."</string>
<string name="notification_content_gesture_nav_available" msgid="4431460803004659888">"Перейдіть у налаштування, щоб оновити навігацію в системі"</string>
<string name="inattentive_sleep_warning_title" msgid="3891371591713990373">"Режим очікування"</string>
@@ -1016,4 +1014,10 @@
<string name="controls_favorite_header_all" msgid="7507855973418969992">"Усі"</string>
<string name="controls_favorite_load_error" msgid="2533215155804455348">"Не вдалося завантажити список усіх елементів керування."</string>
<string name="controls_favorite_other_zone_header" msgid="9089613266575525252">"Інше"</string>
+ <!-- no translation found for controls_dialog_title (8806193219278278442) -->
+ <skip />
+ <!-- no translation found for controls_dialog_ok (7011816381344485651) -->
+ <skip />
+ <!-- no translation found for controls_dialog_message (6292099631702047540) -->
+ <skip />
</resources>
diff --git a/packages/SystemUI/res/values-ur/strings.xml b/packages/SystemUI/res/values-ur/strings.xml
index a1523bf2f22e..cc5f3c576a8a 100644
--- a/packages/SystemUI/res/values-ur/strings.xml
+++ b/packages/SystemUI/res/values-ur/strings.xml
@@ -558,6 +558,8 @@
<string name="monitoring_description_app_personal_work" msgid="6175816356939166101">"آپ کا دفتری پروفائل <xliff:g id="ORGANIZATION">%1$s</xliff:g> کے زیر انتظام ہے۔ پروفائل <xliff:g id="APPLICATION_WORK">%2$s</xliff:g> سے منسلک ہے جو ای میلز، ایپس اور ویب سائٹس سمیت آپ کے دفتری نیٹ ورک کی سرگرمی مانیٹر کر سکتی ہے۔\n\nآپ <xliff:g id="APPLICATION_PERSONAL">%3$s</xliff:g> سے بھی منسلک ہیں، جو آپ کے ذاتی نیٹ ورک کی سرگرمی مانیٹر کر سکتی ہے۔"</string>
<string name="keyguard_indication_trust_unlocked" msgid="7395154975733744547">"ٹرسٹ ایجنٹ نے غیر مقفل رکھا ہے"</string>
<string name="keyguard_indication_trust_disabled" msgid="6820793704816727918">"آلہ اس وقت تک مقفل رہے گا جب تک آپ دستی طور پر اسے غیر مقفل نہ کریں"</string>
+ <!-- no translation found for keyguard_indication_trust_unlocked_plugged_in (2323452175329362855) -->
+ <skip />
<string name="hidden_notifications_title" msgid="1782412844777612795">"تیزی سے اطلاعات حاصل کریں"</string>
<string name="hidden_notifications_text" msgid="5899627470450792578">"غیر مقفل کرنے سے پہلے انہیں دیکھیں"</string>
<string name="hidden_notifications_cancel" msgid="4805370226181001278">"نہیں شکریہ"</string>
@@ -979,12 +981,9 @@
<string name="bubble_accessibility_action_move_bottom_left" msgid="6339015902495504715">"نیچے بائیں جانب لے جائیں"</string>
<string name="bubble_accessibility_action_move_bottom_right" msgid="7471571700628346212">"نیچے دائیں جانب لے جائیں"</string>
<string name="bubble_dismiss_text" msgid="7071770411580452911">"برخاست کریں"</string>
- <!-- no translation found for bubbles_user_education_title (3385222165904578710) -->
- <skip />
- <!-- no translation found for bubbles_user_education_description (6663205638091146934) -->
- <skip />
- <!-- no translation found for bubbles_user_education_manage (1391639189507036423) -->
- <skip />
+ <string name="bubbles_user_education_title" msgid="3385222165904578710">"چیٹس سامنے رکھیں"</string>
+ <string name="bubbles_user_education_description" msgid="6663205638091146934">"<xliff:g id="APP_NAME">%1$s</xliff:g> کی نئی چیٹس بلبلوں کے طور پر ظاہر ہوں گی۔ اسے کھولنے کے لیے کسی بلبلہ کو تھپتھپائیں۔ اسے منتقل کرنے کے لیے گھسیٹیں۔\n\nبلبلہ کو تھپتھپائیں"</string>
+ <string name="bubbles_user_education_manage" msgid="1391639189507036423">"اس ایپ سے بلبلوں کو آف کرنے کے لیے نظم کریں پر تھپتھپائیں"</string>
<string name="notification_content_system_nav_changed" msgid="5077913144844684544">"سسٹم نیویگیشن اپ ڈیٹ کیا گیا۔ تبدیلیاں کرنے کے لیے، ترتیبات پر جائیں۔"</string>
<string name="notification_content_gesture_nav_available" msgid="4431460803004659888">"سسٹم نیویگیشن اپ ڈیٹ کرنے کے لیے ترتیبات پر جائیں"</string>
<string name="inattentive_sleep_warning_title" msgid="3891371591713990373">"اسٹینڈ بائی"</string>
@@ -1004,4 +1003,10 @@
<string name="controls_favorite_header_all" msgid="7507855973418969992">"تمام"</string>
<string name="controls_favorite_load_error" msgid="2533215155804455348">"تمام کنٹرولز کی فہرست لوڈ نہیں کی جا سکی۔"</string>
<string name="controls_favorite_other_zone_header" msgid="9089613266575525252">"دیگر"</string>
+ <!-- no translation found for controls_dialog_title (8806193219278278442) -->
+ <skip />
+ <!-- no translation found for controls_dialog_ok (7011816381344485651) -->
+ <skip />
+ <!-- no translation found for controls_dialog_message (6292099631702047540) -->
+ <skip />
</resources>
diff --git a/packages/SystemUI/res/values-uz/strings.xml b/packages/SystemUI/res/values-uz/strings.xml
index 7192a8ed82bf..6ceaeeb64c4c 100644
--- a/packages/SystemUI/res/values-uz/strings.xml
+++ b/packages/SystemUI/res/values-uz/strings.xml
@@ -558,6 +558,7 @@
<string name="monitoring_description_app_personal_work" msgid="6175816356939166101">"Ishchi profilingiz <xliff:g id="ORGANIZATION">%1$s</xliff:g> tomonidan boshqariladi. <xliff:g id="APPLICATION_WORK">%2$s</xliff:g> ilovasi ish tarmog‘idagi, jumladan, e-pochta, ilova va veb-saytlardagi xatti-harakatlaringizni kuzatishi mumkin.\n\nShuningdek, <xliff:g id="APPLICATION_PERSONAL">%3$s</xliff:g> ilovasi ham shaxsiy tarmoqdagi harakatlaringizni kuzatishi mumkin."</string>
<string name="keyguard_indication_trust_unlocked" msgid="7395154975733744547">"TrustAgent tomonidan ochilgan"</string>
<string name="keyguard_indication_trust_disabled" msgid="6820793704816727918">"Qurilma qo‘lda qulfdan chiqarilmaguncha qulflangan holatda qoladi"</string>
+ <string name="keyguard_indication_trust_unlocked_plugged_in" msgid="2323452175329362855">"<xliff:g id="KEYGUARD_INDICATION">%1$s</xliff:g>\n<xliff:g id="POWER_INDICATION">%2$s</xliff:g>"</string>
<string name="hidden_notifications_title" msgid="1782412844777612795">"Bildirishnomalarni tezroq oling"</string>
<string name="hidden_notifications_text" msgid="5899627470450792578">"Ularni qulfdan chiqarishdan oldin ko‘ring"</string>
<string name="hidden_notifications_cancel" msgid="4805370226181001278">"Kerak emas"</string>
@@ -979,12 +980,9 @@
<string name="bubble_accessibility_action_move_bottom_left" msgid="6339015902495504715">"Quyi chapga surish"</string>
<string name="bubble_accessibility_action_move_bottom_right" msgid="7471571700628346212">"Quyi oʻngga surish"</string>
<string name="bubble_dismiss_text" msgid="7071770411580452911">"Yopish"</string>
- <!-- no translation found for bubbles_user_education_title (3385222165904578710) -->
- <skip />
- <!-- no translation found for bubbles_user_education_description (6663205638091146934) -->
- <skip />
- <!-- no translation found for bubbles_user_education_manage (1391639189507036423) -->
- <skip />
+ <string name="bubbles_user_education_title" msgid="3385222165904578710">"Chatlar asosiy planda"</string>
+ <string name="bubbles_user_education_description" msgid="6663205638091146934">"<xliff:g id="APP_NAME">%1$s</xliff:g> ilovasidan yangi chatlar bulutchalar shaklida chiqadi. Uni ochish uchun bulutchani bosing. Uni surish uchun torting.\n\nBulutchani bosing"</string>
+ <string name="bubbles_user_education_manage" msgid="1391639189507036423">"Bu ilova bulutchalarini faolsizlantirish uchun Boshqarish tugmasini bosing"</string>
<string name="notification_content_system_nav_changed" msgid="5077913144844684544">"Tizim navigatsiyasi yangilandi. Buni Sozlamalar orqali oʻzgartirishingiz mumkin."</string>
<string name="notification_content_gesture_nav_available" msgid="4431460803004659888">"Tizim navigatsiyasini yangilash uchun Sozlamalarni oching"</string>
<string name="inattentive_sleep_warning_title" msgid="3891371591713990373">"Kutib turing"</string>
@@ -1004,4 +1002,10 @@
<string name="controls_favorite_header_all" msgid="7507855973418969992">"Hammasi"</string>
<string name="controls_favorite_load_error" msgid="2533215155804455348">"Boshqaruv elementlarining barchasi yuklanmadi."</string>
<string name="controls_favorite_other_zone_header" msgid="9089613266575525252">"Boshqa"</string>
+ <!-- no translation found for controls_dialog_title (8806193219278278442) -->
+ <skip />
+ <!-- no translation found for controls_dialog_ok (7011816381344485651) -->
+ <skip />
+ <!-- no translation found for controls_dialog_message (6292099631702047540) -->
+ <skip />
</resources>
diff --git a/packages/SystemUI/res/values-vi/strings.xml b/packages/SystemUI/res/values-vi/strings.xml
index a9dd01de118a..37f71c028f79 100644
--- a/packages/SystemUI/res/values-vi/strings.xml
+++ b/packages/SystemUI/res/values-vi/strings.xml
@@ -558,6 +558,7 @@
<string name="monitoring_description_app_personal_work" msgid="6175816356939166101">"Hồ sơ công việc của bạn do <xliff:g id="ORGANIZATION">%1$s</xliff:g> quản lý. Hồ sơ này được kết nối với <xliff:g id="APPLICATION_WORK">%2$s</xliff:g>, ứng dụng này có thể giám sát hoạt động mạng của bạn, bao gồm email, ứng dụng và trang web.\n\nBạn cũng đang kết nối với <xliff:g id="APPLICATION_PERSONAL">%3$s</xliff:g>, ứng dụng này có thể giám sát hoạt động mạng cá nhân của bạn."</string>
<string name="keyguard_indication_trust_unlocked" msgid="7395154975733744547">"Luôn được TrustAgent mở khóa"</string>
<string name="keyguard_indication_trust_disabled" msgid="6820793704816727918">"Thiết bị sẽ vẫn bị khóa cho tới khi bạn mở khóa theo cách thủ công"</string>
+ <string name="keyguard_indication_trust_unlocked_plugged_in" msgid="2323452175329362855">"<xliff:g id="KEYGUARD_INDICATION">%1$s</xliff:g>\n<xliff:g id="POWER_INDICATION">%2$s</xliff:g>"</string>
<string name="hidden_notifications_title" msgid="1782412844777612795">"Nhận thông báo nhanh hơn"</string>
<string name="hidden_notifications_text" msgid="5899627470450792578">"Xem thông báo trước khi bạn mở khóa"</string>
<string name="hidden_notifications_cancel" msgid="4805370226181001278">"Ko, cảm ơn"</string>
@@ -979,12 +980,9 @@
<string name="bubble_accessibility_action_move_bottom_left" msgid="6339015902495504715">"Chuyển tới dưới cùng bên trái"</string>
<string name="bubble_accessibility_action_move_bottom_right" msgid="7471571700628346212">"Chuyển tới dưới cùng bên phải"</string>
<string name="bubble_dismiss_text" msgid="7071770411580452911">"Loại bỏ"</string>
- <!-- no translation found for bubbles_user_education_title (3385222165904578710) -->
- <skip />
- <!-- no translation found for bubbles_user_education_description (6663205638091146934) -->
- <skip />
- <!-- no translation found for bubbles_user_education_manage (1391639189507036423) -->
- <skip />
+ <string name="bubbles_user_education_title" msgid="3385222165904578710">"Giữ cuộc trò chuyện trên nền trước"</string>
+ <string name="bubbles_user_education_description" msgid="6663205638091146934">"Các cuộc trò chuyện mới từ ứng dụng <xliff:g id="APP_NAME">%1$s</xliff:g> sẽ hiển thị dưới dạng bong bóng. Hãy nhấn vào bong bóng để mở. Kéo để di chuyển cuộc trò chuyện.\n\nNhấn vào bong bóng"</string>
+ <string name="bubbles_user_education_manage" msgid="1391639189507036423">"Nhấn vào nút Quản lý để tắt bong bóng từ ứng dụng này"</string>
<string name="notification_content_system_nav_changed" msgid="5077913144844684544">"Đã cập nhật chế độ di chuyển trên hệ thống. Để thay đổi, hãy chuyển đến phần Cài đặt."</string>
<string name="notification_content_gesture_nav_available" msgid="4431460803004659888">"Chuyển đến phần Cài đặt để cập nhật chế độ di chuyển trên hệ thống"</string>
<string name="inattentive_sleep_warning_title" msgid="3891371591713990373">"Chế độ chờ"</string>
@@ -1004,4 +1002,10 @@
<string name="controls_favorite_header_all" msgid="7507855973418969992">"Tất cả"</string>
<string name="controls_favorite_load_error" msgid="2533215155804455348">"Không thể tải danh sách tất cả tùy chọn điều khiển."</string>
<string name="controls_favorite_other_zone_header" msgid="9089613266575525252">"Khác"</string>
+ <!-- no translation found for controls_dialog_title (8806193219278278442) -->
+ <skip />
+ <!-- no translation found for controls_dialog_ok (7011816381344485651) -->
+ <skip />
+ <!-- no translation found for controls_dialog_message (6292099631702047540) -->
+ <skip />
</resources>
diff --git a/packages/SystemUI/res/values-zh-rCN/strings.xml b/packages/SystemUI/res/values-zh-rCN/strings.xml
index e80a624093a4..119767bea804 100644
--- a/packages/SystemUI/res/values-zh-rCN/strings.xml
+++ b/packages/SystemUI/res/values-zh-rCN/strings.xml
@@ -558,6 +558,7 @@
<string name="monitoring_description_app_personal_work" msgid="6175816356939166101">"您的工作资料由“<xliff:g id="ORGANIZATION">%1$s</xliff:g>”负责管理,且已连接到“<xliff:g id="APPLICATION_WORK">%2$s</xliff:g>”(该应用能够监控您的工作网络活动,其中包括收发电子邮件、使用应用和浏览网站)。\n\n此外,您还连接到了“<xliff:g id="APPLICATION_PERSONAL">%3$s</xliff:g>”(该应用能够监控您的个人网络活动)。"</string>
<string name="keyguard_indication_trust_unlocked" msgid="7395154975733744547">"由 TrustAgent 保持解锁状态"</string>
<string name="keyguard_indication_trust_disabled" msgid="6820793704816727918">"在您手动解锁之前,设备会保持锁定状态"</string>
+ <string name="keyguard_indication_trust_unlocked_plugged_in" msgid="2323452175329362855">"<xliff:g id="KEYGUARD_INDICATION">%1$s</xliff:g>\n<xliff:g id="POWER_INDICATION">%2$s</xliff:g>"</string>
<string name="hidden_notifications_title" msgid="1782412844777612795">"更快捷地查看通知"</string>
<string name="hidden_notifications_text" msgid="5899627470450792578">"无需解锁即可查看通知"</string>
<string name="hidden_notifications_cancel" msgid="4805370226181001278">"不用了"</string>
@@ -979,12 +980,9 @@
<string name="bubble_accessibility_action_move_bottom_left" msgid="6339015902495504715">"移至左下角"</string>
<string name="bubble_accessibility_action_move_bottom_right" msgid="7471571700628346212">"移至右下角"</string>
<string name="bubble_dismiss_text" msgid="7071770411580452911">"关闭"</string>
- <!-- no translation found for bubbles_user_education_title (3385222165904578710) -->
- <skip />
- <!-- no translation found for bubbles_user_education_description (6663205638091146934) -->
- <skip />
- <!-- no translation found for bubbles_user_education_manage (1391639189507036423) -->
- <skip />
+ <string name="bubbles_user_education_title" msgid="3385222165904578710">"让聊天在前台运行"</string>
+ <string name="bubbles_user_education_description" msgid="6663205638091146934">"来自<xliff:g id="APP_NAME">%1$s</xliff:g>的新聊天消息会显示为气泡。点按某个气泡可将其打开。拖动即可移动气泡。\n\n点按该气泡"</string>
+ <string name="bubbles_user_education_manage" msgid="1391639189507036423">"点按“管理”按钮,可关闭来自此应用的气泡"</string>
<string name="notification_content_system_nav_changed" msgid="5077913144844684544">"系统导航已更新。要进行更改,请转到“设置”。"</string>
<string name="notification_content_gesture_nav_available" msgid="4431460803004659888">"转到“设置”即可更新系统导航"</string>
<string name="inattentive_sleep_warning_title" msgid="3891371591713990373">"待机"</string>
@@ -1004,4 +1002,10 @@
<string name="controls_favorite_header_all" msgid="7507855973418969992">"全部"</string>
<string name="controls_favorite_load_error" msgid="2533215155804455348">"无法加载所有控件的列表。"</string>
<string name="controls_favorite_other_zone_header" msgid="9089613266575525252">"其他"</string>
+ <!-- no translation found for controls_dialog_title (8806193219278278442) -->
+ <skip />
+ <!-- no translation found for controls_dialog_ok (7011816381344485651) -->
+ <skip />
+ <!-- no translation found for controls_dialog_message (6292099631702047540) -->
+ <skip />
</resources>
diff --git a/packages/SystemUI/res/values-zh-rHK/strings.xml b/packages/SystemUI/res/values-zh-rHK/strings.xml
index 4787b9b39d20..8a3687fbe0aa 100644
--- a/packages/SystemUI/res/values-zh-rHK/strings.xml
+++ b/packages/SystemUI/res/values-zh-rHK/strings.xml
@@ -558,6 +558,7 @@
<string name="monitoring_description_app_personal_work" msgid="6175816356939166101">"您的工作設定檔由<xliff:g id="ORGANIZATION">%1$s</xliff:g>管理。設定檔已連結至「<xliff:g id="APPLICATION_WORK">%2$s</xliff:g>」,此應用程式可以監控您的工作網絡活動,包括電郵、應用程式和網站。\n\n您亦已連結至「<xliff:g id="APPLICATION_PERSONAL">%3$s</xliff:g>」,此應用程式可以監控您的個人網絡活動。"</string>
<string name="keyguard_indication_trust_unlocked" msgid="7395154975733744547">"由信任的代理保持解鎖狀態"</string>
<string name="keyguard_indication_trust_disabled" msgid="6820793704816727918">"裝置將保持上鎖,直到您手動解鎖"</string>
+ <string name="keyguard_indication_trust_unlocked_plugged_in" msgid="2323452175329362855">"<xliff:g id="KEYGUARD_INDICATION">%1$s</xliff:g>\n<xliff:g id="POWER_INDICATION">%2$s</xliff:g>"</string>
<string name="hidden_notifications_title" msgid="1782412844777612795">"更快取得通知"</string>
<string name="hidden_notifications_text" msgid="5899627470450792578">"解鎖前顯示"</string>
<string name="hidden_notifications_cancel" msgid="4805370226181001278">"不用了,謝謝"</string>
@@ -979,12 +980,9 @@
<string name="bubble_accessibility_action_move_bottom_left" msgid="6339015902495504715">"移去左下角"</string>
<string name="bubble_accessibility_action_move_bottom_right" msgid="7471571700628346212">"移去右下角"</string>
<string name="bubble_dismiss_text" msgid="7071770411580452911">"關閉"</string>
- <!-- no translation found for bubbles_user_education_title (3385222165904578710) -->
- <skip />
- <!-- no translation found for bubbles_user_education_description (6663205638091146934) -->
- <skip />
- <!-- no translation found for bubbles_user_education_manage (1391639189507036423) -->
- <skip />
+ <string name="bubbles_user_education_title" msgid="3385222165904578710">"保持即時通訊在最前面"</string>
+ <string name="bubbles_user_education_description" msgid="6663205638091146934">"「<xliff:g id="APP_NAME">%1$s</xliff:g>」的新即時通訊將以小視窗形式顯示。輕按小視窗即可開啟。拖曳即可移動。\n\n輕按小視窗"</string>
+ <string name="bubbles_user_education_manage" msgid="1391639189507036423">"輕按「管理」即可關閉此應用程式的小視窗"</string>
<string name="notification_content_system_nav_changed" msgid="5077913144844684544">"系統導覽已更新。如需變更,請前往「設定」。"</string>
<string name="notification_content_gesture_nav_available" msgid="4431460803004659888">"前往「設定」更新系統導覽"</string>
<string name="inattentive_sleep_warning_title" msgid="3891371591713990373">"待機"</string>
@@ -1004,4 +1002,10 @@
<string name="controls_favorite_header_all" msgid="7507855973418969992">"全部"</string>
<string name="controls_favorite_load_error" msgid="2533215155804455348">"無法載入完整控制項清單。"</string>
<string name="controls_favorite_other_zone_header" msgid="9089613266575525252">"其他"</string>
+ <!-- no translation found for controls_dialog_title (8806193219278278442) -->
+ <skip />
+ <!-- no translation found for controls_dialog_ok (7011816381344485651) -->
+ <skip />
+ <!-- no translation found for controls_dialog_message (6292099631702047540) -->
+ <skip />
</resources>
diff --git a/packages/SystemUI/res/values-zh-rTW/strings.xml b/packages/SystemUI/res/values-zh-rTW/strings.xml
index 3158a30cd59f..16ee9603fd8c 100644
--- a/packages/SystemUI/res/values-zh-rTW/strings.xml
+++ b/packages/SystemUI/res/values-zh-rTW/strings.xml
@@ -558,6 +558,7 @@
<string name="monitoring_description_app_personal_work" msgid="6175816356939166101">"你的工作資料夾是由「<xliff:g id="ORGANIZATION">%1$s</xliff:g>」所管理。由於該設定檔已連結至「<xliff:g id="APPLICATION_WORK">%2$s</xliff:g>」,因此你的網路活動 (包括收發電子郵件、使用應用程式和瀏覽網站) 可能會受到這個應用程式監控。\n\n此外,你還與「<xliff:g id="APPLICATION_PERSONAL">%3$s</xliff:g>」建立了連結,因此你的個人網路活動也可能會受到該應用程式監控。"</string>
<string name="keyguard_indication_trust_unlocked" msgid="7395154975733744547">"由 TrustAgent 維持解鎖狀態"</string>
<string name="keyguard_indication_trust_disabled" msgid="6820793704816727918">"在你手動解鎖前,裝置將保持鎖定狀態"</string>
+ <string name="keyguard_indication_trust_unlocked_plugged_in" msgid="2323452175329362855">"<xliff:g id="KEYGUARD_INDICATION">%1$s</xliff:g>\n<xliff:g id="POWER_INDICATION">%2$s</xliff:g>"</string>
<string name="hidden_notifications_title" msgid="1782412844777612795">"更快取得通知"</string>
<string name="hidden_notifications_text" msgid="5899627470450792578">"解鎖前顯示"</string>
<string name="hidden_notifications_cancel" msgid="4805370226181001278">"不用了,謝謝"</string>
@@ -979,12 +980,9 @@
<string name="bubble_accessibility_action_move_bottom_left" msgid="6339015902495504715">"移至左下方"</string>
<string name="bubble_accessibility_action_move_bottom_right" msgid="7471571700628346212">"移至右下方"</string>
<string name="bubble_dismiss_text" msgid="7071770411580452911">"關閉"</string>
- <!-- no translation found for bubbles_user_education_title (3385222165904578710) -->
- <skip />
- <!-- no translation found for bubbles_user_education_description (6663205638091146934) -->
- <skip />
- <!-- no translation found for bubbles_user_education_manage (1391639189507036423) -->
- <skip />
+ <string name="bubbles_user_education_title" msgid="3385222165904578710">"讓即時通訊繼續在前景執行"</string>
+ <string name="bubbles_user_education_description" msgid="6663205638091146934">"系統會以泡泡形式顯示來自「<xliff:g id="APP_NAME">%1$s</xliff:g>」的新即時通訊。輕觸泡泡即可開啟,拖曳則可移動泡泡。\n\n輕觸泡泡"</string>
+ <string name="bubbles_user_education_manage" msgid="1391639189507036423">"輕觸 [管理] 即可關閉來自這個應用程式的泡泡"</string>
<string name="notification_content_system_nav_changed" msgid="5077913144844684544">"系統操作機制已更新。如要進行變更,請前往「設定」。"</string>
<string name="notification_content_gesture_nav_available" msgid="4431460803004659888">"請前往「設定」更新系統操作機制"</string>
<string name="inattentive_sleep_warning_title" msgid="3891371591713990373">"待機"</string>
@@ -1004,4 +1002,10 @@
<string name="controls_favorite_header_all" msgid="7507855973418969992">"全部"</string>
<string name="controls_favorite_load_error" msgid="2533215155804455348">"無法載入完整的控制項清單。"</string>
<string name="controls_favorite_other_zone_header" msgid="9089613266575525252">"其他"</string>
+ <!-- no translation found for controls_dialog_title (8806193219278278442) -->
+ <skip />
+ <!-- no translation found for controls_dialog_ok (7011816381344485651) -->
+ <skip />
+ <!-- no translation found for controls_dialog_message (6292099631702047540) -->
+ <skip />
</resources>
diff --git a/packages/SystemUI/res/values-zu/strings.xml b/packages/SystemUI/res/values-zu/strings.xml
index e94a8ab27f97..7e2b53e8c1bf 100644
--- a/packages/SystemUI/res/values-zu/strings.xml
+++ b/packages/SystemUI/res/values-zu/strings.xml
@@ -558,6 +558,7 @@
<string name="monitoring_description_app_personal_work" msgid="6175816356939166101">"Iphrofayela yakho yomsebenzi iphethwe i-<xliff:g id="ORGANIZATION">%1$s</xliff:g>. Iphrofayela ixhumeke ku-<xliff:g id="APPLICATION_WORK">%2$s</xliff:g>, engaqapha umsebenzi wakho wenethiwekhi, ofaka ama-imeyili, izinhlelo zokusebenza, namawebhusayithi.\n\nFuthi uxhumeke ku-<xliff:g id="APPLICATION_PERSONAL">%3$s</xliff:g>, engaqapha umsebenzi wakho siqu wenethiwekhi."</string>
<string name="keyguard_indication_trust_unlocked" msgid="7395154975733744547">"Igcinwa ivuliwe ngo-TrustAgent"</string>
<string name="keyguard_indication_trust_disabled" msgid="6820793704816727918">"Idivayisi izohlala ikhiyekile uze uyivule ngokwenza"</string>
+ <string name="keyguard_indication_trust_unlocked_plugged_in" msgid="2323452175329362855">"<xliff:g id="KEYGUARD_INDICATION">%1$s</xliff:g>\n<xliff:g id="POWER_INDICATION">%2$s</xliff:g>"</string>
<string name="hidden_notifications_title" msgid="1782412844777612795">"Thola izaziso ngokushesha"</string>
<string name="hidden_notifications_text" msgid="5899627470450792578">"Ibone ngaphambi kokuthi uyivule"</string>
<string name="hidden_notifications_cancel" msgid="4805370226181001278">"Cha ngiyabonga"</string>
@@ -979,12 +980,9 @@
<string name="bubble_accessibility_action_move_bottom_left" msgid="6339015902495504715">"Hambisa inkinobho ngakwesokunxele"</string>
<string name="bubble_accessibility_action_move_bottom_right" msgid="7471571700628346212">"Hambisa inkinobho ngakwesokudla"</string>
<string name="bubble_dismiss_text" msgid="7071770411580452911">"Cashisa"</string>
- <!-- no translation found for bubbles_user_education_title (3385222165904578710) -->
- <skip />
- <!-- no translation found for bubbles_user_education_description (6663205638091146934) -->
- <skip />
- <!-- no translation found for bubbles_user_education_manage (1391639189507036423) -->
- <skip />
+ <string name="bubbles_user_education_title" msgid="3385222165904578710">"Gcina izingxoxo ziphambili"</string>
+ <string name="bubbles_user_education_description" msgid="6663205638091146934">"Izingxoxo ezintsha kusuka ku-<xliff:g id="APP_NAME">%1$s</xliff:g>zizovela njengamabhamuza. Thepha ibhamuza ukuze ulivule. Hudula ukuze ulisuse.\n\nThepha ibhamuza"</string>
+ <string name="bubbles_user_education_manage" msgid="1391639189507036423">"Thepha okuthi Phatha ukuvala amabhamuza kusuka kulolu hlelo lokusebenza"</string>
<string name="notification_content_system_nav_changed" msgid="5077913144844684544">"Ukuzulazula kwesistimu kubuyekeziwe. Ukuze wenze ushintsho, hamba kokuthi Izilungiselelo."</string>
<string name="notification_content_gesture_nav_available" msgid="4431460803004659888">"Hamba kuzilungiselelo ukuze ubuyekeze ukuzulazula kwesistimu"</string>
<string name="inattentive_sleep_warning_title" msgid="3891371591713990373">"Ilindile"</string>
@@ -1004,4 +1002,10 @@
<string name="controls_favorite_header_all" msgid="7507855973418969992">"Konke"</string>
<string name="controls_favorite_load_error" msgid="2533215155804455348">"Uhlu lwazo zonke izilawuli alilayishekanga."</string>
<string name="controls_favorite_other_zone_header" msgid="9089613266575525252">"Okunye"</string>
+ <!-- no translation found for controls_dialog_title (8806193219278278442) -->
+ <skip />
+ <!-- no translation found for controls_dialog_ok (7011816381344485651) -->
+ <skip />
+ <!-- no translation found for controls_dialog_message (6292099631702047540) -->
+ <skip />
</resources>
diff --git a/packages/SystemUI/res/values/colors.xml b/packages/SystemUI/res/values/colors.xml
index 73e49cee6a8b..80c1ac8e3496 100644
--- a/packages/SystemUI/res/values/colors.xml
+++ b/packages/SystemUI/res/values/colors.xml
@@ -219,8 +219,10 @@
<color name="magnification_border_color">#FF9900</color>
<!-- controls -->
- <color name="control_primary_text">@*android:color/foreground_material_dark</color>
- <color name="control_secondary_text">@*android:color/dim_foreground_dark</color>
- <color name="control_default_foreground">@*android:color/foreground_material_dark</color>
- <color name="control_default_background">@*android:color/background_floating_material_dark</color>
+ <color name="control_primary_text">@color/GM2_grey_100</color>
+ <color name="control_secondary_text">@color/GM2_grey_500</color>
+ <color name="control_default_foreground">@color/GM2_grey_500</color>
+ <color name="control_default_background">@color/GM2_grey_900</color>
+ <color name="control_list_popup_background">@*android:color/background_floating_material_dark</color>
+ <color name="control_spinner_dropdown">@*android:color/foreground_material_dark</color>
</resources>
diff --git a/packages/SystemUI/res/values/config.xml b/packages/SystemUI/res/values/config.xml
index 27ffcee2a2dc..d16082915207 100644
--- a/packages/SystemUI/res/values/config.xml
+++ b/packages/SystemUI/res/values/config.xml
@@ -506,4 +506,21 @@
<item>@*android:string/status_bar_headset</item>
</string-array>
+ <!-- A path similar to frameworks/base/core/res/res/values/config.xml
+ config_mainBuiltInDisplayCutout that describes a path larger than the exact path of a display
+ cutout. If present as well as config_enableDisplayCutoutProtection is set to true, then
+ SystemUI will draw this "protection path" instead of the display cutout path that is normally
+ used for anti-aliasing.
+
+ This path will only be drawn when the front-facing camera turns on, otherwise the main
+ DisplayCutout path will be rendered
+ -->
+ <string translatable="false" name="config_frontBuiltInDisplayCutoutProtection"></string>
+
+ <!-- ID for the camera that needs extra protection -->
+ <string translatable="false" name="config_protectedCameraId"></string>
+
+ <!-- Flag to turn on the rendering of the above path or not -->
+ <bool name="config_enableDisplayCutoutProtection">false</bool>
+
</resources>
diff --git a/packages/SystemUI/res/values/dimens.xml b/packages/SystemUI/res/values/dimens.xml
index 4f803bccfb25..291db65da225 100644
--- a/packages/SystemUI/res/values/dimens.xml
+++ b/packages/SystemUI/res/values/dimens.xml
@@ -983,6 +983,9 @@
<!-- The touchable/draggable edge size for PIP resize. -->
<dimen name="pip_resize_edge_size">30dp</dimen>
+ <!-- The corner radius for PiP window. -->
+ <dimen name="pip_corner_radius">8dp</dimen>
+
<dimen name="default_gear_space">18dp</dimen>
<dimen name="cell_overlay_padding">18dp</dimen>
@@ -1183,6 +1186,9 @@
<dimen name="bubble_dismiss_target_padding_x">40dp</dimen>
<dimen name="bubble_dismiss_target_padding_y">20dp</dimen>
+ <dimen name="dismiss_circle_size">52dp</dimen>
+ <dimen name="dismiss_target_x_size">24dp</dimen>
+
<!-- Bubbles user education views -->
<dimen name="bubbles_manage_education_width">160dp</dimen>
<!-- The inset from the top bound of the manage button to place the user education. -->
@@ -1216,11 +1222,18 @@
<dimen name="magnifier_up_down_controls_height">40dp</dimen>
<!-- Home Controls -->
+ <dimen name="controls_header_side_margin">32dp</dimen>
+ <dimen name="controls_header_app_icon_size">40dp</dimen>
+ <dimen name="controls_list_side_margin">16dp</dimen>
+ <dimen name="controls_top_margin">44dp</dimen>
+ <dimen name="control_header_text_size">22sp</dimen>
+ <dimen name="control_text_size">14sp</dimen>
<dimen name="control_spacing">4dp</dimen>
<dimen name="control_list_divider">1dp</dimen>
- <dimen name="control_corner_radius">15dp</dimen>
- <dimen name="control_height">100dp</dimen>
- <dimen name="control_padding">15dp</dimen>
+ <dimen name="control_corner_radius">12dp</dimen>
+ <dimen name="control_height">106dp</dimen>
+ <dimen name="control_padding">12dp</dimen>
+ <dimen name="control_padding_adjustment">4dp</dimen>
<dimen name="control_status_normal">12sp</dimen>
<dimen name="control_status_expanded">18sp</dimen>
<dimen name="control_base_item_margin">2dp</dimen>
@@ -1236,12 +1249,17 @@
<dimen name="controls_app_icon_size">32dp</dimen>
<dimen name="controls_app_icon_frame_side_padding">8dp</dimen>
<dimen name="controls_app_icon_frame_top_padding">4dp</dimen>
+ <dimen name="controls_app_icon_frame_bottom_padding">@dimen/controls_app_icon_frame_top_padding</dimen>
<dimen name="controls_app_bottom_margin">8dp</dimen>
<dimen name="controls_app_text_padding">8dp</dimen>
<dimen name="controls_app_divider_height">2dp</dimen>
<dimen name="controls_app_divider_side_margin">32dp</dimen>
<dimen name="controls_card_margin">2dp</dimen>
+ <item name="control_card_elevation" type="dimen" format="float">15</item>
+
+ <dimen name="controls_dialog_padding">8dp</dimen>
+ <dimen name="controls_dialog_control_width">200dp</dimen>
<!-- Screen Record -->
<dimen name="screenrecord_dialog_padding">18dp</dimen>
diff --git a/packages/SystemUI/res/values/integers.xml b/packages/SystemUI/res/values/integers.xml
index 4171cd974132..f35f3513d530 100644
--- a/packages/SystemUI/res/values/integers.xml
+++ b/packages/SystemUI/res/values/integers.xml
@@ -40,4 +40,8 @@
<integer name="magnification_default_scale">2</integer>
+ <!-- The position of the volume dialog on the screen.
+ See com.android.systemui.volume.VolumeDialogImpl.
+ Value 21 corresponds to RIGHT|CENTER_VERTICAL. -->
+ <integer name="volume_dialog_gravity">21</integer>
</resources> \ No newline at end of file
diff --git a/packages/SystemUI/res/values/strings.xml b/packages/SystemUI/res/values/strings.xml
index ecbe59872a21..caf22fe16beb 100644
--- a/packages/SystemUI/res/values/strings.xml
+++ b/packages/SystemUI/res/values/strings.xml
@@ -2640,5 +2640,17 @@
<!-- Controls management controls screen header for Other zone [CHAR LIMIT=60] -->
<string name="controls_favorite_other_zone_header">Other</string>
-
+ <!-- Controls dialog title [CHAR LIMIT=30] -->
+ <string name="controls_dialog_title">Add to Quick Controls</string>
+ <!-- Controls dialog add to favorites [CHAR LIMIT=30] -->
+ <string name="controls_dialog_ok">Add to favorites</string>
+ <!-- Controls dialog message [CHAR LIMIT=NONE] -->
+ <string name="controls_dialog_message"><xliff:g id="app" example="System UI">%s</xliff:g> suggested this control to add to your favorites.</string>
+
+ <!-- Controls PIN entry dialog, switch to alphanumeric keyboard [CHAR LIMIT=100] -->
+ <string name="controls_pin_use_alphanumeric">PIN contains letters or symbols</string>
+ <!-- Controls PIN entry dialog, title [CHAR LIMIT=30] -->
+ <string name="controls_pin_verify">Verify device PIN</string>
+ <!-- Controls PIN entry dialog, text hint [CHAR LIMIT=30] -->
+ <string name="controls_pin_instructions">Enter PIN</string>
</resources>
diff --git a/packages/SystemUI/res/values/styles.xml b/packages/SystemUI/res/values/styles.xml
index 83c507095534..125dd8f1d60c 100644
--- a/packages/SystemUI/res/values/styles.xml
+++ b/packages/SystemUI/res/values/styles.xml
@@ -656,27 +656,48 @@
<item name="android:fontFamily">@*android:string/config_bodyFontFamily</item>
</style>
- <style name="Control.Spinner.Header" parent="@*android:style/Widget.DeviceDefault.Spinner.DropDown">
- <item name="android:textSize">25sp</item>
+ <style name="Control" />
+
+ <style name="Control.Spinner">
+ <item name="android:textSize">@dimen/control_header_text_size</item>
+ <item name="android:fontFamily">@*android:string/config_headlineFontFamilyMedium</item>
+ <item name="android:singleLine">true</item>
+ <item name="android:ellipsize">end</item>
+ </style>
+
+ <style name="Control.Spinner.Header">
+ <item name="android:background">@drawable/control_spinner_background</item>
<item name="android:textColor">@color/control_primary_text</item>
- <item name="android:fontFamily">@*android:string/config_headlineFontFamily</item>
+ </style>
+
+ <style name="Control.Spinner.Item">
+ <item name="android:textColor">@color/control_secondary_text</item>
</style>
<style name="TextAppearance.Control.Status">
- <item name="android:textSize">12sp</item>
+ <item name="android:fontFamily">@*android:string/config_headlineFontFamilyMedium</item>
+ <item name="android:textSize">@dimen/control_text_size</item>
<item name="android:textColor">@color/control_primary_text</item>
</style>
<style name="TextAppearance.Control.Title">
- <item name="android:textSize">14sp</item>
+ <item name="android:fontFamily">@*android:string/config_headlineFontFamilyMedium</item>
+ <item name="android:textSize">@dimen/control_text_size</item>
+ <item name="android:lineSpacingExtra">6sp</item>
<item name="android:textColor">@color/control_primary_text</item>
</style>
<style name="TextAppearance.Control.Subtitle">
- <item name="android:textSize">12sp</item>
+ <item name="android:fontFamily">@*android:string/config_headlineFontFamilyMedium</item>
+ <item name="android:textSize">@dimen/control_text_size</item>
<item name="android:textColor">@color/control_secondary_text</item>
</style>
- <style name="Control.ListPopupWindow" parent="@android:style/Widget.ListPopupWindow">
+ <style name="Control.ListPopupWindow" parent="@*android:style/Widget.DeviceDefault.ListPopupWindow">
<item name="android:overlapAnchor">true</item>
+
+ <!-- used to override dark/light theming -->
+ <item name="*android:colorPopupBackground">@color/control_list_popup_background</item>
</style>
-
+
+ <style name="Theme.ControlsRequestDialog" parent="@style/Theme.SystemUI.MediaProjectionAlertDialog"/>
+
</resources>
diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/system/InputConsumerController.java b/packages/SystemUI/shared/src/com/android/systemui/shared/system/InputConsumerController.java
index e554dcd36100..ebed1fcdb48b 100644
--- a/packages/SystemUI/shared/src/com/android/systemui/shared/system/InputConsumerController.java
+++ b/packages/SystemUI/shared/src/com/android/systemui/shared/system/InputConsumerController.java
@@ -64,7 +64,7 @@ public class InputConsumerController {
private final class InputEventReceiver extends BatchedInputEventReceiver {
public InputEventReceiver(InputChannel inputChannel, Looper looper) {
- super(inputChannel, looper, Choreographer.getSfInstance());
+ super(inputChannel, looper, Choreographer.getInstance());
}
@Override
diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/system/QuickStepContract.java b/packages/SystemUI/shared/src/com/android/systemui/shared/system/QuickStepContract.java
index 386fe531c93d..4885ade23f6a 100644
--- a/packages/SystemUI/shared/src/com/android/systemui/shared/system/QuickStepContract.java
+++ b/packages/SystemUI/shared/src/com/android/systemui/shared/system/QuickStepContract.java
@@ -49,15 +49,6 @@ public class QuickStepContract {
public static final String NAV_BAR_MODE_GESTURAL_OVERLAY =
WindowManagerPolicyConstants.NAV_BAR_MODE_GESTURAL_OVERLAY;
- // Action sent by a system app to switch to gesture nav
- public static final String ACTION_ENABLE_GESTURE_NAV =
- "com.android.systemui.ENABLE_GESTURE_NAV";
- // Action for the intent to receive the result
- public static final String ACTION_ENABLE_GESTURE_NAV_RESULT =
- "com.android.systemui.action.ENABLE_GESTURE_NAV_RESULT";
- // Extra containing the pending intent to receive the result
- public static final String EXTRA_RESULT_INTENT = "com.android.systemui.EXTRA_RESULT_INTENT";
-
// Overview is disabled, either because the device is in lock task mode, or because the device
// policy has disabled the feature
public static final int SYSUI_STATE_SCREEN_PINNING = 1 << 0;
diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/system/RemoteAnimationTargetCompat.java b/packages/SystemUI/shared/src/com/android/systemui/shared/system/RemoteAnimationTargetCompat.java
index ca88f13932ad..aed7c216433b 100644
--- a/packages/SystemUI/shared/src/com/android/systemui/shared/system/RemoteAnimationTargetCompat.java
+++ b/packages/SystemUI/shared/src/com/android/systemui/shared/system/RemoteAnimationTargetCompat.java
@@ -44,7 +44,9 @@ public class RemoteAnimationTargetCompat {
public final Rect clipRect;
public final int prefixOrderIndex;
public final Point position;
+ public final Rect localBounds;
public final Rect sourceContainerBounds;
+ public final Rect screenSpaceBounds;
public final boolean isNotInRecents;
public final Rect contentInsets;
@@ -57,7 +59,9 @@ public class RemoteAnimationTargetCompat {
isTranslucent = app.isTranslucent;
clipRect = app.clipRect;
position = app.position;
+ localBounds = app.localBounds;
sourceContainerBounds = app.sourceContainerBounds;
+ screenSpaceBounds = app.screenSpaceBounds;
prefixOrderIndex = app.prefixOrderIndex;
isNotInRecents = app.isNotInRecents;
contentInsets = app.contentInsets;
diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/system/SurfaceViewRequestReceiver.java b/packages/SystemUI/shared/src/com/android/systemui/shared/system/SurfaceViewRequestReceiver.java
new file mode 100644
index 000000000000..d33c653f2cb7
--- /dev/null
+++ b/packages/SystemUI/shared/src/com/android/systemui/shared/system/SurfaceViewRequestReceiver.java
@@ -0,0 +1,96 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.shared.system;
+
+import android.content.Context;
+import android.graphics.PixelFormat;
+import android.os.Bundle;
+import android.os.IBinder;
+import android.util.Size;
+import android.view.SurfaceControl;
+import android.view.SurfaceControlViewHost;
+import android.view.View;
+import android.view.WindowManager;
+import android.view.WindowlessWindowManager;
+
+/**
+ * A generic receiver that specifically handles SurfaceView request created by {@link
+ * com.android.systemui.shared.system.SurfaceViewRequestUtils}.
+ */
+public class SurfaceViewRequestReceiver {
+
+ private final int mOpacity;
+ private SurfaceControlViewHost mSurfaceControlViewHost;
+
+ public SurfaceViewRequestReceiver() {
+ this(PixelFormat.TRANSPARENT);
+ }
+
+ public SurfaceViewRequestReceiver(int opacity) {
+ mOpacity = opacity;
+ }
+
+ /** See {@link #onReceive(Context, Bundle, View, Size)}. */
+ public void onReceive(Context context, Bundle bundle, View view) {
+ onReceive(context, bundle, view, null);
+ }
+
+ /**
+ * Called whenever a surface view request is received.
+ * @param view the view rendering content, on the receiver end of the surface request.
+ * @param viewSize when {@param viewSize} is not specified, we will use the surface control size
+ * to attach the view to the window.
+ */
+ public void onReceive(Context context, Bundle bundle, View view, Size viewSize) {
+ if (mSurfaceControlViewHost != null) {
+ mSurfaceControlViewHost.die();
+ }
+ SurfaceControl surfaceControl = SurfaceViewRequestUtils.getSurfaceControl(bundle);
+ if (surfaceControl != null) {
+ if (viewSize == null) {
+ viewSize = new Size(surfaceControl.getWidth(), surfaceControl.getHeight());
+ }
+
+ IBinder hostToken = SurfaceViewRequestUtils.getHostToken(bundle);
+
+ WindowlessWindowManager windowlessWindowManager =
+ new WindowlessWindowManager(context.getResources().getConfiguration(),
+ surfaceControl, hostToken);
+ mSurfaceControlViewHost = new SurfaceControlViewHost(context,
+ context.getDisplayNoVerify(), windowlessWindowManager);
+ WindowManager.LayoutParams layoutParams =
+ new WindowManager.LayoutParams(
+ viewSize.getWidth(),
+ viewSize.getHeight(),
+ WindowManager.LayoutParams.TYPE_APPLICATION,
+ WindowManager.LayoutParams.FLAG_HARDWARE_ACCELERATED,
+ mOpacity);
+
+ // This aspect scales the view to fit in the surface and centers it
+ final float scale = Math.min(surfaceControl.getWidth() / (float) viewSize.getWidth(),
+ surfaceControl.getHeight() / (float) viewSize.getHeight());
+ view.setScaleX(scale);
+ view.setScaleY(scale);
+ view.setPivotX(0);
+ view.setPivotY(0);
+ view.setTranslationX((surfaceControl.getWidth() - scale * viewSize.getWidth()) / 2);
+ view.setTranslationY((surfaceControl.getHeight() - scale * viewSize.getHeight()) / 2);
+
+ mSurfaceControlViewHost.addView(view, layoutParams);
+ }
+ }
+}
diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/system/SurfaceViewRequestUtils.java b/packages/SystemUI/shared/src/com/android/systemui/shared/system/SurfaceViewRequestUtils.java
new file mode 100644
index 000000000000..4409276f8c27
--- /dev/null
+++ b/packages/SystemUI/shared/src/com/android/systemui/shared/system/SurfaceViewRequestUtils.java
@@ -0,0 +1,55 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.shared.system;
+
+import android.annotation.Nullable;
+import android.os.Bundle;
+import android.os.IBinder;
+import android.view.SurfaceControl;
+import android.view.SurfaceView;
+
+/** Util class that wraps a SurfaceView request into a bundle. */
+public class SurfaceViewRequestUtils {
+ private static final String KEY_HOST_TOKEN = "host_token";
+ private static final String KEY_SURFACE_CONTROL = "surface_control";
+
+ /** Creates a SurfaceView based bundle that stores the input host token and surface control. */
+ public static Bundle createSurfaceBundle(SurfaceView surfaceView) {
+ Bundle bundle = new Bundle();
+ bundle.putBinder(KEY_HOST_TOKEN, surfaceView.getHostToken());
+ bundle.putParcelable(KEY_SURFACE_CONTROL, surfaceView.getSurfaceControl());
+ return bundle;
+ }
+
+ /**
+ * Retrieves the SurfaceControl from a bundle created by
+ * {@link #createSurfaceBundle(SurfaceView)}.
+ **/
+ public static SurfaceControl getSurfaceControl(Bundle bundle) {
+ return bundle.getParcelable(KEY_SURFACE_CONTROL);
+ }
+
+ /**
+ * Retrieves the input token from a bundle created by
+ * {@link #createSurfaceBundle(SurfaceView)}.
+ **/
+ public static @Nullable IBinder getHostToken(Bundle bundle) {
+ return bundle.getBinder(KEY_HOST_TOKEN);
+ }
+
+ private SurfaceViewRequestUtils() {}
+}
diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/system/UniversalSmartspaceUtils.java b/packages/SystemUI/shared/src/com/android/systemui/shared/system/UniversalSmartspaceUtils.java
index 871cae3b4f8d..359d36939b31 100644
--- a/packages/SystemUI/shared/src/com/android/systemui/shared/system/UniversalSmartspaceUtils.java
+++ b/packages/SystemUI/shared/src/com/android/systemui/shared/system/UniversalSmartspaceUtils.java
@@ -18,50 +18,27 @@ package com.android.systemui.shared.system;
import android.content.Intent;
import android.os.Bundle;
-import android.os.IBinder;
-import android.view.SurfaceControl;
import android.view.SurfaceView;
/** Utility class that is shared between SysUI and Launcher for Universal Smartspace features. */
public final class UniversalSmartspaceUtils {
public static final String ACTION_REQUEST_SMARTSPACE_VIEW =
"com.android.systemui.REQUEST_SMARTSPACE_VIEW";
+ public static final String INTENT_BUNDLE_KEY = "bundle_key";
private static final String SYSUI_PACKAGE = "com.android.systemui";
- private static final String INTENT_KEY_INPUT_BUNDLE = "input_bundle";
- private static final String BUNDLE_KEY_INPUT_TOKEN = "input_token";
- private static final String INTENT_KEY_SURFACE_CONTROL = "surface_control";
/** Creates an intent to request that sysui draws the Smartspace to the SurfaceView. */
public static Intent createRequestSmartspaceIntent(SurfaceView surfaceView) {
Intent intent = new Intent(ACTION_REQUEST_SMARTSPACE_VIEW);
- Bundle inputBundle = new Bundle();
- inputBundle.putBinder(BUNDLE_KEY_INPUT_TOKEN, surfaceView.getHostToken());
+ Bundle bundle = SurfaceViewRequestUtils.createSurfaceBundle(surfaceView);
return intent
- .putExtra(INTENT_KEY_SURFACE_CONTROL, surfaceView.getSurfaceControl())
- .putExtra(INTENT_KEY_INPUT_BUNDLE, inputBundle)
+ .putExtra(INTENT_BUNDLE_KEY, bundle)
.setPackage(SYSUI_PACKAGE)
.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY
| Intent.FLAG_RECEIVER_FOREGROUND);
}
- /**
- * Retrieves the SurfaceControl from an Intent created by
- * {@link #createRequestSmartspaceIntent(SurfaceView)}.
- **/
- public static SurfaceControl getSurfaceControl(Intent intent) {
- return intent.getParcelableExtra(INTENT_KEY_SURFACE_CONTROL);
- }
-
- /**
- * Retrieves the input token from an Intent created by
- * {@link #createRequestSmartspaceIntent(SurfaceView)}.
- **/
- public static IBinder getInputToken(Intent intent) {
- Bundle inputBundle = intent.getBundleExtra(INTENT_KEY_INPUT_BUNDLE);
- return inputBundle == null ? null : inputBundle.getBinder(BUNDLE_KEY_INPUT_TOKEN);
- }
-
private UniversalSmartspaceUtils() {}
}
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardStatusView.java b/packages/SystemUI/src/com/android/keyguard/KeyguardStatusView.java
index 241f96e19e38..a181ce4b000a 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardStatusView.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardStatusView.java
@@ -24,9 +24,7 @@ import android.content.Intent;
import android.content.IntentFilter;
import android.content.res.Resources;
import android.graphics.Color;
-import android.graphics.PixelFormat;
import android.os.Handler;
-import android.os.IBinder;
import android.os.RemoteException;
import android.os.UserHandle;
import android.text.TextUtils;
@@ -35,11 +33,7 @@ import android.util.AttributeSet;
import android.util.Log;
import android.util.Slog;
import android.util.TypedValue;
-import android.view.SurfaceControl;
-import android.view.SurfaceControlViewHost;
import android.view.View;
-import android.view.WindowManager;
-import android.view.WindowlessWindowManager;
import android.widget.GridLayout;
import android.widget.LinearLayout;
import android.widget.TextView;
@@ -49,6 +43,7 @@ import androidx.core.graphics.ColorUtils;
import com.android.internal.widget.LockPatternUtils;
import com.android.systemui.Dependency;
import com.android.systemui.R;
+import com.android.systemui.shared.system.SurfaceViewRequestReceiver;
import com.android.systemui.shared.system.UniversalSmartspaceUtils;
import com.android.systemui.statusbar.policy.ConfigurationController;
@@ -86,7 +81,6 @@ public class KeyguardStatusView extends GridLayout implements
private int mIconTopMargin;
private int mIconTopMarginWithHeader;
private boolean mShowingHeader;
- private SurfaceControlViewHost mUniversalSmartspaceViewHost;
private KeyguardUpdateMonitorCallback mInfoCallback = new KeyguardUpdateMonitorCallback() {
@@ -133,37 +127,20 @@ public class KeyguardStatusView extends GridLayout implements
}
};
- private BroadcastReceiver mUniversalSmartspaceBroadcastReceiver = new BroadcastReceiver() {
+ private final BroadcastReceiver mUniversalSmartspaceBroadcastReceiver =
+ new BroadcastReceiver() {
+ private final SurfaceViewRequestReceiver mReceiver = new SurfaceViewRequestReceiver();
+
@Override
public void onReceive(Context context, Intent i) {
// TODO(b/148159743): Restrict to Pixel Launcher.
if (UniversalSmartspaceUtils.ACTION_REQUEST_SMARTSPACE_VIEW.equals(i.getAction())) {
- if (mUniversalSmartspaceViewHost != null) {
- mUniversalSmartspaceViewHost.die();
- }
- SurfaceControl surfaceControl = UniversalSmartspaceUtils.getSurfaceControl(i);
- if (surfaceControl != null) {
- IBinder input = UniversalSmartspaceUtils.getInputToken(i);
-
- WindowlessWindowManager windowlessWindowManager =
- new WindowlessWindowManager(context.getResources().getConfiguration(),
- surfaceControl, input);
- mUniversalSmartspaceViewHost = new SurfaceControlViewHost(context,
- context.getDisplayNoVerify(), windowlessWindowManager);
- WindowManager.LayoutParams layoutParams =
- new WindowManager.LayoutParams(
- surfaceControl.getWidth(),
- surfaceControl.getHeight(),
- WindowManager.LayoutParams.TYPE_APPLICATION,
- 0,
- PixelFormat.TRANSPARENT);
-
- mUniversalSmartspaceViewHost.addView(
- inflate(context, R.layout.keyguard_status_area, null), layoutParams);
- }
+ mReceiver.onReceive(context,
+ i.getBundleExtra(UniversalSmartspaceUtils.INTENT_BUNDLE_KEY),
+ inflate(mContext, R.layout.keyguard_status_area, null));
}
}
- };;
+ };
public KeyguardStatusView(Context context) {
this(context, null, 0);
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java b/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java
index 6a6255f616a3..4508fc74e884 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java
@@ -23,7 +23,6 @@ import static android.content.Intent.ACTION_USER_STOPPED;
import static android.content.Intent.ACTION_USER_UNLOCKED;
import static android.os.BatteryManager.BATTERY_STATUS_UNKNOWN;
import static android.telephony.PhoneStateListener.LISTEN_ACTIVE_DATA_SUBSCRIPTION_ID_CHANGE;
-import static android.telephony.TelephonyManager.MODEM_COUNT_DUAL_MODEM;
import static com.android.internal.widget.LockPatternUtils.StrongAuthTracker.STRONG_AUTH_REQUIRED_AFTER_BOOT;
import static com.android.internal.widget.LockPatternUtils.StrongAuthTracker.STRONG_AUTH_REQUIRED_AFTER_DPM_LOCK_NOW;
@@ -455,7 +454,7 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener, Dumpab
*/
public List<SubscriptionInfo> getFilteredSubscriptionInfo(boolean forceReload) {
List<SubscriptionInfo> subscriptions = getSubscriptionInfo(false);
- if (subscriptions.size() == MODEM_COUNT_DUAL_MODEM) {
+ if (subscriptions.size() == 2) {
SubscriptionInfo info1 = subscriptions.get(0);
SubscriptionInfo info2 = subscriptions.get(1);
if (info1.getGroupUuid() != null && info1.getGroupUuid().equals(info2.getGroupUuid())) {
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardViewController.java b/packages/SystemUI/src/com/android/keyguard/KeyguardViewController.java
new file mode 100644
index 000000000000..fc29f5cddb26
--- /dev/null
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardViewController.java
@@ -0,0 +1,174 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.keyguard;
+
+import android.os.Bundle;
+import android.view.View;
+import android.view.ViewGroup;
+import android.view.ViewRootImpl;
+
+import com.android.systemui.keyguard.DismissCallbackRegistry;
+import com.android.systemui.keyguard.KeyguardViewMediator;
+import com.android.systemui.plugins.FalsingManager;
+import com.android.systemui.statusbar.phone.BiometricUnlockController;
+import com.android.systemui.statusbar.phone.KeyguardBypassController;
+import com.android.systemui.statusbar.phone.NotificationPanelViewController;
+import com.android.systemui.statusbar.phone.StatusBar;
+
+/**
+ * Interface to control Keyguard View. It should be implemented by KeyguardViewManagers, which
+ * should, in turn, be injected into {@link KeyguardViewMediator}.
+ */
+public interface KeyguardViewController {
+ /**
+ * Shows Keyguard.
+ * @param options
+ */
+ void show(Bundle options);
+
+ /**
+ * Hides Keyguard with the fade-out animation as configured by the parameters provided.
+ *
+ * @param startTime
+ * @param fadeoutDuration
+ */
+ void hide(long startTime, long fadeoutDuration);
+
+ /**
+ * Resets the state of Keyguard View.
+ * @param hideBouncerWhenShowing
+ */
+ void reset(boolean hideBouncerWhenShowing);
+
+ /**
+ * Called when the device started going to sleep.
+ */
+ void onStartedGoingToSleep();
+
+ /**
+ * Called when the device has finished going to sleep.
+ */
+ void onFinishedGoingToSleep();
+
+ /**
+ * Called when the device started waking up.
+ */
+ void onStartedWakingUp();
+
+ /**
+ * Called when the device started turning on.
+ */
+ void onScreenTurningOn();
+
+ /**
+ * Called when the device has finished turning on.
+ */
+ void onScreenTurnedOn();
+
+ /**
+ * Sets whether the Keyguard needs input.
+ * @param needsInput
+ */
+ void setNeedsInput(boolean needsInput);
+
+ /**
+ * Called when cancel button in bouncer is pressed.
+ */
+ void onCancelClicked();
+
+ /**
+ * Sets whether the keyguard is occluded by another window.
+ *
+ * @param occluded
+ * @param animate
+ */
+ void setOccluded(boolean occluded, boolean animate);
+
+ /**
+ * @return Whether the keyguard is showing
+ */
+ boolean isShowing();
+
+ /**
+ * Dismisses the keyguard by going to the next screen or making it gone.
+ */
+ void dismissAndCollapse();
+
+ /**
+ * Notifies that Keyguard is just about to go away.
+ */
+ void keyguardGoingAway();
+
+ /**
+ * @return Whether window animation for unlock should be disabled.
+ */
+ boolean shouldDisableWindowAnimationsForUnlock();
+
+ /**
+ * @return Whether the keyguard is going to notification shade.
+ */
+ boolean isGoingToNotificationShade();
+
+ /**
+ * @return Whether subtle animation should be used for unlocking the device.
+ */
+ boolean isUnlockWithWallpaper();
+
+ /**
+ * @return Whether subtle animation should be used for unlocking the device.
+ */
+ boolean shouldSubtleWindowAnimationsForUnlock();
+
+ /**
+ * Starts the animation before we dismiss Keyguard, i.e. an disappearing animation on the
+ * security view of the bouncer.
+ *
+ * @param finishRunnable the runnable to be run after the animation finished, or {@code null} if
+ * no action should be run
+ */
+ void startPreHideAnimation(Runnable finishRunnable);
+
+ /**
+ * @return the ViewRootImpl of the View where the Keyguard is mounted.
+ */
+ ViewRootImpl getViewRootImpl();
+
+ // TODO: Deprecate registerStatusBar in KeyguardViewController interface. It is currently
+ // only used for testing purposes in StatusBarKeyguardViewManager, and it prevents us from
+ // achieving complete abstraction away from where the Keyguard View is mounted.
+
+ /**
+ * Registers the StatusBar to which this Keyguard View is mounted.
+ *
+ * @param statusBar
+ * @param container
+ * @param notificationPanelViewController
+ * @param biometricUnlockController
+ * @param dismissCallbackRegistry
+ * @param lockIconContainer
+ * @param notificationContainer
+ * @param bypassController
+ * @param falsingManager
+ */
+ void registerStatusBar(StatusBar statusBar,
+ ViewGroup container,
+ NotificationPanelViewController notificationPanelViewController,
+ BiometricUnlockController biometricUnlockController,
+ DismissCallbackRegistry dismissCallbackRegistry,
+ ViewGroup lockIconContainer, View notificationContainer,
+ KeyguardBypassController bypassController, FalsingManager falsingManager);
+}
diff --git a/packages/SystemUI/src/com/android/systemui/CameraAvailabilityListener.kt b/packages/SystemUI/src/com/android/systemui/CameraAvailabilityListener.kt
new file mode 100644
index 000000000000..284074e76ae2
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/CameraAvailabilityListener.kt
@@ -0,0 +1,138 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License
+ */
+
+package com.android.systemui
+
+import android.content.Context
+import android.graphics.Path
+import android.graphics.Rect
+import android.graphics.RectF
+import android.hardware.camera2.CameraManager
+import android.util.PathParser
+import java.util.concurrent.Executor
+
+import kotlin.math.roundToInt
+
+const val TAG = "CameraAvailabilityListener"
+
+/**
+ * Listens for usage of the Camera and controls the ScreenDecorations transition to show extra
+ * protection around a display cutout based on config_frontBuiltInDisplayCutoutProtection and
+ * config_enableDisplayCutoutProtection
+ */
+class CameraAvailabilityListener(
+ private val cameraManager: CameraManager,
+ private val cutoutProtectionPath: Path,
+ private val targetCameraId: String,
+ private val executor: Executor
+) {
+ private var cutoutBounds = Rect()
+ private val listeners = mutableListOf<CameraTransitionCallback>()
+ private val availabilityCallback: CameraManager.AvailabilityCallback =
+ object : CameraManager.AvailabilityCallback() {
+ override fun onCameraAvailable(cameraId: String) {
+ if (targetCameraId == cameraId) {
+ notifyCameraInactive()
+ }
+ }
+
+ override fun onCameraUnavailable(cameraId: String) {
+ if (targetCameraId == cameraId) {
+ notifyCameraActive()
+ }
+ }
+ }
+
+ init {
+ val computed = RectF()
+ cutoutProtectionPath.computeBounds(computed, false /* unused */)
+ cutoutBounds.set(
+ computed.left.roundToInt(),
+ computed.top.roundToInt(),
+ computed.right.roundToInt(),
+ computed.bottom.roundToInt())
+ }
+
+ /**
+ * Start listening for availability events, and maybe notify listeners
+ *
+ * @return true if we started listening
+ */
+ fun startListening() {
+ registerCameraListener()
+ }
+
+ fun stop() {
+ unregisterCameraListener()
+ }
+
+ fun addTransitionCallback(callback: CameraTransitionCallback) {
+ listeners.add(callback)
+ }
+
+ fun removeTransitionCallback(callback: CameraTransitionCallback) {
+ listeners.remove(callback)
+ }
+
+ private fun registerCameraListener() {
+ cameraManager.registerAvailabilityCallback(executor, availabilityCallback)
+ }
+
+ private fun unregisterCameraListener() {
+ cameraManager.unregisterAvailabilityCallback(availabilityCallback)
+ }
+
+ private fun notifyCameraActive() {
+ listeners.forEach { it.onApplyCameraProtection(cutoutProtectionPath, cutoutBounds) }
+ }
+
+ private fun notifyCameraInactive() {
+ listeners.forEach { it.onHideCameraProtection() }
+ }
+
+ /**
+ * Callbacks to tell a listener that a relevant camera turned on and off.
+ */
+ interface CameraTransitionCallback {
+ fun onApplyCameraProtection(protectionPath: Path, bounds: Rect)
+ fun onHideCameraProtection()
+ }
+
+ companion object Factory {
+ fun build(context: Context, executor: Executor): CameraAvailabilityListener {
+ val manager = context
+ .getSystemService(Context.CAMERA_SERVICE) as CameraManager
+ val res = context.resources
+ val pathString = res.getString(R.string.config_frontBuiltInDisplayCutoutProtection)
+ val cameraId = res.getString(R.string.config_protectedCameraId)
+
+ return CameraAvailabilityListener(
+ manager, pathFromString(pathString), cameraId, executor)
+ }
+
+ private fun pathFromString(pathString: String): Path {
+ val spec = pathString.trim()
+ val p: Path
+ try {
+ p = PathParser.createPathFromPathData(spec)
+ } catch (e: Throwable) {
+ throw IllegalArgumentException("Invalid protection path", e)
+ }
+
+ return p
+ }
+ }
+} \ No newline at end of file
diff --git a/packages/SystemUI/src/com/android/systemui/HardwareUiLayout.java b/packages/SystemUI/src/com/android/systemui/HardwareUiLayout.java
deleted file mode 100644
index ad2e0024065f..000000000000
--- a/packages/SystemUI/src/com/android/systemui/HardwareUiLayout.java
+++ /dev/null
@@ -1,570 +0,0 @@
-/*
- * Copyright (C) 2017 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file
- * except in compliance with the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software distributed under the
- * License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied. See the License for the specific language governing
- * permissions and limitations under the License.
- */
-
-package com.android.systemui;
-
-import static com.android.systemui.util.leak.RotationUtils.ROTATION_LANDSCAPE;
-import static com.android.systemui.util.leak.RotationUtils.ROTATION_NONE;
-import static com.android.systemui.util.leak.RotationUtils.ROTATION_SEASCAPE;
-
-import android.animation.Animator;
-import android.animation.AnimatorListenerAdapter;
-import android.animation.AnimatorSet;
-import android.animation.ObjectAnimator;
-import android.content.Context;
-import android.provider.Settings;
-import android.util.AttributeSet;
-import android.view.Gravity;
-import android.view.View;
-import android.view.ViewGroup;
-import android.view.ViewOutlineProvider;
-import android.view.ViewTreeObserver;
-import android.widget.LinearLayout;
-
-import com.android.systemui.tuner.TunerService;
-import com.android.systemui.tuner.TunerService.Tunable;
-import com.android.systemui.util.leak.RotationUtils;
-
-/**
- * Layout for placing two containers at a specific physical position on the device, relative to the
- * device's hardware, regardless of screen rotation.
- */
-public class HardwareUiLayout extends MultiListLayout implements Tunable {
-
- private static final String EDGE_BLEED = "sysui_hwui_edge_bleed";
- private static final String ROUNDED_DIVIDER = "sysui_hwui_rounded_divider";
- private final int[] mTmp2 = new int[2];
- private ViewGroup mList;
- private ViewGroup mSeparatedView;
- private int mOldHeight;
- private boolean mAnimating;
- private AnimatorSet mAnimation;
- private View mDivision;
- private HardwareBgDrawable mListBackground;
- private HardwareBgDrawable mSeparatedViewBackground;
- private Animator mAnimator;
- private boolean mCollapse;
- private int mEndPoint;
- private boolean mEdgeBleed;
- private boolean mRoundedDivider;
- private boolean mRotatedBackground;
- private boolean mSwapOrientation = true;
-
- public HardwareUiLayout(Context context, AttributeSet attrs) {
- super(context, attrs);
- // Manually re-initialize mRotation to portrait-mode, since this view must always
- // be constructed in portrait mode and rotated into the correct initial position.
- mRotation = ROTATION_NONE;
- updateSettings();
- }
-
- @Override
- protected ViewGroup getSeparatedView() {
- return findViewById(com.android.systemui.R.id.separated_button);
- }
-
- @Override
- protected ViewGroup getListView() {
- return findViewById(android.R.id.list);
- }
-
- @Override
- protected void onAttachedToWindow() {
- super.onAttachedToWindow();
- updateSettings();
- Dependency.get(TunerService.class).addTunable(this, EDGE_BLEED, ROUNDED_DIVIDER);
- getViewTreeObserver().addOnComputeInternalInsetsListener(mInsetsListener);
- }
-
- @Override
- protected void onDetachedFromWindow() {
- super.onDetachedFromWindow();
- getViewTreeObserver().removeOnComputeInternalInsetsListener(mInsetsListener);
- Dependency.get(TunerService.class).removeTunable(this);
- }
-
- @Override
- public void onTuningChanged(String key, String newValue) {
- updateSettings();
- }
-
- private void updateSettings() {
- mEdgeBleed = Settings.Secure.getInt(getContext().getContentResolver(),
- EDGE_BLEED, 0) != 0;
- mRoundedDivider = Settings.Secure.getInt(getContext().getContentResolver(),
- ROUNDED_DIVIDER, 0) != 0;
- updateEdgeMargin(mEdgeBleed ? 0 : getEdgePadding());
- mListBackground = new HardwareBgDrawable(mRoundedDivider, !mEdgeBleed, getContext());
- mSeparatedViewBackground = new HardwareBgDrawable(mRoundedDivider, !mEdgeBleed,
- getContext());
- if (mList != null) {
- mList.setBackground(mListBackground);
- mSeparatedView.setBackground(mSeparatedViewBackground);
- requestLayout();
- }
- }
-
- private void updateEdgeMargin(int edge) {
- if (mList != null) {
- MarginLayoutParams params = (MarginLayoutParams) mList.getLayoutParams();
- if (mRotation == ROTATION_LANDSCAPE) {
- params.topMargin = edge;
- } else if (mRotation == ROTATION_SEASCAPE) {
- params.bottomMargin = edge;
- } else {
- params.rightMargin = edge;
- }
- mList.setLayoutParams(params);
- }
-
- if (mSeparatedView != null) {
- MarginLayoutParams params = (MarginLayoutParams) mSeparatedView.getLayoutParams();
- if (mRotation == ROTATION_LANDSCAPE) {
- params.topMargin = edge;
- } else if (mRotation == ROTATION_SEASCAPE) {
- params.bottomMargin = edge;
- } else {
- params.rightMargin = edge;
- }
- mSeparatedView.setLayoutParams(params);
- }
- }
-
- private int getEdgePadding() {
- return getContext().getResources().getDimensionPixelSize(R.dimen.edge_margin);
- }
-
- @Override
- protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
- super.onMeasure(widthMeasureSpec, heightMeasureSpec);
- if (mList == null) {
- if (getChildCount() != 0) {
- mList = getListView();
- mList.setBackground(mListBackground);
- mSeparatedView = getSeparatedView();
- mSeparatedView.setBackground(mSeparatedViewBackground);
- updateEdgeMargin(mEdgeBleed ? 0 : getEdgePadding());
- mOldHeight = mList.getMeasuredHeight();
-
- // Must be called to initialize view rotation correctly.
- // Requires LayoutParams, hence why this isn't called during the constructor.
- updateRotation();
- } else {
- return;
- }
- }
- int newHeight = mList.getMeasuredHeight();
- if (newHeight != mOldHeight) {
- animateChild(mOldHeight, newHeight);
- }
-
- post(() -> updatePaddingAndGravityIfTooTall());
- post(() -> updatePosition());
- }
-
- public void setSwapOrientation(boolean swapOrientation) {
- mSwapOrientation = swapOrientation;
- }
-
- private void updateRotation() {
- int rotation = RotationUtils.getRotation(getContext());
- if (rotation != mRotation) {
- rotate(mRotation, rotation);
- mRotation = rotation;
- }
- }
-
- /**
- * Requires LayoutParams to be set to work correctly, and therefore must be run after after
- * the HardwareUILayout has been added to the view hierarchy.
- */
- protected void rotate(int from, int to) {
- super.rotate(from, to);
- if (from != ROTATION_NONE && to != ROTATION_NONE) {
- // Rather than handling this confusing case, just do 2 rotations.
- rotate(from, ROTATION_NONE);
- rotate(ROTATION_NONE, to);
- return;
- }
- if (from == ROTATION_LANDSCAPE || to == ROTATION_SEASCAPE) {
- rotateRight();
- } else {
- rotateLeft();
- }
- if (mAdapter.hasSeparatedItems()) {
- if (from == ROTATION_SEASCAPE || to == ROTATION_SEASCAPE) {
- // Separated view has top margin, so seascape separated view need special rotation,
- // not a full left or right rotation.
- swapLeftAndTop(mSeparatedView);
- } else if (from == ROTATION_LANDSCAPE) {
- rotateRight(mSeparatedView);
- } else {
- rotateLeft(mSeparatedView);
- }
- }
- if (to != ROTATION_NONE) {
- if (mList instanceof LinearLayout) {
- mRotatedBackground = true;
- mListBackground.setRotatedBackground(true);
- mSeparatedViewBackground.setRotatedBackground(true);
- LinearLayout linearLayout = (LinearLayout) mList;
- if (mSwapOrientation) {
- linearLayout.setOrientation(LinearLayout.HORIZONTAL);
- setOrientation(LinearLayout.HORIZONTAL);
- }
- swapDimens(mList);
- swapDimens(mSeparatedView);
- }
- } else {
- if (mList instanceof LinearLayout) {
- mRotatedBackground = false;
- mListBackground.setRotatedBackground(false);
- mSeparatedViewBackground.setRotatedBackground(false);
- LinearLayout linearLayout = (LinearLayout) mList;
- if (mSwapOrientation) {
- linearLayout.setOrientation(LinearLayout.VERTICAL);
- setOrientation(LinearLayout.VERTICAL);
- }
- swapDimens(mList);
- swapDimens(mSeparatedView);
- }
- }
- }
-
- @Override
- public void onUpdateList() {
- super.onUpdateList();
-
- for (int i = 0; i < mAdapter.getCount(); i++) {
- ViewGroup parent;
- boolean separated = mAdapter.shouldBeSeparated(i);
- if (separated) {
- parent = getSeparatedView();
- } else {
- parent = getListView();
- }
- View v = mAdapter.getView(i, null, parent);
- parent.addView(v);
- }
- }
-
- private void rotateRight() {
- rotateRight(this);
- rotateRight(mList);
- swapDimens(this);
-
- LayoutParams p = (LayoutParams) mList.getLayoutParams();
- p.gravity = rotateGravityRight(p.gravity);
- mList.setLayoutParams(p);
-
- LayoutParams separatedViewLayoutParams = (LayoutParams) mSeparatedView.getLayoutParams();
- separatedViewLayoutParams.gravity = rotateGravityRight(separatedViewLayoutParams.gravity);
- mSeparatedView.setLayoutParams(separatedViewLayoutParams);
-
- setGravity(rotateGravityRight(getGravity()));
- }
-
- private void swapDimens(View v) {
- ViewGroup.LayoutParams params = v.getLayoutParams();
- int h = params.width;
- params.width = params.height;
- params.height = h;
- v.setLayoutParams(params);
- }
-
- private int rotateGravityRight(int gravity) {
- int retGravity = 0;
- int layoutDirection = getLayoutDirection();
- final int absoluteGravity = Gravity.getAbsoluteGravity(gravity, layoutDirection);
- final int verticalGravity = gravity & Gravity.VERTICAL_GRAVITY_MASK;
-
- switch (absoluteGravity & Gravity.HORIZONTAL_GRAVITY_MASK) {
- case Gravity.CENTER_HORIZONTAL:
- retGravity |= Gravity.CENTER_VERTICAL;
- break;
- case Gravity.RIGHT:
- retGravity |= Gravity.BOTTOM;
- break;
- case Gravity.LEFT:
- default:
- retGravity |= Gravity.TOP;
- break;
- }
-
- switch (verticalGravity) {
- case Gravity.CENTER_VERTICAL:
- retGravity |= Gravity.CENTER_HORIZONTAL;
- break;
- case Gravity.BOTTOM:
- retGravity |= Gravity.LEFT;
- break;
- case Gravity.TOP:
- default:
- retGravity |= Gravity.RIGHT;
- break;
- }
- return retGravity;
- }
-
- private void rotateLeft() {
- rotateLeft(this);
- rotateLeft(mList);
- swapDimens(this);
-
- LayoutParams p = (LayoutParams) mList.getLayoutParams();
- p.gravity = rotateGravityLeft(p.gravity);
- mList.setLayoutParams(p);
-
- LayoutParams separatedViewLayoutParams = (LayoutParams) mSeparatedView.getLayoutParams();
- separatedViewLayoutParams.gravity = rotateGravityLeft(separatedViewLayoutParams.gravity);
- mSeparatedView.setLayoutParams(separatedViewLayoutParams);
-
- setGravity(rotateGravityLeft(getGravity()));
- }
-
- private int rotateGravityLeft(int gravity) {
- if (gravity == -1) {
- gravity = Gravity.TOP | Gravity.START;
- }
- int retGravity = 0;
- int layoutDirection = getLayoutDirection();
- final int absoluteGravity = Gravity.getAbsoluteGravity(gravity, layoutDirection);
- final int verticalGravity = gravity & Gravity.VERTICAL_GRAVITY_MASK;
-
- switch (absoluteGravity & Gravity.HORIZONTAL_GRAVITY_MASK) {
- case Gravity.CENTER_HORIZONTAL:
- retGravity |= Gravity.CENTER_VERTICAL;
- break;
- case Gravity.RIGHT:
- retGravity |= Gravity.TOP;
- break;
- case Gravity.LEFT:
- default:
- retGravity |= Gravity.BOTTOM;
- break;
- }
-
- switch (verticalGravity) {
- case Gravity.CENTER_VERTICAL:
- retGravity |= Gravity.CENTER_HORIZONTAL;
- break;
- case Gravity.BOTTOM:
- retGravity |= Gravity.RIGHT;
- break;
- case Gravity.TOP:
- default:
- retGravity |= Gravity.LEFT;
- break;
- }
- return retGravity;
- }
-
- private void rotateLeft(View v) {
- v.setPadding(v.getPaddingTop(), v.getPaddingRight(), v.getPaddingBottom(),
- v.getPaddingLeft());
- MarginLayoutParams params = (MarginLayoutParams) v.getLayoutParams();
- params.setMargins(params.topMargin, params.rightMargin, params.bottomMargin,
- params.leftMargin);
- v.setLayoutParams(params);
- }
-
- private void rotateRight(View v) {
- v.setPadding(v.getPaddingBottom(), v.getPaddingLeft(), v.getPaddingTop(),
- v.getPaddingRight());
- MarginLayoutParams params = (MarginLayoutParams) v.getLayoutParams();
- params.setMargins(params.bottomMargin, params.leftMargin, params.topMargin,
- params.rightMargin);
- v.setLayoutParams(params);
- }
-
- private void swapLeftAndTop(View v) {
- v.setPadding(v.getPaddingTop(), v.getPaddingLeft(), v.getPaddingBottom(),
- v.getPaddingRight());
- MarginLayoutParams params = (MarginLayoutParams) v.getLayoutParams();
- params.setMargins(params.topMargin, params.leftMargin, params.bottomMargin,
- params.rightMargin);
- v.setLayoutParams(params);
- }
-
- @Override
- protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
- super.onLayout(changed, left, top, right, bottom);
-
- post(() -> updatePosition());
-
- }
-
- private void animateChild(int oldHeight, int newHeight) {
- if (true) return;
- if (mAnimating) {
- mAnimation.cancel();
- }
- mAnimating = true;
- mAnimation = new AnimatorSet();
- mAnimation.addListener(new AnimatorListenerAdapter() {
- @Override
- public void onAnimationEnd(Animator animation) {
- mAnimating = false;
- }
- });
- int fromTop = mList.getTop();
- int fromBottom = mList.getBottom();
- int toTop = fromTop - ((newHeight - oldHeight) / 2);
- int toBottom = fromBottom + ((newHeight - oldHeight) / 2);
- ObjectAnimator top = ObjectAnimator.ofInt(mList, "top", fromTop, toTop);
- top.addUpdateListener(animation -> mListBackground.invalidateSelf());
- mAnimation.playTogether(top,
- ObjectAnimator.ofInt(mList, "bottom", fromBottom, toBottom));
- }
-
- public void setDivisionView(View v) {
- mDivision = v;
- if (mDivision != null) {
- mDivision.addOnLayoutChangeListener(
- (v1, left, top, right, bottom, oldLeft, oldTop, oldRight, oldBottom) ->
- updatePosition());
- }
- updatePosition();
- }
-
- private void updatePosition() {
- if (mList == null) return;
- // If got separated button, setRotatedBackground to false,
- // all items won't get white background.
- boolean separated = mAdapter.hasSeparatedItems();
- mListBackground.setRotatedBackground(separated);
- mSeparatedViewBackground.setRotatedBackground(separated);
- if (mDivision != null && mDivision.getVisibility() == VISIBLE) {
- int index = mRotatedBackground ? 0 : 1;
- mDivision.getLocationOnScreen(mTmp2);
- float trans = mRotatedBackground ? mDivision.getTranslationX()
- : mDivision.getTranslationY();
- int viewTop = (int) (mTmp2[index] + trans);
- mList.getLocationOnScreen(mTmp2);
- viewTop -= mTmp2[index];
- setCutPoint(viewTop);
- } else {
- setCutPoint(mList.getMeasuredHeight());
- }
- }
-
- private void setCutPoint(int point) {
- int curPoint = mListBackground.getCutPoint();
- if (curPoint == point) return;
- if (getAlpha() == 0 || curPoint == 0) {
- mListBackground.setCutPoint(point);
- return;
- }
- if (mAnimator != null) {
- if (mEndPoint == point) {
- return;
- }
- mAnimator.cancel();
- }
- mEndPoint = point;
- mAnimator = ObjectAnimator.ofInt(mListBackground, "cutPoint", curPoint, point);
- if (mCollapse) {
- mAnimator.setStartDelay(300);
- mCollapse = false;
- }
- mAnimator.start();
- }
-
- // If current power menu height larger then screen height, remove padding to break power menu
- // alignment and set menu center vertical within the screen.
- private void updatePaddingAndGravityIfTooTall() {
- int defaultTopPadding;
- int viewsTotalHeight;
- int separatedViewTopMargin;
- int screenHeight;
- int totalHeight;
- int targetGravity;
- boolean separated = mAdapter.hasSeparatedItems();
- MarginLayoutParams params = (MarginLayoutParams) mSeparatedView.getLayoutParams();
- switch (RotationUtils.getRotation(getContext())) {
- case RotationUtils.ROTATION_LANDSCAPE:
- defaultTopPadding = getPaddingLeft();
- viewsTotalHeight = mList.getMeasuredWidth() + mSeparatedView.getMeasuredWidth();
- separatedViewTopMargin = separated ? params.leftMargin : 0;
- screenHeight = getMeasuredWidth();
- targetGravity = Gravity.CENTER_HORIZONTAL|Gravity.TOP;
- break;
- case RotationUtils.ROTATION_SEASCAPE:
- defaultTopPadding = getPaddingRight();
- viewsTotalHeight = mList.getMeasuredWidth() + mSeparatedView.getMeasuredWidth();
- separatedViewTopMargin = separated ? params.leftMargin : 0;
- screenHeight = getMeasuredWidth();
- targetGravity = Gravity.CENTER_HORIZONTAL|Gravity.BOTTOM;
- break;
- default: // Portrait
- defaultTopPadding = getPaddingTop();
- viewsTotalHeight = mList.getMeasuredHeight() + mSeparatedView.getMeasuredHeight();
- separatedViewTopMargin = separated ? params.topMargin : 0;
- screenHeight = getMeasuredHeight();
- targetGravity = Gravity.CENTER_VERTICAL|Gravity.RIGHT;
- break;
- }
- totalHeight = defaultTopPadding + viewsTotalHeight + separatedViewTopMargin;
- if (totalHeight >= screenHeight) {
- setPadding(0, 0, 0, 0);
- setGravity(targetGravity);
- }
- }
-
- @Override
- public ViewOutlineProvider getOutlineProvider() {
- return super.getOutlineProvider();
- }
-
- public void setCollapse() {
- mCollapse = true;
- }
-
- private final ViewTreeObserver.OnComputeInternalInsetsListener mInsetsListener = inoutInfo -> {
- if (mHasOutsideTouch || (mList == null)) {
- inoutInfo.setTouchableInsets(
- ViewTreeObserver.InternalInsetsInfo.TOUCHABLE_INSETS_FRAME);
- return;
- }
- inoutInfo.setTouchableInsets(
- ViewTreeObserver.InternalInsetsInfo.TOUCHABLE_INSETS_CONTENT);
- inoutInfo.contentInsets.set(mList.getLeft(), mList.getTop(),
- 0, getBottom() - mList.getBottom());
- };
-
- private float getAnimationDistance() {
- return getContext().getResources().getDimension(
- com.android.systemui.R.dimen.global_actions_panel_width) / 2;
- }
-
- @Override
- public float getAnimationOffsetX() {
- if (RotationUtils.getRotation(mContext) == ROTATION_NONE) {
- return getAnimationDistance();
- }
- return 0;
- }
-
- @Override
- public float getAnimationOffsetY() {
- switch (RotationUtils.getRotation(getContext())) {
- case RotationUtils.ROTATION_LANDSCAPE:
- return -getAnimationDistance();
- case RotationUtils.ROTATION_SEASCAPE:
- return getAnimationDistance();
- default: // Portrait
- return 0;
- }
- }
-} \ No newline at end of file
diff --git a/packages/SystemUI/src/com/android/systemui/ScreenDecorations.java b/packages/SystemUI/src/com/android/systemui/ScreenDecorations.java
index 0f896c44ae63..cab9f187da6f 100644
--- a/packages/SystemUI/src/com/android/systemui/ScreenDecorations.java
+++ b/packages/SystemUI/src/com/android/systemui/ScreenDecorations.java
@@ -28,7 +28,11 @@ import static android.view.ViewGroup.LayoutParams.MATCH_PARENT;
import static android.view.ViewGroup.LayoutParams.WRAP_CONTENT;
import static android.view.WindowManager.LayoutParams.LAYOUT_IN_DISPLAY_CUTOUT_MODE_ALWAYS;
+import android.animation.Animator;
+import android.animation.AnimatorListenerAdapter;
+import android.animation.ValueAnimator;
import android.annotation.Dimension;
+import android.annotation.NonNull;
import android.app.ActivityManager;
import android.content.BroadcastReceiver;
import android.content.Context;
@@ -36,6 +40,7 @@ import android.content.Intent;
import android.content.IntentFilter;
import android.content.res.ColorStateList;
import android.content.res.Configuration;
+import android.content.res.Resources;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Matrix;
@@ -105,6 +110,7 @@ public class ScreenDecorations extends SystemUI implements Tunable {
private final Handler mMainHandler;
private final TunerService mTunerService;
private DisplayManager.DisplayListener mDisplayListener;
+ private CameraAvailabilityListener mCameraListener;
@VisibleForTesting
protected int mRoundedDefault;
@@ -122,6 +128,26 @@ public class ScreenDecorations extends SystemUI implements Tunable {
private boolean mPendingRotationChange;
private Handler mHandler;
+ private CameraAvailabilityListener.CameraTransitionCallback mCameraTransitionCallback =
+ new CameraAvailabilityListener.CameraTransitionCallback() {
+ @Override
+ public void onApplyCameraProtection(@NonNull Path protectionPath, @NonNull Rect bounds) {
+ // Show the extra protection around the front facing camera if necessary
+ for (DisplayCutoutView dcv : mCutoutViews) {
+ dcv.setProtection(protectionPath, bounds);
+ dcv.setShowProtection(true);
+ }
+ }
+
+ @Override
+ public void onHideCameraProtection() {
+ // Go back to the regular anti-aliasing
+ for (DisplayCutoutView dcv : mCutoutViews) {
+ dcv.setShowProtection(false);
+ }
+ }
+ };
+
/**
* Converts a set of {@link Rect}s into a {@link Region}
*
@@ -169,6 +195,8 @@ public class ScreenDecorations extends SystemUI implements Tunable {
mDisplayManager = mContext.getSystemService(DisplayManager.class);
updateRoundedCornerRadii();
setupDecorations();
+ setupCameraListener();
+
mDisplayListener = new DisplayManager.DisplayListener() {
@Override
public void onDisplayAdded(int displayId) {
@@ -443,6 +471,16 @@ public class ScreenDecorations extends SystemUI implements Tunable {
: pos - rotation;
}
+ private void setupCameraListener() {
+ Resources res = mContext.getResources();
+ boolean enabled = res.getBoolean(R.bool.config_enableDisplayCutoutProtection);
+ if (enabled) {
+ mCameraListener = CameraAvailabilityListener.Factory.build(mContext, mHandler::post);
+ mCameraListener.addTransitionCallback(mCameraTransitionCallback);
+ mCameraListener.startListening();
+ }
+ }
+
private final BroadcastReceiver mIntentReceiver = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
@@ -679,17 +717,29 @@ public class ScreenDecorations extends SystemUI implements Tunable {
public static class DisplayCutoutView extends View implements DisplayManager.DisplayListener,
RegionInterceptableView {
+ private static final float HIDDEN_CAMERA_PROTECTION_SCALE = 0.5f;
+
private final DisplayInfo mInfo = new DisplayInfo();
private final Paint mPaint = new Paint();
private final List<Rect> mBounds = new ArrayList();
private final Rect mBoundingRect = new Rect();
private final Path mBoundingPath = new Path();
+ // Don't initialize these yet because they may never exist
+ private Rect mProtectionRect;
+ private Path mProtectionPath;
+ private Path mProtectionPathOrig;
+ private Rect mTotalBounds = new Rect();
+ // Whether or not to show the cutout protection path
+ private boolean mShowProtection = false;
+
private final int[] mLocation = new int[2];
private final ScreenDecorations mDecorations;
private int mColor = Color.BLACK;
private int mRotation;
private int mInitialPosition;
private int mPosition;
+ private float mCameraProtectionProgress = HIDDEN_CAMERA_PROTECTION_SCALE;
+ private ValueAnimator mCameraProtectionAnimator;
public DisplayCutoutView(Context context, @BoundsPosition int pos,
ScreenDecorations decorations) {
@@ -727,12 +777,19 @@ public class ScreenDecorations extends SystemUI implements Tunable {
super.onDraw(canvas);
getLocationOnScreen(mLocation);
canvas.translate(-mLocation[0], -mLocation[1]);
+
if (!mBoundingPath.isEmpty()) {
mPaint.setColor(mColor);
mPaint.setStyle(Paint.Style.FILL);
mPaint.setAntiAlias(true);
canvas.drawPath(mBoundingPath, mPaint);
}
+ if (mCameraProtectionProgress > HIDDEN_CAMERA_PROTECTION_SCALE
+ && !mProtectionRect.isEmpty()) {
+ canvas.scale(mCameraProtectionProgress, mCameraProtectionProgress,
+ mProtectionRect.centerX(), mProtectionRect.centerY());
+ canvas.drawPath(mProtectionPath, mPaint);
+ }
}
@Override
@@ -755,6 +812,49 @@ public class ScreenDecorations extends SystemUI implements Tunable {
update();
}
+ void setProtection(Path protectionPath, Rect pathBounds) {
+ if (mProtectionPathOrig == null) {
+ mProtectionPathOrig = new Path();
+ mProtectionPath = new Path();
+ }
+ mProtectionPathOrig.set(protectionPath);
+ mProtectionRect = pathBounds;
+ }
+
+ void setShowProtection(boolean shouldShow) {
+ if (mShowProtection == shouldShow) {
+ return;
+ }
+
+ mShowProtection = shouldShow;
+ updateBoundingPath();
+ // Delay the relayout until the end of the animation when hiding the cutout,
+ // otherwise we'd clip it.
+ if (mShowProtection) {
+ requestLayout();
+ }
+ if (mCameraProtectionAnimator != null) {
+ mCameraProtectionAnimator.cancel();
+ }
+ mCameraProtectionAnimator = ValueAnimator.ofFloat(mCameraProtectionProgress,
+ mShowProtection ? 1.0f : HIDDEN_CAMERA_PROTECTION_SCALE).setDuration(750);
+ mCameraProtectionAnimator.setInterpolator(Interpolators.DECELERATE_QUINT);
+ mCameraProtectionAnimator.addUpdateListener(animation -> {
+ mCameraProtectionProgress = (float) animation.getAnimatedValue();
+ invalidate();
+ });
+ mCameraProtectionAnimator.addListener(new AnimatorListenerAdapter() {
+ @Override
+ public void onAnimationEnd(Animator animation) {
+ mCameraProtectionAnimator = null;
+ if (!mShowProtection) {
+ requestLayout();
+ }
+ }
+ });
+ mCameraProtectionAnimator.start();
+ }
+
private void update() {
if (!isAttachedToWindow() || mDecorations.mPendingRotationChange) {
return;
@@ -794,6 +894,11 @@ public class ScreenDecorations extends SystemUI implements Tunable {
Matrix m = new Matrix();
transformPhysicalToLogicalCoordinates(mInfo.rotation, dw, dh, m);
mBoundingPath.transform(m);
+ if (mProtectionPathOrig != null) {
+ // Reset the protection path so we don't aggregate rotations
+ mProtectionPath.set(mProtectionPathOrig);
+ mProtectionPath.transform(m);
+ }
}
private static void transformPhysicalToLogicalCoordinates(@Surface.Rotation int rotation,
@@ -855,9 +960,19 @@ public class ScreenDecorations extends SystemUI implements Tunable {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
return;
}
- setMeasuredDimension(
- resolveSizeAndState(mBoundingRect.width(), widthMeasureSpec, 0),
- resolveSizeAndState(mBoundingRect.height(), heightMeasureSpec, 0));
+
+ if (mShowProtection) {
+ // Make sure that our measured height encompases the protection
+ mTotalBounds.union(mBoundingRect);
+ mTotalBounds.union(mProtectionRect);
+ setMeasuredDimension(
+ resolveSizeAndState(mTotalBounds.width(), widthMeasureSpec, 0),
+ resolveSizeAndState(mTotalBounds.height(), heightMeasureSpec, 0));
+ } else {
+ setMeasuredDimension(
+ resolveSizeAndState(mBoundingRect.width(), widthMeasureSpec, 0),
+ resolveSizeAndState(mBoundingRect.height(), heightMeasureSpec, 0));
+ }
}
public static void boundsFromDirection(DisplayCutout displayCutout, int gravity,
diff --git a/packages/SystemUI/src/com/android/systemui/SizeCompatModeActivityController.java b/packages/SystemUI/src/com/android/systemui/SizeCompatModeActivityController.java
index 4749addc7139..73295a3d8814 100644
--- a/packages/SystemUI/src/com/android/systemui/SizeCompatModeActivityController.java
+++ b/packages/SystemUI/src/com/android/systemui/SizeCompatModeActivityController.java
@@ -229,6 +229,9 @@ public class SizeCompatModeActivityController extends SystemUI implements Comman
}
void remove() {
+ if (mShowingHint != null) {
+ mShowingHint.dismiss();
+ }
getContext().getSystemService(WindowManager.class).removeViewImmediate(this);
}
diff --git a/packages/SystemUI/src/com/android/systemui/assist/AssistManager.java b/packages/SystemUI/src/com/android/systemui/assist/AssistManager.java
index 256c5d51c421..5077e18b06e4 100644
--- a/packages/SystemUI/src/com/android/systemui/assist/AssistManager.java
+++ b/packages/SystemUI/src/com/android/systemui/assist/AssistManager.java
@@ -81,11 +81,6 @@ public class AssistManager {
void onGestureCompletion(float velocity);
/**
- * Called with the Bundle from VoiceInteractionSessionListener.onSetUiHints.
- */
- void processBundle(Bundle hints);
-
- /**
* Hides any SysUI for the assistant, but _does not_ close the assistant itself.
*/
void hide();
diff --git a/packages/SystemUI/src/com/android/systemui/assist/ui/DefaultUiController.java b/packages/SystemUI/src/com/android/systemui/assist/ui/DefaultUiController.java
index f201a6fb1137..68242f0a0ac2 100644
--- a/packages/SystemUI/src/com/android/systemui/assist/ui/DefaultUiController.java
+++ b/packages/SystemUI/src/com/android/systemui/assist/ui/DefaultUiController.java
@@ -26,7 +26,6 @@ import android.content.Context;
import android.graphics.PixelFormat;
import android.metrics.LogMaker;
import android.os.Build;
-import android.os.Bundle;
import android.util.Log;
import android.view.Gravity;
import android.view.LayoutInflater;
@@ -94,11 +93,6 @@ public class DefaultUiController implements AssistManager.UiController {
}
@Override // AssistManager.UiController
- public void processBundle(Bundle bundle) {
- Log.e(TAG, "Bundle received but handling is not implemented; ignoring");
- }
-
- @Override // AssistManager.UiController
public void onInvocationProgress(int type, float progress) {
boolean invocationWasInProgress = mInvocationInProgress;
diff --git a/packages/SystemUI/src/com/android/systemui/bubbles/Bubble.java b/packages/SystemUI/src/com/android/systemui/bubbles/Bubble.java
index 7ca23085f6ee..4240209c4f1b 100644
--- a/packages/SystemUI/src/com/android/systemui/bubbles/Bubble.java
+++ b/packages/SystemUI/src/com/android/systemui/bubbles/Bubble.java
@@ -279,7 +279,8 @@ class Bubble implements BubbleViewProvider {
/**
* @return the display id of the virtual display on which bubble contents is drawn.
*/
- int getDisplayId() {
+ @Override
+ public int getDisplayId() {
return mExpandedView != null ? mExpandedView.getVirtualDisplayId() : INVALID_DISPLAY;
}
diff --git a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleController.java b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleController.java
index 48457f627e83..22c2c7ee9750 100644
--- a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleController.java
+++ b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleController.java
@@ -1175,23 +1175,17 @@ public class BubbleController implements ConfigurationController.ConfigurationLi
* status bar, otherwise returns {@link Display#INVALID_DISPLAY}.
*/
public int getExpandedDisplayId(Context context) {
- final Bubble bubble = getExpandedBubble(context);
- return bubble != null ? bubble.getDisplayId() : INVALID_DISPLAY;
- }
-
- @Nullable
- private Bubble getExpandedBubble(Context context) {
if (mStackView == null) {
- return null;
+ return INVALID_DISPLAY;
}
final boolean defaultDisplay = context.getDisplay() != null
&& context.getDisplay().getDisplayId() == DEFAULT_DISPLAY;
- final Bubble expandedBubble = mStackView.getExpandedBubble();
- if (defaultDisplay && expandedBubble != null && isStackExpanded()
+ final BubbleViewProvider expandedViewProvider = mStackView.getExpandedBubble();
+ if (defaultDisplay && expandedViewProvider != null && isStackExpanded()
&& !mNotificationShadeWindowController.getPanelExpanded()) {
- return expandedBubble;
+ return expandedViewProvider.getDisplayId();
}
- return null;
+ return INVALID_DISPLAY;
}
@VisibleForTesting
@@ -1256,7 +1250,7 @@ public class BubbleController implements ConfigurationController.ConfigurationLi
@Override
public void onSingleTaskDisplayEmpty(int displayId) {
- final Bubble expandedBubble = mStackView != null
+ final BubbleViewProvider expandedBubble = mStackView != null
? mStackView.getExpandedBubble()
: null;
int expandedId = expandedBubble != null ? expandedBubble.getDisplayId() : -1;
@@ -1311,7 +1305,7 @@ public class BubbleController implements ConfigurationController.ConfigurationLi
private class BubblesImeListener extends PinnedStackListenerForwarder.PinnedStackListener {
@Override
public void onImeVisibilityChanged(boolean imeVisible, int imeHeight) {
- if (mStackView != null && mStackView.getBubbleCount() > 0) {
+ if (mStackView != null) {
mStackView.post(() -> mStackView.onImeVisibilityChanged(imeVisible, imeHeight));
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleDebugConfig.java b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleDebugConfig.java
index e800011981a9..19733a5f895c 100644
--- a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleDebugConfig.java
+++ b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleDebugConfig.java
@@ -59,13 +59,15 @@ public class BubbleDebugConfig {
return FORCE_SHOW_USER_EDUCATION || forceShow;
}
- static String formatBubblesString(List<Bubble> bubbles, Bubble selected) {
+ static String formatBubblesString(List<Bubble> bubbles, BubbleViewProvider selected) {
StringBuilder sb = new StringBuilder();
for (Bubble bubble : bubbles) {
if (bubble == null) {
sb.append(" <null> !!!!!\n");
} else {
- boolean isSelected = (selected != null && bubble == selected);
+ boolean isSelected = (selected != null
+ && selected.getKey() != BubbleOverflow.KEY
+ && bubble == selected);
String arrow = isSelected ? "=>" : " ";
sb.append(String.format("%s Bubble{act=%12d, ongoing=%d, key=%s}\n",
arrow,
diff --git a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleExpandedView.java b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleExpandedView.java
index a6f759f3e0b9..5c66462f2a5b 100644
--- a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleExpandedView.java
+++ b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleExpandedView.java
@@ -308,7 +308,14 @@ public class BubbleExpandedView extends LinearLayout implements View.OnClickList
mKeyboardVisible = false;
mNeedsNewHeight = false;
if (mActivityView != null) {
- mActivityView.setForwardedInsets(Insets.of(0, 0, 0, 0));
+ // TODO: Temporary hack to offset the view until we can properly inset Bubbles again.
+ if (sNewInsetsMode == NEW_INSETS_MODE_FULL) {
+ mStackView.animate()
+ .setDuration(100)
+ .translationY(0);
+ } else {
+ mActivityView.setForwardedInsets(Insets.of(0, 0, 0, 0));
+ }
}
if (DEBUG_BUBBLE_EXPANDED_VIEW) {
Log.d(TAG, "onDetachedFromWindow: bubble=" + getBubbleKey());
@@ -351,7 +358,10 @@ public class BubbleExpandedView extends LinearLayout implements View.OnClickList
// TODO: Temporary hack to offset the view until we can properly inset Bubbles again.
if (sNewInsetsMode == NEW_INSETS_MODE_FULL) {
- mStackView.animate().translationY(-insetsBottom);
+ mStackView.animate()
+ .setDuration(100)
+ .translationY(-insetsBottom)
+ .withEndAction(() -> mActivityView.onLocationChanged());
} else {
mActivityView.setForwardedInsets(Insets.of(0, 0, 0, insetsBottom));
}
diff --git a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleExperimentConfig.java b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleExperimentConfig.java
index 2873811aeffb..b33eeba5da70 100644
--- a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleExperimentConfig.java
+++ b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleExperimentConfig.java
@@ -73,6 +73,9 @@ public class BubbleExperimentConfig {
private static final String WHITELISTED_AUTO_BUBBLE_APPS = "whitelisted_auto_bubble_apps";
+ private static final String ALLOW_BUBBLE_OVERFLOW = "allow_bubble_overflow";
+ private static final boolean ALLOW_BUBBLE_OVERFLOW_DEFAULT = false;
+
/**
* When true, if a notification has the information necessary to bubble (i.e. valid
* contentIntent and an icon or image), then a {@link android.app.Notification.BubbleMetadata}
@@ -87,6 +90,15 @@ public class BubbleExperimentConfig {
}
/**
+ * When true, show a menu with dismissed and aged-out bubbles.
+ */
+ static boolean allowBubbleOverflow(Context context) {
+ return Settings.Secure.getInt(context.getContentResolver(),
+ ALLOW_BUBBLE_OVERFLOW,
+ ALLOW_BUBBLE_OVERFLOW_DEFAULT ? 1 : 0) != 0;
+ }
+
+ /**
* Same as {@link #allowAnyNotifToBubble(Context)} except it filters for notifications that
* are using {@link Notification.MessagingStyle} and have remote input.
*/
diff --git a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleOverflow.java b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleOverflow.java
index 313bb4250570..4fb2d0881ede 100644
--- a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleOverflow.java
+++ b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleOverflow.java
@@ -16,6 +16,7 @@
package com.android.systemui.bubbles;
+import static android.view.Display.INVALID_DISPLAY;
import static android.view.View.GONE;
import static com.android.systemui.bubbles.BadgedImageView.DEFAULT_PATH_SIZE;
@@ -45,7 +46,7 @@ public class BubbleOverflow implements BubbleViewProvider {
public static final String KEY = "Overflow";
private BadgedImageView mOverflowBtn;
- private BubbleExpandedView mOverflowExpandedView;
+ private BubbleExpandedView mExpandedView;
private LayoutInflater mInflater;
private Context mContext;
private Bitmap mIcon;
@@ -63,11 +64,11 @@ public class BubbleOverflow implements BubbleViewProvider {
}
void setUpOverflow(ViewGroup parentViewGroup, BubbleStackView stackView) {
- mOverflowExpandedView = (BubbleExpandedView) mInflater.inflate(
+ mExpandedView = (BubbleExpandedView) mInflater.inflate(
R.layout.bubble_expanded_view, parentViewGroup /* root */,
false /* attachToRoot */);
- mOverflowExpandedView.setOverflow(true);
- mOverflowExpandedView.setStackView(stackView);
+ mExpandedView.setOverflow(true);
+ mExpandedView.setStackView(stackView);
updateIcon(mContext, parentViewGroup);
}
@@ -124,7 +125,7 @@ public class BubbleOverflow implements BubbleViewProvider {
@Override
public BubbleExpandedView getExpandedView() {
- return mOverflowExpandedView;
+ return mExpandedView;
}
@Override
@@ -149,7 +150,7 @@ public class BubbleOverflow implements BubbleViewProvider {
@Override
public void setContentVisibility(boolean visible) {
- mOverflowExpandedView.setContentVisibility(visible);
+ mExpandedView.setContentVisibility(visible);
}
@Override
@@ -167,4 +168,9 @@ public class BubbleOverflow implements BubbleViewProvider {
public String getKey() {
return BubbleOverflow.KEY;
}
+
+ @Override
+ public int getDisplayId() {
+ return mExpandedView != null ? mExpandedView.getVirtualDisplayId() : INVALID_DISPLAY;
+ }
}
diff --git a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleStackView.java b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleStackView.java
index 6647069f2033..aedd2db738ee 100644
--- a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleStackView.java
+++ b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleStackView.java
@@ -32,7 +32,6 @@ import static com.android.systemui.bubbles.BubbleDebugConfig.TAG_WITH_CLASS_NAME
import android.animation.Animator;
import android.animation.AnimatorListenerAdapter;
import android.animation.ValueAnimator;
-import android.annotation.NonNull;
import android.app.Notification;
import android.content.Context;
import android.content.res.Configuration;
@@ -47,7 +46,6 @@ import android.graphics.PointF;
import android.graphics.Rect;
import android.graphics.RectF;
import android.os.Bundle;
-import android.os.VibrationEffect;
import android.os.Vibrator;
import android.util.Log;
import android.view.Choreographer;
@@ -56,6 +54,7 @@ import android.view.Gravity;
import android.view.LayoutInflater;
import android.view.MotionEvent;
import android.view.View;
+import android.view.ViewGroup;
import android.view.ViewTreeObserver;
import android.view.WindowInsets;
import android.view.WindowManager;
@@ -66,6 +65,7 @@ import android.widget.FrameLayout;
import android.widget.TextView;
import androidx.annotation.MainThread;
+import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.dynamicanimation.animation.DynamicAnimation;
import androidx.dynamicanimation.animation.FloatPropertyCompat;
@@ -81,7 +81,10 @@ import com.android.systemui.bubbles.animation.ExpandedAnimationController;
import com.android.systemui.bubbles.animation.PhysicsAnimationLayout;
import com.android.systemui.bubbles.animation.StackAnimationController;
import com.android.systemui.shared.system.SysUiStatsLog;
+import com.android.systemui.util.DismissCircleView;
import com.android.systemui.util.FloatingContentCoordinator;
+import com.android.systemui.util.animation.PhysicsAnimator;
+import com.android.systemui.util.magnetictarget.MagnetizedObject;
import java.io.FileDescriptor;
import java.io.PrintWriter;
@@ -123,6 +126,11 @@ public class BubbleStackView extends FrameLayout {
@VisibleForTesting
static final int FLYOUT_HIDE_AFTER = 5000;
+ private static final PhysicsAnimator.SpringConfig FLYOUT_IME_ANIMATION_SPRING_CONFIG =
+ new PhysicsAnimator.SpringConfig(
+ StackAnimationController.IME_ANIMATION_STIFFNESS,
+ StackAnimationController.DEFAULT_BOUNCINESS);
+
/**
* Interface to synchronize {@link View} state and the screen.
*
@@ -227,8 +235,6 @@ public class BubbleStackView extends FrameLayout {
pw.print(" gestureInProgress: "); pw.println(mIsGestureInProgress);
pw.print(" showingDismiss: "); pw.println(mShowingDismiss);
pw.print(" isExpansionAnimating: "); pw.println(mIsExpansionAnimating);
- pw.print(" draggingInDismiss: "); pw.println(mDraggingInDismissTarget);
- pw.print(" animatingMagnet: "); pw.println(mAnimatingMagnet);
mStackAnimationController.dump(fd, pw, args);
mExpandedAnimationController.dump(fd, pw, args);
}
@@ -240,16 +246,6 @@ public class BubbleStackView extends FrameLayout {
private boolean mIsExpansionAnimating = false;
private boolean mShowingDismiss = false;
- /**
- * Whether the user is currently dragging their finger within the dismiss target. In this state
- * the stack will be magnetized to the center of the target, so we shouldn't move it until the
- * touch exits the dismiss target area.
- */
- private boolean mDraggingInDismissTarget = false;
-
- /** Whether the stack is magneting towards the dismiss target. */
- private boolean mAnimatingMagnet = false;
-
/** The view to desaturate/darken when magneted to the dismiss target. */
private View mDesaturateAndDarkenTargetView;
@@ -331,8 +327,100 @@ public class BubbleStackView extends FrameLayout {
@NonNull
private final SurfaceSynchronizer mSurfaceSynchronizer;
- private BubbleDismissView mDismissContainer;
- private Runnable mAfterMagnet;
+ /**
+ * The currently magnetized object, which is being dragged and will be attracted to the magnetic
+ * dismiss target.
+ *
+ * This is either the stack itself, or an individual bubble.
+ */
+ private MagnetizedObject<?> mMagnetizedObject;
+
+ /**
+ * The action to run when the magnetized object is released in the dismiss target.
+ *
+ * This will actually perform the dismissal of either the stack or an individual bubble.
+ */
+ private Runnable mReleasedInDismissTargetAction;
+
+ /**
+ * The MagneticTarget instance for our circular dismiss view. This is added to the
+ * MagnetizedObject instances for the stack and any dragged-out bubbles.
+ */
+ private MagnetizedObject.MagneticTarget mMagneticTarget;
+
+ /** Magnet listener that handles animating and dismissing individual dragged-out bubbles. */
+ private final MagnetizedObject.MagnetListener mIndividualBubbleMagnetListener =
+ new MagnetizedObject.MagnetListener() {
+ @Override
+ public void onStuckToTarget(@NonNull MagnetizedObject.MagneticTarget target) {
+ animateDesaturateAndDarken(
+ mExpandedAnimationController.getDraggedOutBubble(), true);
+ }
+
+ @Override
+ public void onUnstuckFromTarget(@NonNull MagnetizedObject.MagneticTarget target,
+ float velX, float velY, boolean wasFlungOut) {
+ animateDesaturateAndDarken(
+ mExpandedAnimationController.getDraggedOutBubble(), false);
+
+ if (wasFlungOut) {
+ mExpandedAnimationController.snapBubbleBack(
+ mExpandedAnimationController.getDraggedOutBubble(), velX, velY);
+ hideDismissTarget();
+ } else {
+ mExpandedAnimationController.onUnstuckFromTarget();
+ }
+ }
+
+ @Override
+ public void onReleasedInTarget(@NonNull MagnetizedObject.MagneticTarget target) {
+ mExpandedAnimationController.dismissDraggedOutBubble(
+ mExpandedAnimationController.getDraggedOutBubble(),
+ mReleasedInDismissTargetAction);
+ hideDismissTarget();
+ }
+ };
+
+ /** Magnet listener that handles animating and dismissing the entire stack. */
+ private final MagnetizedObject.MagnetListener mStackMagnetListener =
+ new MagnetizedObject.MagnetListener() {
+ @Override
+ public void onStuckToTarget(
+ @NonNull MagnetizedObject.MagneticTarget target) {
+ animateDesaturateAndDarken(mBubbleContainer, true);
+ }
+
+ @Override
+ public void onUnstuckFromTarget(@NonNull MagnetizedObject.MagneticTarget target,
+ float velX, float velY, boolean wasFlungOut) {
+ animateDesaturateAndDarken(mBubbleContainer, false);
+
+ if (wasFlungOut) {
+ mStackAnimationController.flingStackThenSpringToEdge(
+ mStackAnimationController.getStackPosition().x, velX, velY);
+ hideDismissTarget();
+ } else {
+ mStackAnimationController.onUnstuckFromTarget();
+ }
+ }
+
+ @Override
+ public void onReleasedInTarget(@NonNull MagnetizedObject.MagneticTarget target) {
+ mStackAnimationController.implodeStack(
+ () -> {
+ resetDesaturationAndDarken();
+ mReleasedInDismissTargetAction.run();
+ }
+ );
+
+ hideDismissTarget();
+ }
+ };
+
+ private ViewGroup mDismissTargetContainer;
+ private PhysicsAnimator<View> mDismissTargetAnimator;
+ private PhysicsAnimator.SpringConfig mDismissTargetSpring = new PhysicsAnimator.SpringConfig(
+ SpringForce.STIFFNESS_LOW, SpringForce.DAMPING_RATIO_LOW_BOUNCY);
private int mOrientation = Configuration.ORIENTATION_UNDEFINED;
@@ -409,12 +497,31 @@ public class BubbleStackView extends FrameLayout {
.setDampingRatio(SpringForce.DAMPING_RATIO_LOW_BOUNCY));
mFlyoutTransitionSpring.addEndListener(mAfterFlyoutTransitionSpring);
- mDismissContainer = new BubbleDismissView(mContext);
- mDismissContainer.setLayoutParams(new FrameLayout.LayoutParams(
+ final int targetSize = res.getDimensionPixelSize(R.dimen.dismiss_circle_size);
+ final View targetView = new DismissCircleView(context);
+ final FrameLayout.LayoutParams newParams =
+ new FrameLayout.LayoutParams(targetSize, targetSize);
+ newParams.gravity = Gravity.CENTER;
+ targetView.setLayoutParams(newParams);
+ mDismissTargetAnimator = PhysicsAnimator.getInstance(targetView);
+
+ mDismissTargetContainer = new FrameLayout(context);
+ mDismissTargetContainer.setLayoutParams(new FrameLayout.LayoutParams(
MATCH_PARENT,
getResources().getDimensionPixelSize(R.dimen.pip_dismiss_gradient_height),
Gravity.BOTTOM));
- addView(mDismissContainer);
+ mDismissTargetContainer.setClipChildren(false);
+ mDismissTargetContainer.addView(targetView);
+ mDismissTargetContainer.setVisibility(View.INVISIBLE);
+ addView(mDismissTargetContainer);
+
+ // Start translated down so the target springs up.
+ targetView.setTranslationY(
+ getResources().getDimensionPixelSize(R.dimen.pip_dismiss_gradient_height));
+
+ // Save the MagneticTarget instance for the newly set up view - we'll add this to the
+ // MagnetizedObjects.
+ mMagneticTarget = new MagnetizedObject.MagneticTarget(targetView, mBubbleSize * 2);
mExpandedViewXAnim =
new SpringAnimation(mExpandedViewContainer, DynamicAnimation.TRANSLATION_X);
@@ -589,6 +696,9 @@ public class BubbleStackView extends FrameLayout {
}
private void setUpOverflow() {
+ if (!BubbleExperimentConfig.allowBubbleOverflow(mContext)) {
+ return;
+ }
int overflowBtnIndex = 0;
if (mBubbleOverflow == null) {
mBubbleOverflow = new BubbleOverflow(getContext());
@@ -798,13 +908,8 @@ public class BubbleStackView extends FrameLayout {
* The {@link Bubble} that is expanded, null if one does not exist.
*/
@Nullable
- Bubble getExpandedBubble() {
- if (mExpandedBubble == null
- || (mExpandedBubble.getIconView() == mBubbleOverflow.getBtn()
- && BubbleOverflow.KEY.equals(mExpandedBubble.getKey()))) {
- return null;
- }
- return (Bubble) mExpandedBubble;
+ BubbleViewProvider getExpandedBubble() {
+ return mExpandedBubble;
}
// via BubbleData.Listener
@@ -857,6 +962,9 @@ public class BubbleStackView extends FrameLayout {
}
private void updateOverflowBtnVisibility(boolean apply) {
+ if (!BubbleExperimentConfig.allowBubbleOverflow(mContext)) {
+ return;
+ }
if (mIsExpanded) {
if (DEBUG_BUBBLE_STACK_VIEW) {
Log.d(TAG, "Show overflow button.");
@@ -1059,6 +1167,14 @@ public class BubbleStackView extends FrameLayout {
}
}
+ /*
+ * Sets the action to run to dismiss the currently dragging object (either the stack or an
+ * individual bubble).
+ */
+ public void setReleasedInDismissTargetAction(Runnable action) {
+ mReleasedInDismissTargetAction = action;
+ }
+
/**
* Dismiss the stack of bubbles.
*
@@ -1083,7 +1199,8 @@ public class BubbleStackView extends FrameLayout {
float y = event.getRawY();
if (mIsExpanded) {
if (isIntersecting(mBubbleContainer, x, y)) {
- if (isIntersecting(mBubbleOverflow.getBtn(), x, y)) {
+ if (BubbleExperimentConfig.allowBubbleOverflow(mContext)
+ && isIntersecting(mBubbleOverflow.getBtn(), x, y)) {
return mBubbleOverflow.getBtn();
}
// Could be tapping or dragging a bubble while expanded
@@ -1122,7 +1239,8 @@ public class BubbleStackView extends FrameLayout {
}
/**
- * @deprecated use {@link #setExpanded(boolean)} and {@link #setSelectedBubble(Bubble)}
+ * @deprecated use {@link #setExpanded(boolean)} and
+ * {@link BubbleData#setSelectedBubble(Bubble)}
*/
@Deprecated
@MainThread
@@ -1164,7 +1282,7 @@ public class BubbleStackView extends FrameLayout {
if (DEBUG_BUBBLE_STACK_VIEW) {
Log.d(TAG, "animateCollapse");
Log.d(TAG, BubbleDebugConfig.formatBubblesString(getBubblesOnScreen(),
- getExpandedBubble()));
+ mExpandedBubble));
}
updateOverflowBtnVisibility(/* apply */ false);
mBubbleContainer.cancelAllAnimations();
@@ -1236,8 +1354,23 @@ public class BubbleStackView extends FrameLayout {
public void onImeVisibilityChanged(boolean visible, int height) {
mStackAnimationController.setImeHeight(visible ? height + mImeOffset : 0);
- if (!mIsExpanded) {
- mStackAnimationController.animateForImeVisibility(visible);
+ if (!mIsExpanded && getBubbleCount() > 0) {
+ final float stackDestinationY =
+ mStackAnimationController.animateForImeVisibility(visible);
+
+ // How far the stack is animating due to IME, we'll just animate the flyout by that
+ // much too.
+ final float stackDy =
+ stackDestinationY - mStackAnimationController.getStackPosition().y;
+
+ // If the flyout is visible, translate it along with the bubble stack.
+ if (mFlyout.getVisibility() == VISIBLE) {
+ PhysicsAnimator.getInstance(mFlyout)
+ .spring(DynamicAnimation.TRANSLATION_Y,
+ mFlyout.getTranslationY() + stackDy,
+ FLYOUT_IME_ANIMATION_SPRING_CONFIG)
+ .start();
+ }
}
}
@@ -1253,8 +1386,14 @@ public class BubbleStackView extends FrameLayout {
if (DEBUG_BUBBLE_STACK_VIEW) {
Log.d(TAG, "onBubbleDragStart: bubble=" + bubble);
}
+ mExpandedAnimationController.prepareForBubbleDrag(bubble, mMagneticTarget);
+
+ // We're dragging an individual bubble, so set the magnetized object to the magnetized
+ // bubble.
+ mMagnetizedObject = mExpandedAnimationController.getMagnetizedBubbleDraggingOut();
+ mMagnetizedObject.setMagnetListener(mIndividualBubbleMagnetListener);
+
maybeShowManageEducation(false);
- mExpandedAnimationController.prepareForBubbleDrag(bubble);
}
/** Called with the coordinates to which an individual bubble has been dragged. */
@@ -1296,7 +1435,9 @@ public class BubbleStackView extends FrameLayout {
mBubbleContainer.setActiveController(mStackAnimationController);
hideFlyoutImmediate();
- mDraggingInDismissTarget = false;
+ // Since we're dragging the stack, set the magnetized object to the magnetized stack.
+ mMagnetizedObject = mStackAnimationController.getMagnetizedStack(mMagneticTarget);
+ mMagnetizedObject.setMagnetListener(mStackMagnetListener);
}
void onDragged(float x, float y) {
@@ -1417,6 +1558,11 @@ public class BubbleStackView extends FrameLayout {
}
}
+ /** Passes the MotionEvent to the magnetized object and returns true if it was consumed. */
+ boolean passEventToMagnetizedObject(MotionEvent event) {
+ return mMagnetizedObject != null && mMagnetizedObject.maybeConsumeMotionEvent(event);
+ }
+
/** Prepares and starts the desaturate/darken animation on the bubble stack. */
private void animateDesaturateAndDarken(View targetView, boolean desaturateAndDarken) {
mDesaturateAndDarkenTargetView = targetView;
@@ -1447,102 +1593,6 @@ public class BubbleStackView extends FrameLayout {
mDesaturateAndDarkenTargetView.setLayerType(View.LAYER_TYPE_NONE, null);
}
- /**
- * Magnets the stack to the target, while also transforming the target to encircle the stack and
- * desaturating/darkening the bubbles.
- */
- void animateMagnetToDismissTarget(
- View magnetView, boolean toTarget, float x, float y, float velX, float velY) {
- mDraggingInDismissTarget = toTarget;
-
- if (toTarget) {
- // The Y-value for the bubble stack to be positioned in the center of the dismiss target
- final float destY = mDismissContainer.getDismissTargetCenterY() - mBubbleSize / 2f;
-
- mAnimatingMagnet = true;
-
- final Runnable afterMagnet = () -> {
- mAnimatingMagnet = false;
- if (mAfterMagnet != null) {
- mAfterMagnet.run();
- }
- };
-
- if (magnetView == this) {
- mStackAnimationController.magnetToDismiss(velX, velY, destY, afterMagnet);
- animateDesaturateAndDarken(mBubbleContainer, true);
- } else {
- mExpandedAnimationController.magnetBubbleToDismiss(
- magnetView, velX, velY, destY, afterMagnet);
-
- animateDesaturateAndDarken(magnetView, true);
- }
- } else {
- mAnimatingMagnet = false;
-
- if (magnetView == this) {
- mStackAnimationController.demagnetizeFromDismissToPoint(x, y, velX, velY);
- animateDesaturateAndDarken(mBubbleContainer, false);
- } else {
- mExpandedAnimationController.demagnetizeBubbleTo(x, y, velX, velY);
- animateDesaturateAndDarken(magnetView, false);
- }
- }
-
- mVibrator.vibrate(VibrationEffect.get(toTarget
- ? VibrationEffect.EFFECT_CLICK
- : VibrationEffect.EFFECT_TICK));
- }
-
- /**
- * Magnets the stack to the dismiss target if it's not already there. Then, dismiss the stack
- * using the 'implode' animation and animate out the target.
- */
- void magnetToStackIfNeededThenAnimateDismissal(
- View touchedView, float velX, float velY, Runnable after) {
- final View draggedOutBubble = mExpandedAnimationController.getDraggedOutBubble();
- final Runnable animateDismissal = () -> {
- mAfterMagnet = null;
-
- mVibrator.vibrate(VibrationEffect.get(VibrationEffect.EFFECT_CLICK));
- mDismissContainer.springOut();
-
- // 'Implode' the stack and then hide the dismiss target.
- if (touchedView == this) {
- mStackAnimationController.implodeStack(
- () -> {
- mAnimatingMagnet = false;
- mShowingDismiss = false;
- mDraggingInDismissTarget = false;
- after.run();
- resetDesaturationAndDarken();
- });
- } else {
- mExpandedAnimationController.dismissDraggedOutBubble(draggedOutBubble, () -> {
- mAnimatingMagnet = false;
- mShowingDismiss = false;
- mDraggingInDismissTarget = false;
- resetDesaturationAndDarken();
- after.run();
- });
- }
- };
-
- if (mAnimatingMagnet) {
- // If the magnet animation is currently playing, dismiss the stack after it's done. This
- // happens if the stack is flung towards the target.
- mAfterMagnet = animateDismissal;
- } else if (mDraggingInDismissTarget) {
- // If we're in the dismiss target, but not animating, we already magneted - dismiss
- // immediately.
- animateDismissal.run();
- } else {
- // Otherwise, we need to start the magnet animation and then dismiss afterward.
- animateMagnetToDismissTarget(touchedView, true, -1 /* x */, -1 /* y */, velX, velY);
- mAfterMagnet = animateDismissal;
- }
- }
-
/** Animates in the dismiss target. */
private void springInDismissTarget() {
if (mShowingDismiss) {
@@ -1551,10 +1601,14 @@ public class BubbleStackView extends FrameLayout {
mShowingDismiss = true;
- // Show the dismiss container and bring it to the front so the bubbles will go behind it.
- mDismissContainer.springIn();
- mDismissContainer.bringToFront();
- mDismissContainer.setZ(Short.MAX_VALUE - 1);
+ mDismissTargetContainer.bringToFront();
+ mDismissTargetContainer.setZ(Short.MAX_VALUE - 1);
+ mDismissTargetContainer.setVisibility(VISIBLE);
+
+ mDismissTargetAnimator.cancel();
+ mDismissTargetAnimator
+ .spring(DynamicAnimation.TRANSLATION_Y, 0f, mDismissTargetSpring)
+ .start();
}
/**
@@ -1566,13 +1620,13 @@ public class BubbleStackView extends FrameLayout {
return;
}
- mDismissContainer.springOut();
mShowingDismiss = false;
- }
- /** Whether the location of the given MotionEvent is within the dismiss target area. */
- boolean isInDismissTarget(MotionEvent ev) {
- return isIntersecting(mDismissContainer.getDismissTarget(), ev.getRawX(), ev.getRawY());
+ mDismissTargetAnimator
+ .spring(DynamicAnimation.TRANSLATION_Y, mDismissTargetContainer.getHeight(),
+ mDismissTargetSpring)
+ .withEndActions(() -> mDismissTargetContainer.setVisibility(View.INVISIBLE))
+ .start();
}
/** Animates the flyout collapsed (to dot), or the reverse, starting with the given velocity. */
@@ -1803,25 +1857,27 @@ public class BubbleStackView extends FrameLayout {
}
private void updatePointerPosition() {
- Bubble expandedBubble = getExpandedBubble();
- if (expandedBubble == null) {
+ if (mExpandedBubble == null) {
return;
}
- int index = getBubbleIndex(expandedBubble);
+ int index = getBubbleIndex(mExpandedBubble);
float bubbleLeftFromScreenLeft = mExpandedAnimationController.getBubbleLeft(index);
float halfBubble = mBubbleSize / 2f;
float bubbleCenter = bubbleLeftFromScreenLeft + halfBubble;
// Padding might be adjusted for insets, so get it directly from the view
bubbleCenter -= mExpandedViewContainer.getPaddingLeft();
- expandedBubble.getExpandedView().setPointerPosition(bubbleCenter);
+ mExpandedBubble.getExpandedView().setPointerPosition(bubbleCenter);
}
/**
* @return the number of bubbles in the stack view.
*/
public int getBubbleCount() {
- // Subtract 1 for the overflow button that is always in the bubble container.
- return mBubbleContainer.getChildCount() - 1;
+ if (BubbleExperimentConfig.allowBubbleOverflow(mContext)) {
+ // Subtract 1 for the overflow button that is always in the bubble container.
+ return mBubbleContainer.getChildCount() - 1;
+ }
+ return mBubbleContainer.getChildCount();
}
/**
@@ -1832,11 +1888,10 @@ public class BubbleStackView extends FrameLayout {
* is between 0 and the bubble count minus 1.
*/
int getBubbleIndex(@Nullable BubbleViewProvider provider) {
- if (provider == null || provider.getKey() == BubbleOverflow.KEY) {
+ if (provider == null) {
return 0;
}
- Bubble b = (Bubble) provider;
- return mBubbleContainer.indexOfChild(b.getIconView());
+ return mBubbleContainer.indexOfChild(provider.getIconView());
}
/**
diff --git a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleTouchHandler.java b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleTouchHandler.java
index 46d1e0dfbab7..0c5bef4d2bde 100644
--- a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleTouchHandler.java
+++ b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleTouchHandler.java
@@ -30,28 +30,6 @@ import com.android.systemui.Dependency;
* dismissing, and flings.
*/
class BubbleTouchHandler implements View.OnTouchListener {
- /** Velocity required to dismiss the stack without dragging it into the dismiss target. */
- private static final float STACK_DISMISS_MIN_VELOCITY = 4000f;
-
- /**
- * Velocity required to dismiss an individual bubble without dragging it into the dismiss
- * target.
- *
- * This is higher than the stack dismiss velocity since unlike the stack, a downward fling could
- * also be an attempted gesture to return the bubble to the row of expanded bubbles, which would
- * usually be below the dragged bubble. By increasing the required velocity, it's less likely
- * that the user is trying to drop it back into the row vs. fling it away.
- */
- private static final float INDIVIDUAL_BUBBLE_DISMISS_MIN_VELOCITY = 6000f;
-
- /**
- * When the stack is flung towards the bottom of the screen, it'll be dismissed if it's flung
- * towards the center of the screen (where the dismiss target is). This value is the width of
- * the target area to be considered 'towards the target'. For example 50% means that the stack
- * needs to be flung towards the middle 50%, and the 25% on the left and right sides won't
- * count.
- */
- private static final float DISMISS_FLING_TARGET_WIDTH_PERCENT = 0.5f;
private final PointF mTouchDown = new PointF();
private final PointF mViewPositionOnTouchDown = new PointF();
@@ -66,8 +44,6 @@ class BubbleTouchHandler implements View.OnTouchListener {
/** View that was initially touched, when we received the first ACTION_DOWN event. */
private View mTouchedView;
- /** Whether the current touched view is in the dismiss target. */
- private boolean mInDismissTarget;
BubbleTouchHandler(BubbleStackView stackView,
BubbleData bubbleData, Context context) {
@@ -124,13 +100,33 @@ class BubbleTouchHandler implements View.OnTouchListener {
if (isStack) {
mViewPositionOnTouchDown.set(mStack.getStackPosition());
+
+ // Dismiss the entire stack if it's released in the dismiss target.
+ mStack.setReleasedInDismissTargetAction(
+ () -> mController.dismissStack(BubbleController.DISMISS_USER_GESTURE));
mStack.onDragStart();
+ mStack.passEventToMagnetizedObject(event);
} else if (isFlyout) {
mStack.onFlyoutDragStart();
} else {
mViewPositionOnTouchDown.set(
mTouchedView.getTranslationX(), mTouchedView.getTranslationY());
+
+ // Dismiss only the dragged-out bubble if it's released in the target.
+ final String individualBubbleKey = ((BadgedImageView) mTouchedView).getKey();
+ mStack.setReleasedInDismissTargetAction(() -> {
+ final Bubble bubble =
+ mBubbleData.getBubbleWithKey(individualBubbleKey);
+ // bubble can be null if the user is in the middle of
+ // dismissing the bubble, but the app also sent a cancel
+ if (bubble != null) {
+ mController.removeBubble(bubble.getEntry(),
+ BubbleController.DISMISS_USER_GESTURE);
+ }
+ });
+
mStack.onBubbleDragStart(mTouchedView);
+ mStack.passEventToMagnetizedObject(event);
}
break;
@@ -144,27 +140,16 @@ class BubbleTouchHandler implements View.OnTouchListener {
}
if (mMovedEnough) {
- if (isStack) {
- mStack.onDragged(viewX, viewY);
- } else if (isFlyout) {
+ if (isFlyout) {
mStack.onFlyoutDragged(deltaX);
- } else {
- mStack.onBubbleDragged(mTouchedView, viewX, viewY);
- }
- }
-
- final boolean currentlyInDismissTarget = mStack.isInDismissTarget(event);
- if (currentlyInDismissTarget != mInDismissTarget) {
- mInDismissTarget = currentlyInDismissTarget;
-
- mVelocityTracker.computeCurrentVelocity(/* maxVelocity */ 1000);
- final float velX = mVelocityTracker.getXVelocity();
- final float velY = mVelocityTracker.getYVelocity();
-
- // If the touch event is within the dismiss target, magnet the stack to it.
- if (!isFlyout) {
- mStack.animateMagnetToDismissTarget(
- mTouchedView, mInDismissTarget, viewX, viewY, velX, velY);
+ } else if (!mStack.passEventToMagnetizedObject(event)) {
+ // If the magnetic target doesn't consume the event, drag the stack or
+ // bubble.
+ if (isStack) {
+ mStack.onDragged(viewX, viewY);
+ } else {
+ mStack.onBubbleDragged(mTouchedView, viewX, viewY);
+ }
}
}
break;
@@ -179,42 +164,21 @@ class BubbleTouchHandler implements View.OnTouchListener {
final float velX = mVelocityTracker.getXVelocity();
final float velY = mVelocityTracker.getYVelocity();
- final boolean shouldDismiss =
- isStack
- ? mInDismissTarget
- || isFastFlingTowardsDismissTarget(rawX, rawY, velX, velY)
- : mInDismissTarget
- || velY > INDIVIDUAL_BUBBLE_DISMISS_MIN_VELOCITY;
-
if (isFlyout && mMovedEnough) {
mStack.onFlyoutDragFinished(rawX - mTouchDown.x /* deltaX */, velX);
- } else if (shouldDismiss) {
- final String individualBubbleKey =
- isStack ? null : ((BadgedImageView) mTouchedView).getKey();
- mStack.magnetToStackIfNeededThenAnimateDismissal(mTouchedView, velX, velY,
- () -> {
- if (isStack) {
- mController.dismissStack(BubbleController.DISMISS_USER_GESTURE);
- } else {
- final Bubble bubble =
- mBubbleData.getBubbleWithKey(individualBubbleKey);
- // bubble can be null if the user is in the middle of
- // dismissing the bubble, but the app also sent a cancel
- if (bubble != null) {
- mController.removeBubble(bubble.getEntry(),
- BubbleController.DISMISS_USER_GESTURE);
- }
- }
- });
} else if (isFlyout) {
if (!mBubbleData.isExpanded() && !mMovedEnough) {
mStack.onFlyoutTapped();
}
} else if (mMovedEnough) {
- if (isStack) {
- mStack.onDragFinish(viewX, viewY, velX, velY);
- } else {
- mStack.onBubbleDragFinish(mTouchedView, viewX, viewY, velX, velY);
+ if (!mStack.passEventToMagnetizedObject(event)) {
+ // If the magnetic target didn't consume the event, tell the stack to finish
+ // the drag.
+ if (isStack) {
+ mStack.onDragFinish(viewX, viewY, velX, velY);
+ } else {
+ mStack.onBubbleDragFinish(mTouchedView, viewX, viewY, velX, velY);
+ }
}
} else if (mTouchedView == mStack.getExpandedBubbleView()) {
mBubbleData.setExpanded(false);
@@ -235,45 +199,15 @@ class BubbleTouchHandler implements View.OnTouchListener {
return true;
}
- /**
- * Whether the given touch data represents a powerful fling towards the bottom-center of the
- * screen (the dismiss target).
- */
- private boolean isFastFlingTowardsDismissTarget(
- float rawX, float rawY, float velX, float velY) {
- // Not a fling downward towards the target if velocity is zero or negative.
- if (velY <= 0) {
- return false;
- }
-
- float bottomOfScreenInterceptX = rawX;
-
- // Only do math if the X velocity is non-zero, otherwise X won't change.
- if (velX != 0) {
- // Rise over run...
- final float slope = velY / velX;
- // ...y = mx + b, b = y / mx...
- final float yIntercept = rawY - slope * rawX;
- // ...calculate the x value when y = bottom of the screen.
- bottomOfScreenInterceptX = (mStack.getHeight() - yIntercept) / slope;
- }
-
- final float dismissTargetWidth =
- mStack.getWidth() * DISMISS_FLING_TARGET_WIDTH_PERCENT;
- return velY > STACK_DISMISS_MIN_VELOCITY
- && bottomOfScreenInterceptX > dismissTargetWidth / 2f
- && bottomOfScreenInterceptX < mStack.getWidth() - dismissTargetWidth / 2f;
- }
-
/** Clears all touch-related state. */
private void resetForNextGesture() {
if (mVelocityTracker != null) {
mVelocityTracker.recycle();
mVelocityTracker = null;
}
+
mTouchedView = null;
mMovedEnough = false;
- mInDismissTarget = false;
mStack.onGestureFinished();
}
diff --git a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleViewProvider.java b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleViewProvider.java
index f04933abdcc2..ef84c73b3145 100644
--- a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleViewProvider.java
+++ b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleViewProvider.java
@@ -41,4 +41,6 @@ interface BubbleViewProvider {
Path getDotPath();
boolean showDot();
+
+ int getDisplayId();
}
diff --git a/packages/SystemUI/src/com/android/systemui/bubbles/animation/ExpandedAnimationController.java b/packages/SystemUI/src/com/android/systemui/bubbles/animation/ExpandedAnimationController.java
index 607b5ef9b2c2..3eaa90c985d7 100644
--- a/packages/SystemUI/src/com/android/systemui/bubbles/animation/ExpandedAnimationController.java
+++ b/packages/SystemUI/src/com/android/systemui/bubbles/animation/ExpandedAnimationController.java
@@ -25,13 +25,14 @@ import android.view.DisplayCutout;
import android.view.View;
import android.view.WindowInsets;
+import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.dynamicanimation.animation.DynamicAnimation;
import androidx.dynamicanimation.animation.SpringForce;
import com.android.systemui.Interpolators;
import com.android.systemui.R;
-import com.android.systemui.bubbles.BubbleExperimentConfig;
+import com.android.systemui.util.magnetictarget.MagnetizedObject;
import com.google.android.collect.Sets;
@@ -62,6 +63,12 @@ public class ExpandedAnimationController
/** What percentage of the screen to use when centering the bubbles in landscape. */
private static final float CENTER_BUBBLES_LANDSCAPE_PERCENT = 0.66f;
+ /**
+ * Velocity required to dismiss an individual bubble without dragging it into the dismiss
+ * target.
+ */
+ private static final float FLING_TO_DISMISS_MIN_VELOCITY = 6000f;
+
/** Horizontal offset between bubbles, which we need to know to re-stack them. */
private float mStackOffsetPx;
/** Space between status bar and bubbles in the expanded state. */
@@ -79,9 +86,6 @@ public class ExpandedAnimationController
/** What the current screen orientation is. */
private int mScreenOrientation;
- /** Whether the dragged-out bubble is in the dismiss target. */
- private boolean mIndividualBubbleWithinDismissTarget = false;
-
private boolean mAnimatingExpand = false;
private boolean mAnimatingCollapse = false;
private @Nullable Runnable mAfterExpand;
@@ -99,6 +103,17 @@ public class ExpandedAnimationController
*/
private boolean mSpringingBubbleToTouch = false;
+ /**
+ * Whether to spring the bubble to the next touch event coordinates. This is used to animate the
+ * bubble out of the magnetic dismiss target to the touch location.
+ *
+ * Once it 'catches up' and the animation ends, we'll revert to moving it directly.
+ */
+ private boolean mSpringToTouchOnNextMotionEvent = false;
+
+ /** The bubble currently being dragged out of the row (to potentially be dismissed). */
+ private MagnetizedObject<View> mMagnetizedBubbleDraggingOut;
+
private int mExpandedViewPadding;
public ExpandedAnimationController(Point displaySize, int expandedViewPadding,
@@ -113,9 +128,6 @@ public class ExpandedAnimationController
*/
private boolean mBubbleDraggedOutEnough = false;
- /** The bubble currently being dragged out of the row (to potentially be dismissed). */
- private View mBubbleDraggingOut;
-
/**
* Animates expanding the bubbles into a row along the top of the screen.
*/
@@ -235,12 +247,46 @@ public class ExpandedAnimationController
}).startAll(after);
}
+ /** Notifies the controller that the dragged-out bubble was unstuck from the magnetic target. */
+ public void onUnstuckFromTarget() {
+ mSpringToTouchOnNextMotionEvent = true;
+ }
+
/** Prepares the given bubble to be dragged out. */
- public void prepareForBubbleDrag(View bubble) {
+ public void prepareForBubbleDrag(View bubble, MagnetizedObject.MagneticTarget target) {
mLayout.cancelAnimationsOnView(bubble);
- mBubbleDraggingOut = bubble;
- mBubbleDraggingOut.setTranslationZ(Short.MAX_VALUE);
+ bubble.setTranslationZ(Short.MAX_VALUE);
+ mMagnetizedBubbleDraggingOut = new MagnetizedObject<View>(
+ mLayout.getContext(), bubble,
+ DynamicAnimation.TRANSLATION_X, DynamicAnimation.TRANSLATION_Y) {
+ @Override
+ public float getWidth(@NonNull View underlyingObject) {
+ return mBubbleSizePx;
+ }
+
+ @Override
+ public float getHeight(@NonNull View underlyingObject) {
+ return mBubbleSizePx;
+ }
+
+ @Override
+ public void getLocationOnScreen(@NonNull View underlyingObject, @NonNull int[] loc) {
+ loc[0] = (int) bubble.getTranslationX();
+ loc[1] = (int) bubble.getTranslationY();
+ }
+ };
+ mMagnetizedBubbleDraggingOut.addTarget(target);
+ mMagnetizedBubbleDraggingOut.setHapticsEnabled(true);
+ mMagnetizedBubbleDraggingOut.setFlingToTargetMinVelocity(FLING_TO_DISMISS_MIN_VELOCITY);
+ }
+
+ private void springBubbleTo(View bubble, float x, float y) {
+ animationForChild(bubble)
+ .translationX(x)
+ .translationY(y)
+ .withStiffness(SpringForce.STIFFNESS_HIGH)
+ .start();
}
/**
@@ -249,20 +295,20 @@ public class ExpandedAnimationController
* bubble is dragged back into the row.
*/
public void dragBubbleOut(View bubbleView, float x, float y) {
- if (mSpringingBubbleToTouch) {
+ if (mSpringToTouchOnNextMotionEvent) {
+ springBubbleTo(mMagnetizedBubbleDraggingOut.getUnderlyingObject(), x, y);
+ mSpringToTouchOnNextMotionEvent = false;
+ mSpringingBubbleToTouch = true;
+ } else if (mSpringingBubbleToTouch) {
if (mLayout.arePropertiesAnimatingOnView(
bubbleView, DynamicAnimation.TRANSLATION_X, DynamicAnimation.TRANSLATION_Y)) {
- animationForChild(mBubbleDraggingOut)
- .translationX(x)
- .translationY(y)
- .withStiffness(SpringForce.STIFFNESS_HIGH)
- .start();
+ springBubbleTo(mMagnetizedBubbleDraggingOut.getUnderlyingObject(), x, y);
} else {
mSpringingBubbleToTouch = false;
}
}
- if (!mSpringingBubbleToTouch && !mIndividualBubbleWithinDismissTarget) {
+ if (!mSpringingBubbleToTouch && !mMagnetizedBubbleDraggingOut.getObjectStuckToTarget()) {
bubbleView.setTranslationX(x);
bubbleView.setTranslationY(y);
}
@@ -277,8 +323,6 @@ public class ExpandedAnimationController
/** Plays a dismiss animation on the dragged out bubble. */
public void dismissDraggedOutBubble(View bubble, Runnable after) {
- mIndividualBubbleWithinDismissTarget = false;
-
animationForChild(bubble)
.withStiffness(SpringForce.STIFFNESS_HIGH)
.scaleX(1.1f)
@@ -290,37 +334,14 @@ public class ExpandedAnimationController
}
@Nullable public View getDraggedOutBubble() {
- return mBubbleDraggingOut;
- }
-
- /** Magnets the given bubble to the dismiss target. */
- public void magnetBubbleToDismiss(
- View bubbleView, float velX, float velY, float destY, Runnable after) {
- mIndividualBubbleWithinDismissTarget = true;
- mSpringingBubbleToTouch = false;
- animationForChild(bubbleView)
- .withStiffness(SpringForce.STIFFNESS_MEDIUM)
- .withDampingRatio(SpringForce.DAMPING_RATIO_LOW_BOUNCY)
- .withPositionStartVelocities(velX, velY)
- .translationX(mLayout.getWidth() / 2f - mBubbleSizePx / 2f)
- .translationY(destY, after)
- .start();
+ return mMagnetizedBubbleDraggingOut == null
+ ? null
+ : mMagnetizedBubbleDraggingOut.getUnderlyingObject();
}
- /**
- * Springs the dragged-out bubble towards the given coordinates and sets flags to have touch
- * events update the spring's final position until it's settled.
- */
- public void demagnetizeBubbleTo(float x, float y, float velX, float velY) {
- mIndividualBubbleWithinDismissTarget = false;
- mSpringingBubbleToTouch = true;
-
- animationForChild(mBubbleDraggingOut)
- .translationX(x)
- .translationY(y)
- .withPositionStartVelocities(velX, velY)
- .withStiffness(SpringForce.STIFFNESS_HIGH)
- .start();
+ /** Returns the MagnetizedObject instance for the dragging-out bubble. */
+ public MagnetizedObject<View> getMagnetizedBubbleDraggingOut() {
+ return mMagnetizedBubbleDraggingOut;
}
/**
@@ -335,13 +356,14 @@ public class ExpandedAnimationController
.withPositionStartVelocities(velX, velY)
.start(() -> bubbleView.setTranslationZ(0f) /* after */);
+ mMagnetizedBubbleDraggingOut = null;
+
updateBubblePositions();
}
/** Resets bubble drag out gesture flags. */
public void onGestureFinished() {
mBubbleDraggedOutEnough = false;
- mBubbleDraggingOut = null;
updateBubblePositions();
}
@@ -373,7 +395,6 @@ public class ExpandedAnimationController
pw.print(" isActive: "); pw.println(isActiveController());
pw.print(" animatingExpand: "); pw.println(mAnimatingExpand);
pw.print(" animatingCollapse: "); pw.println(mAnimatingCollapse);
- pw.print(" bubbleInDismiss: "); pw.println(mIndividualBubbleWithinDismissTarget);
pw.print(" springingBubble: "); pw.println(mSpringingBubbleToTouch);
}
@@ -453,8 +474,8 @@ public class ExpandedAnimationController
final PhysicsAnimationLayout.PhysicsPropertyAnimator animator = animationForChild(child);
// If we're removing the dragged-out bubble, that means it got dismissed.
- if (child.equals(mBubbleDraggingOut)) {
- mBubbleDraggingOut = null;
+ if (child.equals(getDraggedOutBubble())) {
+ mMagnetizedBubbleDraggingOut = null;
finishRemoval.run();
} else {
animator.alpha(0f, finishRemoval /* endAction */)
@@ -490,7 +511,7 @@ public class ExpandedAnimationController
// Don't animate the dragging out bubble, or it'll jump around while being dragged. It
// will be snapped to the correct X value after the drag (if it's not dismissed).
- if (bubble.equals(mBubbleDraggingOut)) {
+ if (bubble.equals(getDraggedOutBubble())) {
return;
}
diff --git a/packages/SystemUI/src/com/android/systemui/bubbles/animation/StackAnimationController.java b/packages/SystemUI/src/com/android/systemui/bubbles/animation/StackAnimationController.java
index f22c8faad95c..86387f1cc546 100644
--- a/packages/SystemUI/src/com/android/systemui/bubbles/animation/StackAnimationController.java
+++ b/packages/SystemUI/src/com/android/systemui/bubbles/animation/StackAnimationController.java
@@ -16,7 +16,6 @@
package com.android.systemui.bubbles.animation;
-import android.annotation.NonNull;
import android.content.res.Resources;
import android.graphics.PointF;
import android.graphics.Rect;
@@ -25,6 +24,7 @@ import android.util.Log;
import android.view.View;
import android.view.WindowInsets;
+import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.dynamicanimation.animation.DynamicAnimation;
import androidx.dynamicanimation.animation.FlingAnimation;
@@ -35,6 +35,7 @@ import androidx.dynamicanimation.animation.SpringForce;
import com.android.systemui.R;
import com.android.systemui.util.FloatingContentCoordinator;
import com.android.systemui.util.animation.PhysicsAnimator;
+import com.android.systemui.util.magnetictarget.MagnetizedObject;
import com.google.android.collect.Sets;
@@ -67,9 +68,10 @@ public class StackAnimationController extends
/**
* Values to use for the default {@link SpringForce} provided to the physics animation layout.
*/
- private static final int DEFAULT_STIFFNESS = 12000;
+ public static final int DEFAULT_STIFFNESS = 12000;
+ public static final float IME_ANIMATION_STIFFNESS = SpringForce.STIFFNESS_LOW;
private static final int FLING_FOLLOW_STIFFNESS = 20000;
- private static final float DEFAULT_BOUNCINESS = 0.9f;
+ public static final float DEFAULT_BOUNCINESS = 0.9f;
/**
* Friction applied to fling animations. Since the stack must land on one of the sides of the
@@ -92,6 +94,9 @@ public class StackAnimationController extends
*/
private static final float ESCAPE_VELOCITY = 750f;
+ /** Velocity required to dismiss the stack without dragging it into the dismiss target. */
+ private static final float FLING_TO_DISMISS_MIN_VELOCITY = 4000f;
+
/**
* The canonical position of the stack. This is typically the position of the first bubble, but
* we need to keep track of it separately from the first bubble's translation in case there are
@@ -100,6 +105,12 @@ public class StackAnimationController extends
private PointF mStackPosition = new PointF(-1, -1);
/**
+ * MagnetizedObject instance for the stack, which is used by the touch handler for the magnetic
+ * dismiss target.
+ */
+ private MagnetizedObject<StackAnimationController> mMagnetizedStack;
+
+ /**
* The area that Bubbles will occupy after all animations end. This is used to move other
* floating content out of the way proactively.
*/
@@ -108,8 +119,11 @@ public class StackAnimationController extends
/** Whether or not the stack's start position has been set. */
private boolean mStackMovedToStartPosition = false;
- /** The most recent position in which the stack was resting on the edge of the screen. */
- @Nullable private PointF mRestingStackPosition;
+ /**
+ * The stack's most recent position along the edge of the screen. This is saved when the last
+ * bubble is removed, so that the stack can be restored in its previous position.
+ */
+ private PointF mRestingStackPosition;
/** The height of the most recently visible IME. */
private float mImeHeight = 0f;
@@ -136,11 +150,6 @@ public class StackAnimationController extends
private boolean mIsMovingFromFlinging = false;
/**
- * Whether the stack is within the dismiss target (either by being dragged, magnet'd, or flung).
- */
- private boolean mWithinDismissTarget = false;
-
- /**
* Whether the first bubble is springing towards the touch point, rather than using the default
* behavior of moving directly to the touch point with the rest of the stack following it.
*
@@ -154,6 +163,14 @@ public class StackAnimationController extends
*/
private boolean mFirstBubbleSpringingToTouch = false;
+ /**
+ * Whether to spring the stack to the next touch event coordinates. This is used to animate the
+ * stack (including the first bubble) out of the magnetic dismiss target to the touch location.
+ * Once it 'catches up' and the animation ends, we'll revert to moving the first bubble directly
+ * and only animating the following bubbles.
+ */
+ private boolean mSpringToTouchOnNextMotionEvent = false;
+
/** Horizontal offset of bubbles in the stack. */
private float mStackOffset;
/** Diameter of the bubble icon. */
@@ -273,7 +290,8 @@ public class StackAnimationController extends
* Note that we need new SpringForce instances per animation despite identical configs because
* SpringAnimation uses SpringForce's internal (changing) velocity while the animation runs.
*/
- public void springStack(float destinationX, float destinationY, float stiffness) {
+ public void springStack(
+ float destinationX, float destinationY, float stiffness) {
notifyFloatingCoordinatorStackAnimatingTo(destinationX, destinationY);
springFirstBubbleWithStackFollowing(DynamicAnimation.TRANSLATION_X,
@@ -404,7 +422,7 @@ public class StackAnimationController extends
pw.println(mRestingStackPosition != null ? mRestingStackPosition.toString() : "null");
pw.print(" currentStackPos: "); pw.println(mStackPosition.toString());
pw.print(" isMovingFromFlinging: "); pw.println(mIsMovingFromFlinging);
- pw.print(" withinDismiss: "); pw.println(mWithinDismissTarget);
+ pw.print(" withinDismiss: "); pw.println(isStackStuckToTarget());
pw.print(" firstBubbleSpringing: "); pw.println(mFirstBubbleSpringingToTouch);
}
@@ -451,7 +469,6 @@ public class StackAnimationController extends
.addEndListener((animation, canceled, endValue, endVelocity) -> {
if (!canceled) {
- mRestingStackPosition = new PointF();
mRestingStackPosition.set(mStackPosition);
springFirstBubbleWithStackFollowing(property, spring, endVelocity,
@@ -487,8 +504,10 @@ public class StackAnimationController extends
/**
* Animates the stack either away from the newly visible IME, or back to its original position
* due to the IME going away.
+ *
+ * @return The destination Y value of the stack due to the IME movement.
*/
- public void animateForImeVisibility(boolean imeVisible) {
+ public float animateForImeVisibility(boolean imeVisible) {
final float maxBubbleY = getAllowableStackPositionRegion().bottom;
float destinationY = Float.MIN_VALUE;
@@ -509,12 +528,14 @@ public class StackAnimationController extends
springFirstBubbleWithStackFollowing(
DynamicAnimation.TRANSLATION_Y,
getSpringForce(DynamicAnimation.TRANSLATION_Y, /* view */ null)
- .setStiffness(SpringForce.STIFFNESS_LOW),
+ .setStiffness(IME_ANIMATION_STIFFNESS),
/* startVel */ 0f,
destinationY);
notifyFloatingCoordinatorStackAnimatingTo(mStackPosition.x, destinationY);
}
+
+ return destinationY;
}
/**
@@ -569,7 +590,7 @@ public class StackAnimationController extends
- mBubblePaddingTop
- (mImeHeight > Float.MIN_VALUE ? mImeHeight + mBubblePaddingTop : 0f)
- Math.max(
- insets.getSystemWindowInsetBottom(),
+ insets.getStableInsetBottom(),
insets.getDisplayCutout() != null
? insets.getDisplayCutout().getSafeInsetBottom()
: 0);
@@ -580,14 +601,18 @@ public class StackAnimationController extends
/** Moves the stack in response to a touch event. */
public void moveStackFromTouch(float x, float y) {
-
- // If we're springing to the touch point to 'catch up' after dragging out of the dismiss
- // target, then update the stack position animations instead of moving the bubble directly.
- if (mFirstBubbleSpringingToTouch) {
+ // Begin the spring-to-touch catch up animation if needed.
+ if (mSpringToTouchOnNextMotionEvent) {
+ springStack(x, y, DEFAULT_STIFFNESS);
+ mSpringToTouchOnNextMotionEvent = false;
+ mFirstBubbleSpringingToTouch = true;
+ } else if (mFirstBubbleSpringingToTouch) {
final SpringAnimation springToTouchX =
- (SpringAnimation) mStackPositionAnimations.get(DynamicAnimation.TRANSLATION_X);
+ (SpringAnimation) mStackPositionAnimations.get(
+ DynamicAnimation.TRANSLATION_X);
final SpringAnimation springToTouchY =
- (SpringAnimation) mStackPositionAnimations.get(DynamicAnimation.TRANSLATION_Y);
+ (SpringAnimation) mStackPositionAnimations.get(
+ DynamicAnimation.TRANSLATION_Y);
// If either animation is still running, we haven't caught up. Update the animations.
if (springToTouchX.isRunning() || springToTouchY.isRunning()) {
@@ -600,56 +625,14 @@ public class StackAnimationController extends
}
}
- if (!mFirstBubbleSpringingToTouch && !mWithinDismissTarget) {
+ if (!mFirstBubbleSpringingToTouch && !isStackStuckToTarget()) {
moveFirstBubbleWithStackFollowing(x, y);
}
}
- /**
- * Demagnetizes the stack, springing it towards the given point. This also sets flags so that
- * subsequent touch events will update the final position of the demagnetization spring instead
- * of directly moving the bubbles, until demagnetization is complete.
- */
- public void demagnetizeFromDismissToPoint(float x, float y, float velX, float velY) {
- mWithinDismissTarget = false;
- mFirstBubbleSpringingToTouch = true;
-
- springFirstBubbleWithStackFollowing(
- DynamicAnimation.TRANSLATION_X,
- new SpringForce()
- .setDampingRatio(DEFAULT_BOUNCINESS)
- .setStiffness(DEFAULT_STIFFNESS),
- velX, x);
-
- springFirstBubbleWithStackFollowing(
- DynamicAnimation.TRANSLATION_Y,
- new SpringForce()
- .setDampingRatio(DEFAULT_BOUNCINESS)
- .setStiffness(DEFAULT_STIFFNESS),
- velY, y);
- }
-
- /**
- * Spring the stack towards the dismiss target, respecting existing velocity. This also sets
- * flags so that subsequent touch events will not move the stack until it's demagnetized.
- */
- public void magnetToDismiss(float velX, float velY, float destY, Runnable after) {
- mWithinDismissTarget = true;
- mFirstBubbleSpringingToTouch = false;
-
- springFirstBubbleWithStackFollowing(
- DynamicAnimation.TRANSLATION_X,
- new SpringForce()
- .setDampingRatio(SpringForce.DAMPING_RATIO_LOW_BOUNCY)
- .setStiffness(SpringForce.STIFFNESS_MEDIUM),
- velX, mLayout.getWidth() / 2f - mBubbleBitmapSize / 2f);
-
- springFirstBubbleWithStackFollowing(
- DynamicAnimation.TRANSLATION_Y,
- new SpringForce()
- .setDampingRatio(SpringForce.DAMPING_RATIO_LOW_BOUNCY)
- .setStiffness(SpringForce.STIFFNESS_MEDIUM),
- velY, destY, after);
+ /** Notify the controller that the stack has been unstuck from the dismiss target. */
+ public void onUnstuckFromTarget() {
+ mSpringToTouchOnNextMotionEvent = true;
}
/**
@@ -663,13 +646,7 @@ public class StackAnimationController extends
.alpha(0f)
.withDampingRatio(SpringForce.DAMPING_RATIO_NO_BOUNCY)
.withStiffness(SpringForce.STIFFNESS_HIGH)
- .start(() -> {
- // Run the callback and reset flags. The child translation animations might
- // still be running, but that's fine. Once the alpha is at 0f they're no longer
- // visible anyway.
- after.run();
- mWithinDismissTarget = false;
- });
+ .start(after);
}
/**
@@ -720,7 +697,7 @@ public class StackAnimationController extends
if (property.equals(DynamicAnimation.TRANSLATION_X)
|| property.equals(DynamicAnimation.TRANSLATION_Y)) {
return index + 1;
- } else if (mWithinDismissTarget) {
+ } else if (isStackStuckToTarget()) {
return index + 1; // Chain all animations in dismiss (scale, alpha, etc. are used).
} else {
return NONE;
@@ -733,7 +710,7 @@ public class StackAnimationController extends
if (property.equals(DynamicAnimation.TRANSLATION_X)) {
// If we're in the dismiss target, have the bubbles pile on top of each other with no
// offset.
- if (mWithinDismissTarget) {
+ if (isStackStuckToTarget()) {
return 0f;
} else {
// Offset to the left if we're on the left, or the right otherwise.
@@ -755,7 +732,7 @@ public class StackAnimationController extends
@Override
void onChildAdded(View child, int index) {
// Don't animate additions within the dismiss target.
- if (mWithinDismissTarget) {
+ if (isStackStuckToTarget()) {
return;
}
@@ -784,8 +761,6 @@ public class StackAnimationController extends
if (mLayout.getChildCount() > 0) {
animationForChildAtIndex(0).translationX(mStackPosition.x).start();
} else {
- // If there's no other bubbles, and we were in the dismiss target, reset the flag.
- mWithinDismissTarget = false;
// When all children are removed ensure stack position is sane
setStackPosition(mRestingStackPosition == null
? getDefaultStartPosition()
@@ -831,6 +806,9 @@ public class StackAnimationController extends
}
}
+ private boolean isStackStuckToTarget() {
+ return mMagnetizedStack != null && mMagnetizedStack.getObjectStuckToTarget();
+ }
/** Moves the stack, without any animation, to the starting position. */
private void moveStackToStartPosition() {
@@ -882,7 +860,12 @@ public class StackAnimationController extends
public void setStackPosition(PointF pos) {
Log.d(TAG, String.format("Setting position to (%f, %f).", pos.x, pos.y));
mStackPosition.set(pos.x, pos.y);
- mRestingStackPosition = mStackPosition;
+
+ if (mRestingStackPosition == null) {
+ mRestingStackPosition = new PointF();
+ }
+
+ mRestingStackPosition.set(mStackPosition);
// If we're not the active controller, we don't want to physically move the bubble views.
if (isActiveController()) {
@@ -959,6 +942,44 @@ public class StackAnimationController extends
}
/**
+ * Returns the {@link MagnetizedObject} instance for the bubble stack, with the provided
+ * {@link MagnetizedObject.MagneticTarget} added as a target.
+ */
+ public MagnetizedObject<StackAnimationController> getMagnetizedStack(
+ MagnetizedObject.MagneticTarget target) {
+ if (mMagnetizedStack == null) {
+ mMagnetizedStack = new MagnetizedObject<StackAnimationController>(
+ mLayout.getContext(),
+ this,
+ new StackPositionProperty(DynamicAnimation.TRANSLATION_X),
+ new StackPositionProperty(DynamicAnimation.TRANSLATION_Y)
+ ) {
+ @Override
+ public float getWidth(@NonNull StackAnimationController underlyingObject) {
+ return mBubbleSize;
+ }
+
+ @Override
+ public float getHeight(@NonNull StackAnimationController underlyingObject) {
+ return mBubbleSize;
+ }
+
+ @Override
+ public void getLocationOnScreen(@NonNull StackAnimationController underlyingObject,
+ @NonNull int[] loc) {
+ loc[0] = (int) mStackPosition.x;
+ loc[1] = (int) mStackPosition.y;
+ }
+ };
+ mMagnetizedStack.addTarget(target);
+ mMagnetizedStack.setHapticsEnabled(true);
+ mMagnetizedStack.setFlingToTargetMinVelocity(FLING_TO_DISMISS_MIN_VELOCITY);
+ }
+
+ return mMagnetizedStack;
+ }
+
+ /**
* FloatProperty that uses {@link #moveFirstBubbleWithStackFollowing} to set the first bubble's
* translation and animate the rest of the stack with it. A DynamicAnimation can animate this
* property directly to move the first bubble and cause the stack to 'follow' to the new
diff --git a/packages/SystemUI/src/com/android/systemui/controls/ControlStatus.kt b/packages/SystemUI/src/com/android/systemui/controls/ControlStatus.kt
index 49a16d892ef4..dec60073a55e 100644
--- a/packages/SystemUI/src/com/android/systemui/controls/ControlStatus.kt
+++ b/packages/SystemUI/src/com/android/systemui/controls/ControlStatus.kt
@@ -16,10 +16,12 @@
package com.android.systemui.controls
+import android.content.ComponentName
import android.service.controls.Control
data class ControlStatus(
val control: Control,
+ val component: ComponentName,
var favorite: Boolean,
val removed: Boolean = false
-) \ No newline at end of file
+)
diff --git a/packages/SystemUI/src/com/android/systemui/controls/controller/ControlsController.kt b/packages/SystemUI/src/com/android/systemui/controls/controller/ControlsController.kt
index f2881d41574c..7eafe2e65cca 100644
--- a/packages/SystemUI/src/com/android/systemui/controls/controller/ControlsController.kt
+++ b/packages/SystemUI/src/com/android/systemui/controls/controller/ControlsController.kt
@@ -124,6 +124,18 @@ interface ControlsController : UserAwareController {
fun getFavoritesForComponent(componentName: ComponentName): List<StructureInfo>
/**
+ * Adds a single favorite to a given component and structure
+ * @param componentName the name of the service that provides the [Control]
+ * @param structureName the name of the structure that holds the [Control]
+ * @param controlInfo persistent information about the [Control] to be added.
+ */
+ fun addFavorite(
+ componentName: ComponentName,
+ structureName: CharSequence,
+ controlInfo: ControlInfo
+ )
+
+ /**
* Replaces the favorites for the given structure.
*
* Calling this method will eliminate the previous selection of favorites and replace it with a
diff --git a/packages/SystemUI/src/com/android/systemui/controls/controller/ControlsControllerImpl.kt b/packages/SystemUI/src/com/android/systemui/controls/controller/ControlsControllerImpl.kt
index dedd341a46be..989b7cf2423b 100644
--- a/packages/SystemUI/src/com/android/systemui/controls/controller/ControlsControllerImpl.kt
+++ b/packages/SystemUI/src/com/android/systemui/controls/controller/ControlsControllerImpl.kt
@@ -125,14 +125,19 @@ class ControlsControllerImpl @Inject constructor (
@VisibleForTesting
internal val settingObserver = object : ContentObserver(null) {
- override fun onChange(selfChange: Boolean, uri: Uri, userId: Int) {
+ override fun onChange(
+ selfChange: Boolean,
+ uris: MutableIterable<Uri>,
+ flags: Int,
+ userId: Int
+ ) {
// Do not listen to changes in the middle of user change, those will be read by the
// user-switch receiver.
if (userChanging || userId != currentUserId) {
return
}
available = Settings.Secure.getIntForUser(contentResolver, CONTROLS_AVAILABLE,
- DEFAULT_ENABLED, currentUserId) != 0
+ DEFAULT_ENABLED, currentUserId) != 0
resetFavorites(available)
}
}
@@ -233,7 +238,11 @@ class ControlsControllerImpl @Inject constructor (
}
val removed = findRemoved(favoritesForComponentKeys.toSet(), controls)
val controlsWithFavorite = controls.map {
- ControlStatus(it, it.controlId in favoritesForComponentKeys)
+ ControlStatus(
+ it,
+ componentName,
+ it.controlId in favoritesForComponentKeys
+ )
}
val loadData = createLoadDataObject(
Favorites.getControlsForComponent(componentName)
@@ -248,17 +257,21 @@ class ControlsControllerImpl @Inject constructor (
}
override fun error(message: String) {
- val loadData = Favorites.getControlsForComponent(componentName).let {
- controls ->
+ executor.execute {
+ val loadData = Favorites.getControlsForComponent(componentName)
+ .let { controls ->
val keys = controls.map { it.controlId }
createLoadDataObject(
- controls.map { createRemovedStatus(componentName, it, false) },
- keys,
- true
+ controls.map {
+ createRemovedStatus(componentName, it, false)
+ },
+ keys,
+ true
)
- }
+ }
- dataCallback.accept(loadData)
+ dataCallback.accept(loadData)
+ }
}
}
)
@@ -281,7 +294,7 @@ class ControlsControllerImpl @Inject constructor (
.setTitle(controlInfo.controlTitle)
.setDeviceType(controlInfo.deviceType)
.build()
- return ControlStatus(control, true, setRemoved)
+ return ControlStatus(control, componentName, true, setRemoved)
}
private fun findRemoved(favoriteKeys: Set<String>, list: List<Control>): Set<String> {
@@ -300,6 +313,19 @@ class ControlsControllerImpl @Inject constructor (
bindingController.unsubscribe()
}
+ override fun addFavorite(
+ componentName: ComponentName,
+ structureName: CharSequence,
+ controlInfo: ControlInfo
+ ) {
+ if (!confirmAvailability()) return
+ executor.execute {
+ if (Favorites.addFavorite(componentName, structureName, controlInfo)) {
+ persistenceWrapper.storeFavorites(Favorites.getAllStructures())
+ }
+ }
+ }
+
override fun replaceFavoritesForStructure(structureInfo: StructureInfo) {
if (!confirmAvailability()) return
executor.execute {
@@ -437,6 +463,24 @@ private object Favorites {
favMap = newFavMap
}
+ fun addFavorite(
+ componentName: ComponentName,
+ structureName: CharSequence,
+ controlInfo: ControlInfo
+ ): Boolean {
+ // Check if control is in favorites
+ if (getControlsForComponent(componentName)
+ .any { it.controlId == controlInfo.controlId }) {
+ return false
+ }
+ val structureInfo = favMap.get(componentName)
+ ?.firstOrNull { it.structure == structureName }
+ ?: StructureInfo(componentName, structureName, emptyList())
+ val newStructureInfo = structureInfo.copy(controls = structureInfo.controls + controlInfo)
+ replaceControls(newStructureInfo)
+ return true
+ }
+
fun replaceControls(updatedStructure: StructureInfo) {
val newFavMap = favMap.toMutableMap()
val structures = mutableListOf<StructureInfo>()
@@ -449,15 +493,17 @@ private object Favorites {
updatedStructure
} else { s }
- structures.add(newStructure)
+ if (!newStructure.controls.isEmpty()) {
+ structures.add(newStructure)
+ }
}
- if (!replaced) {
+ if (!replaced && !updatedStructure.controls.isEmpty()) {
structures.add(updatedStructure)
}
- newFavMap.put(componentName, structures.toList())
- favMap = newFavMap.toMap()
+ newFavMap.put(componentName, structures)
+ favMap = newFavMap
}
fun clear() {
diff --git a/packages/SystemUI/src/com/android/systemui/controls/dagger/ControlsModule.kt b/packages/SystemUI/src/com/android/systemui/controls/dagger/ControlsModule.kt
index 859311e8767c..946a2365585a 100644
--- a/packages/SystemUI/src/com/android/systemui/controls/dagger/ControlsModule.kt
+++ b/packages/SystemUI/src/com/android/systemui/controls/dagger/ControlsModule.kt
@@ -26,6 +26,7 @@ import com.android.systemui.controls.management.ControlsFavoritingActivity
import com.android.systemui.controls.management.ControlsListingController
import com.android.systemui.controls.management.ControlsListingControllerImpl
import com.android.systemui.controls.management.ControlsProviderSelectorActivity
+import com.android.systemui.controls.management.ControlsRequestDialog
import com.android.systemui.controls.ui.ControlsUiController
import com.android.systemui.controls.ui.ControlsUiControllerImpl
import dagger.Binds
@@ -69,4 +70,11 @@ abstract class ControlsModule {
abstract fun provideControlsFavoritingActivity(
activity: ControlsFavoritingActivity
): Activity
+
+ @Binds
+ @IntoMap
+ @ClassKey(ControlsRequestDialog::class)
+ abstract fun provideControlsRequestDialog(
+ activity: ControlsRequestDialog
+ ): Activity
} \ No newline at end of file
diff --git a/packages/SystemUI/src/com/android/systemui/controls/management/AllModel.kt b/packages/SystemUI/src/com/android/systemui/controls/management/AllModel.kt
index c05351795aed..01f906958fc1 100644
--- a/packages/SystemUI/src/com/android/systemui/controls/management/AllModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/controls/management/AllModel.kt
@@ -22,14 +22,20 @@ import com.android.systemui.controls.ControlStatus
import com.android.systemui.controls.controller.ControlInfo
/**
- * This model is used to show all controls separated by zones.
+ * This model is used to show controls separated by zones.
*
* The model will sort the controls and zones in the following manner:
* * The zones will be sorted in a first seen basis
* * The controls in each zone will be sorted in a first seen basis.
*
- * @property controls List of all controls as returned by loading
- * @property initialFavoriteIds sorted ids of favorite controls
+ * The controls passed should belong to the same structure, as an instance of this model will be
+ * created for each structure.
+ *
+ * The list of favorite ids can contain ids for controls not passed to this model. Those will be
+ * filtered out.
+ *
+ * @property controls List of controls as returned by loading
+ * @property initialFavoriteIds sorted ids of favorite controls.
* @property noZoneString text to use as header for all controls that have blank or `null` zone.
*/
class AllModel(
@@ -50,7 +56,10 @@ class AllModel(
}
}
- private val favoriteIds = initialFavoriteIds.toMutableList()
+ private val favoriteIds = run {
+ val ids = controls.mapTo(HashSet()) { it.control.controlId }
+ initialFavoriteIds.filter { it in ids }.toMutableList()
+ }
override val elements: List<ElementWrapper> = createWrappers(controls)
diff --git a/packages/SystemUI/src/com/android/systemui/controls/management/ControlAdapter.kt b/packages/SystemUI/src/com/android/systemui/controls/management/ControlAdapter.kt
index e87cf74401bf..563c2f677801 100644
--- a/packages/SystemUI/src/com/android/systemui/controls/management/ControlAdapter.kt
+++ b/packages/SystemUI/src/com/android/systemui/controls/management/ControlAdapter.kt
@@ -16,8 +16,8 @@
package com.android.systemui.controls.management
+import android.content.ComponentName
import android.graphics.Rect
-import android.graphics.drawable.Icon
import android.service.controls.DeviceTypes
import android.view.LayoutInflater
import android.view.View
@@ -42,7 +42,7 @@ private typealias ModelFavoriteChanger = (String, Boolean) -> Unit
* @param onlyFavorites set to true to only display favorites instead of all controls
*/
class ControlAdapter(
- private val layoutInflater: LayoutInflater
+ private val elevation: Float
) : RecyclerView.Adapter<Holder>() {
companion object {
@@ -59,6 +59,7 @@ class ControlAdapter(
private var model: ControlsModel? = null
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): Holder {
+ val layoutInflater = LayoutInflater.from(parent.context)
return when (viewType) {
TYPE_CONTROL -> {
ControlHolder(
@@ -66,7 +67,7 @@ class ControlAdapter(
layoutParams.apply {
width = ViewGroup.LayoutParams.MATCH_PARENT
}
- elevation = 15f
+ elevation = this@ControlAdapter.elevation
}
) { id, favorite ->
model?.changeFavoriteStatus(id, favorite)
@@ -146,7 +147,7 @@ private class ControlHolder(view: View, val favoriteCallback: ModelFavoriteChang
override fun bindData(wrapper: ElementWrapper) {
wrapper as ControlWrapper
val data = wrapper.controlStatus
- val renderInfo = getRenderInfo(data.control.deviceType)
+ val renderInfo = getRenderInfo(data.component, data.control.deviceType)
title.text = data.control.title
subtitle.text = data.control.subtitle
favorite.isChecked = data.favorite
@@ -159,16 +160,17 @@ private class ControlHolder(view: View, val favoriteCallback: ModelFavoriteChang
}
private fun getRenderInfo(
+ component: ComponentName,
@DeviceTypes.DeviceType deviceType: Int
): RenderInfo {
- return RenderInfo.lookup(deviceType, true)
+ return RenderInfo.lookup(itemView.context, component, deviceType, true)
}
private fun applyRenderInfo(ri: RenderInfo) {
val context = itemView.context
val fg = context.getResources().getColorStateList(ri.foreground, context.getTheme())
- icon.setImageIcon(Icon.createWithResource(context, ri.iconResourceId))
+ icon.setImageDrawable(ri.icon)
icon.setImageTintList(fg)
}
}
@@ -190,4 +192,4 @@ class MarginItemDecorator(
right = sideMargins
}
}
-} \ No newline at end of file
+}
diff --git a/packages/SystemUI/src/com/android/systemui/controls/management/ControlsFavoritingActivity.kt b/packages/SystemUI/src/com/android/systemui/controls/management/ControlsFavoritingActivity.kt
index 08a1a5000112..04715abe5f99 100644
--- a/packages/SystemUI/src/com/android/systemui/controls/management/ControlsFavoritingActivity.kt
+++ b/packages/SystemUI/src/com/android/systemui/controls/management/ControlsFavoritingActivity.kt
@@ -19,20 +19,24 @@ package com.android.systemui.controls.management
import android.app.Activity
import android.content.ComponentName
import android.content.Intent
+import android.graphics.drawable.Drawable
import android.os.Bundle
-import android.view.LayoutInflater
+import android.text.TextUtils
import android.view.View
import android.view.ViewStub
import android.widget.Button
+import android.widget.ImageView
import android.widget.TextView
-import androidx.recyclerview.widget.GridLayoutManager
-import androidx.recyclerview.widget.RecyclerView
+import androidx.viewpager2.widget.ViewPager2
import com.android.systemui.R
import com.android.systemui.broadcast.BroadcastDispatcher
-import com.android.systemui.controls.controller.StructureInfo
+import com.android.systemui.controls.ControlsServiceInfo
import com.android.systemui.controls.controller.ControlsControllerImpl
+import com.android.systemui.controls.controller.StructureInfo
import com.android.systemui.dagger.qualifiers.Main
+import com.android.systemui.qs.PageIndicator
import com.android.systemui.settings.CurrentUserTracker
+import java.text.Collator
import java.util.concurrent.Executor
import java.util.function.Consumer
import javax.inject.Inject
@@ -40,6 +44,7 @@ import javax.inject.Inject
class ControlsFavoritingActivity @Inject constructor(
@Main private val executor: Executor,
private val controller: ControlsControllerImpl,
+ private val listingController: ControlsListingController,
broadcastDispatcher: BroadcastDispatcher
) : Activity() {
@@ -48,12 +53,18 @@ class ControlsFavoritingActivity @Inject constructor(
const val EXTRA_APP = "extra_app_label"
}
- private lateinit var recyclerViewAll: RecyclerView
- private lateinit var adapterAll: ControlAdapter
- private lateinit var statusText: TextView
- private var model: ControlsModel? = null
private var component: ComponentName? = null
- private var structureName: CharSequence = ""
+ private var appName: CharSequence? = null
+
+ private lateinit var structurePager: ViewPager2
+ private lateinit var statusText: TextView
+ private lateinit var titleView: TextView
+ private lateinit var iconView: ImageView
+ private lateinit var iconFrame: View
+ private lateinit var pageIndicator: PageIndicator
+ private var listOfStructures = emptyList<StructureContainer>()
+
+ private lateinit var comparator: Comparator<StructureContainer>
private val currentUserTracker = object : CurrentUserTracker(broadcastDispatcher) {
private val startingUser = controller.currentUserId
@@ -66,95 +77,141 @@ class ControlsFavoritingActivity @Inject constructor(
}
}
+ private val listingCallback = object : ControlsListingController.ControlsListingCallback {
+ private var icon: Drawable? = null
+
+ override fun onServicesUpdated(serviceInfos: List<ControlsServiceInfo>) {
+ val newIcon = serviceInfos.firstOrNull { it.componentName == component }?.loadIcon()
+ if (icon == newIcon) return
+ icon = newIcon
+ executor.execute {
+ if (icon != null) {
+ iconView.setImageDrawable(icon)
+ }
+ iconFrame.visibility = if (icon != null) View.VISIBLE else View.GONE
+ }
+ }
+ }
+
override fun onBackPressed() {
finish()
}
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
- setContentView(R.layout.controls_management)
- requireViewById<ViewStub>(R.id.stub).apply {
- layoutResource = R.layout.controls_management_favorites
- inflate()
- }
-
- val app = intent.getCharSequenceExtra(EXTRA_APP)
+ val collator = Collator.getInstance(resources.configuration.locales[0])
+ comparator = compareBy(collator) { it.structureName }
+ appName = intent.getCharSequenceExtra(EXTRA_APP)
component = intent.getParcelableExtra<ComponentName>(Intent.EXTRA_COMPONENT_NAME)
- statusText = requireViewById(R.id.status_message)
- setUpRecyclerView()
+ bindViews()
- requireViewById<TextView>(R.id.title).text = app?.let { it }
- ?: resources.getText(R.string.controls_favorite_default_title)
- requireViewById<TextView>(R.id.subtitle).text =
- resources.getText(R.string.controls_favorite_subtitle)
+ setUpPager()
- requireViewById<Button>(R.id.other_apps).apply {
- visibility = View.VISIBLE
- setOnClickListener {
- this@ControlsFavoritingActivity.onBackPressed()
- }
- }
+ loadControls()
- requireViewById<Button>(R.id.done).setOnClickListener {
- if (component == null) return@setOnClickListener
- val favoritesForStorage = model?.favorites?.map {
- it.build()
- }
- if (favoritesForStorage != null) {
- controller.replaceFavoritesForStructure(StructureInfo(component!!, structureName,
- favoritesForStorage))
- finishAffinity()
- }
- }
+ listingController.addCallback(listingCallback)
+
+ currentUserTracker.startTracking()
+ }
+ private fun loadControls() {
component?.let {
statusText.text = resources.getText(com.android.internal.R.string.loading)
+ val emptyZoneString = resources.getText(
+ R.string.controls_favorite_other_zone_header)
controller.loadForComponent(it, Consumer { data ->
val allControls = data.allControls
val favoriteKeys = data.favoritesIds
val error = data.errorOnLoad
- val structures = allControls.fold(hashSetOf<CharSequence>()) {
- s, c ->
- s.add(c.control.structure ?: "")
- s
- }
- // TODO add multi structure switching support
+ val controlsByStructure = allControls.groupBy { it.control.structure ?: "" }
+ listOfStructures = controlsByStructure.map {
+ StructureContainer(it.key, AllModel(it.value, favoriteKeys, emptyZoneString))
+ }.sortedWith(comparator)
executor.execute {
- val emptyZoneString = resources.getText(
- R.string.controls_favorite_other_zone_header)
- val model = AllModel(allControls, favoriteKeys, emptyZoneString)
- adapterAll.changeModel(model)
- this.model = model
+ structurePager.adapter = StructureAdapter(listOfStructures)
if (error) {
statusText.text = resources.getText(R.string.controls_favorite_load_error)
} else {
statusText.visibility = View.GONE
}
+ pageIndicator.setNumPages(listOfStructures.size)
+ pageIndicator.setLocation(0f)
+ pageIndicator.visibility =
+ if (listOfStructures.size > 1) View.VISIBLE else View.GONE
}
})
}
+ }
- currentUserTracker.startTracking()
+ private fun setUpPager() {
+ structurePager.apply {
+ adapter = StructureAdapter(emptyList())
+ registerOnPageChangeCallback(object : ViewPager2.OnPageChangeCallback() {
+ override fun onPageSelected(position: Int) {
+ super.onPageSelected(position)
+ val name = listOfStructures[position].structureName
+ titleView.text = if (!TextUtils.isEmpty(name)) name else appName
+ }
+
+ override fun onPageScrolled(
+ position: Int,
+ positionOffset: Float,
+ positionOffsetPixels: Int
+ ) {
+ super.onPageScrolled(position, positionOffset, positionOffsetPixels)
+ pageIndicator.setLocation(position + positionOffset)
+ }
+ })
+ }
+ }
+
+ private fun bindViews() {
+ setContentView(R.layout.controls_management)
+ requireViewById<ViewStub>(R.id.stub).apply {
+ layoutResource = R.layout.controls_management_favorites
+ inflate()
+ }
+
+ statusText = requireViewById(R.id.status_message)
+ pageIndicator = requireViewById(R.id.structure_page_indicator)
+
+ titleView = requireViewById<TextView>(R.id.title).apply {
+ text = appName ?: resources.getText(R.string.controls_favorite_default_title)
+ }
+ requireViewById<TextView>(R.id.subtitle).text =
+ resources.getText(R.string.controls_favorite_subtitle)
+ iconView = requireViewById(com.android.internal.R.id.icon)
+ iconFrame = requireViewById(R.id.icon_frame)
+ structurePager = requireViewById<ViewPager2>(R.id.structure_pager)
+ bindButtons()
}
- private fun setUpRecyclerView() {
- val margin = resources.getDimensionPixelSize(R.dimen.controls_card_margin)
- val itemDecorator = MarginItemDecorator(margin, margin)
- val layoutInflater = LayoutInflater.from(applicationContext)
+ private fun bindButtons() {
+ requireViewById<Button>(R.id.other_apps).apply {
+ visibility = View.VISIBLE
+ setOnClickListener {
+ this@ControlsFavoritingActivity.onBackPressed()
+ }
+ }
- adapterAll = ControlAdapter(layoutInflater)
- recyclerViewAll = requireViewById<RecyclerView>(R.id.listAll).apply {
- adapter = adapterAll
- layoutManager = GridLayoutManager(applicationContext, 2).apply {
- spanSizeLookup = adapterAll.spanSizeLookup
+ requireViewById<Button>(R.id.done).setOnClickListener {
+ if (component == null) return@setOnClickListener
+ listOfStructures.forEach {
+ val favoritesForStorage = it.model.favorites.map { it.build() }
+ controller.replaceFavoritesForStructure(StructureInfo(component!!, it.structureName,
+ favoritesForStorage))
}
- addItemDecoration(itemDecorator)
+
+ finishAffinity()
}
}
override fun onDestroy() {
currentUserTracker.stopTracking()
+ listingController.removeCallback(listingCallback)
super.onDestroy()
}
}
+
+data class StructureContainer(val structureName: CharSequence, val model: ControlsModel)
diff --git a/packages/SystemUI/src/com/android/systemui/controls/management/ControlsListingControllerImpl.kt b/packages/SystemUI/src/com/android/systemui/controls/management/ControlsListingControllerImpl.kt
index 9b108cf3e34b..94487e5a584a 100644
--- a/packages/SystemUI/src/com/android/systemui/controls/management/ControlsListingControllerImpl.kt
+++ b/packages/SystemUI/src/com/android/systemui/controls/management/ControlsListingControllerImpl.kt
@@ -88,6 +88,8 @@ class ControlsListingControllerImpl @VisibleForTesting constructor(
init {
serviceListing.addCallback(serviceListingCallback)
+ serviceListing.setListening(true)
+ serviceListing.reload()
}
override fun changeUser(newUser: UserHandle) {
@@ -95,11 +97,12 @@ class ControlsListingControllerImpl @VisibleForTesting constructor(
callbacks.clear()
availableServices = emptyList()
serviceListing.setListening(false)
- serviceListing.removeCallback(serviceListingCallback)
currentUserId = newUser.identifier
val contextForUser = context.createContextAsUser(newUser, 0)
serviceListing = serviceListingBuilder(contextForUser)
serviceListing.addCallback(serviceListingCallback)
+ serviceListing.setListening(true)
+ serviceListing.reload()
}
}
@@ -118,12 +121,7 @@ class ControlsListingControllerImpl @VisibleForTesting constructor(
backgroundExecutor.execute {
Log.d(TAG, "Subscribing callback")
callbacks.add(listener)
- if (callbacks.size == 1) {
- serviceListing.setListening(true)
- serviceListing.reload()
- } else {
- listener.onServicesUpdated(getCurrentServices())
- }
+ listener.onServicesUpdated(getCurrentServices())
}
}
@@ -136,9 +134,6 @@ class ControlsListingControllerImpl @VisibleForTesting constructor(
backgroundExecutor.execute {
Log.d(TAG, "Unsubscribing callback")
callbacks.remove(listener)
- if (callbacks.size == 0) {
- serviceListing.setListening(false)
- }
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/controls/management/ControlsRequestDialog.kt b/packages/SystemUI/src/com/android/systemui/controls/management/ControlsRequestDialog.kt
new file mode 100644
index 000000000000..a7fc2ac80070
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/controls/management/ControlsRequestDialog.kt
@@ -0,0 +1,177 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.controls.management
+
+import android.app.AlertDialog
+import android.app.Dialog
+import android.content.ComponentName
+import android.content.DialogInterface
+import android.content.Intent
+import android.os.Bundle
+import android.os.UserHandle
+import android.service.controls.Control
+import android.service.controls.ControlsProviderService
+import android.util.Log
+import android.view.LayoutInflater
+import android.view.View
+import android.widget.ImageView
+import android.widget.TextView
+import com.android.systemui.R
+import com.android.systemui.broadcast.BroadcastDispatcher
+import com.android.systemui.controls.ControlsServiceInfo
+import com.android.systemui.controls.controller.ControlInfo
+import com.android.systemui.controls.controller.ControlsController
+import com.android.systemui.controls.ui.RenderInfo
+import com.android.systemui.settings.CurrentUserTracker
+import com.android.systemui.statusbar.phone.SystemUIDialog
+import com.android.systemui.util.LifecycleActivity
+import javax.inject.Inject
+
+class ControlsRequestDialog @Inject constructor(
+ private val controller: ControlsController,
+ private val broadcastDispatcher: BroadcastDispatcher,
+ private val controlsListingController: ControlsListingController
+) : LifecycleActivity(), DialogInterface.OnClickListener, DialogInterface.OnCancelListener {
+
+ companion object {
+ private const val TAG = "ControlsRequestDialog"
+ }
+
+ private lateinit var component: ComponentName
+ private lateinit var control: Control
+ private var dialog: Dialog? = null
+ private val callback = object : ControlsListingController.ControlsListingCallback {
+ override fun onServicesUpdated(candidates: List<ControlsServiceInfo>) {}
+ }
+
+ private val currentUserTracker = object : CurrentUserTracker(broadcastDispatcher) {
+ private val startingUser = controller.currentUserId
+
+ override fun onUserSwitched(newUserId: Int) {
+ if (newUserId != startingUser) {
+ stopTracking()
+ finish()
+ }
+ }
+ }
+
+ override fun onCreate(savedInstanceState: Bundle?) {
+ super.onCreate(savedInstanceState)
+ if (!controller.available) {
+ Log.w(TAG, "Quick Controls not available for this user ")
+ finish()
+ }
+ currentUserTracker.startTracking()
+ controlsListingController.addCallback(callback)
+
+ val requestUser = intent.getIntExtra(Intent.EXTRA_USER_ID, UserHandle.USER_NULL)
+ val currentUser = controller.currentUserId
+
+ if (requestUser != currentUser) {
+ Log.w(TAG, "Current user ($currentUser) different from request user ($requestUser)")
+ finish()
+ }
+
+ component = intent.getParcelableExtra(Intent.EXTRA_COMPONENT_NAME) ?: run {
+ Log.e(TAG, "Request did not contain componentName")
+ finish()
+ return
+ }
+
+ control = intent.getParcelableExtra(ControlsProviderService.EXTRA_CONTROL) ?: run {
+ Log.e(TAG, "Request did not contain control")
+ finish()
+ return
+ }
+ }
+
+ override fun onResume() {
+ super.onResume()
+ val label = verifyComponentAndGetLabel()
+ if (label == null) {
+ Log.e(TAG, "The component specified (${component.flattenToString()} " +
+ "is not a valid ControlsProviderService")
+ finish()
+ return
+ }
+
+ if (isCurrentFavorite()) {
+ Log.w(TAG, "The control ${control.title} is already a favorite")
+ finish()
+ }
+
+ dialog = createDialog(label)
+
+ dialog?.show()
+ }
+
+ override fun onDestroy() {
+ dialog?.dismiss()
+ currentUserTracker.stopTracking()
+ controlsListingController.removeCallback(callback)
+ super.onDestroy()
+ }
+
+ private fun verifyComponentAndGetLabel(): CharSequence? {
+ return controlsListingController.getAppLabel(component)
+ }
+
+ private fun isCurrentFavorite(): Boolean {
+ val favorites = controller.getFavoritesForComponent(component)
+ return favorites.any { it.controls.any { it.controlId == control.controlId } }
+ }
+
+ fun createDialog(label: CharSequence): Dialog {
+ val renderInfo = RenderInfo.lookup(this, component, control.deviceType, true)
+ val frame = LayoutInflater.from(this).inflate(R.layout.controls_dialog, null).apply {
+ requireViewById<ImageView>(R.id.icon).apply {
+ setImageDrawable(renderInfo.icon)
+ setImageTintList(
+ context.resources.getColorStateList(renderInfo.foreground, context.theme))
+ }
+ requireViewById<TextView>(R.id.title).text = control.title
+ requireViewById<TextView>(R.id.subtitle).text = control.subtitle
+ requireViewById<View>(R.id.control).elevation =
+ resources.getFloat(R.dimen.control_card_elevation)
+ }
+
+ val dialog = AlertDialog.Builder(this)
+ .setTitle(getString(R.string.controls_dialog_title))
+ .setMessage(getString(R.string.controls_dialog_message, label))
+ .setPositiveButton(R.string.controls_dialog_ok, this)
+ .setNegativeButton(android.R.string.cancel, this)
+ .setOnCancelListener(this)
+ .setView(frame)
+ .create()
+
+ SystemUIDialog.registerDismissListener(dialog)
+ dialog.setCanceledOnTouchOutside(true)
+ return dialog
+ }
+
+ override fun onCancel(dialog: DialogInterface?) {
+ finish()
+ }
+
+ override fun onClick(dialog: DialogInterface?, which: Int) {
+ if (which == Dialog.BUTTON_POSITIVE) {
+ controller.addFavorite(componentName, control.structure ?: "",
+ ControlInfo(control.controlId, control.title, control.deviceType))
+ }
+ finish()
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/controls/management/ControlsRequestReceiver.kt b/packages/SystemUI/src/com/android/systemui/controls/management/ControlsRequestReceiver.kt
new file mode 100644
index 000000000000..5c30b5a5bf45
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/controls/management/ControlsRequestReceiver.kt
@@ -0,0 +1,78 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.controls.management
+
+import android.app.ActivityManager
+import android.app.ActivityManager.RunningAppProcessInfo.IMPORTANCE_FOREGROUND
+import android.app.ActivityManager.RunningAppProcessInfo.IMPORTANCE_GONE
+import android.content.BroadcastReceiver
+import android.content.ComponentName
+import android.content.Context
+import android.content.Intent
+import android.content.pm.PackageManager
+import android.os.UserHandle
+import android.service.controls.Control
+import android.service.controls.ControlsProviderService
+import android.util.Log
+
+/**
+ * Proxy to launch in user 0
+ */
+class ControlsRequestReceiver : BroadcastReceiver() {
+
+ companion object {
+ private const val TAG = "ControlsRequestReceiver"
+
+ fun isPackageInForeground(context: Context, packageName: String): Boolean {
+ val uid = try {
+ context.packageManager.getPackageUid(packageName, 0)
+ } catch (_: PackageManager.NameNotFoundException) {
+ Log.w(TAG, "Package $packageName not found")
+ return false
+ }
+
+ val am = context.getSystemService(ActivityManager::class.java)
+ if ((am?.getUidImportance(uid) ?: IMPORTANCE_GONE) != IMPORTANCE_FOREGROUND) {
+ Log.w(TAG, "Uid $uid not in foreground")
+ return false
+ }
+ return true
+ }
+ }
+
+ override fun onReceive(context: Context, intent: Intent) {
+
+ val packageName = intent.getParcelableExtra<ComponentName>(Intent.EXTRA_COMPONENT_NAME)
+ ?.packageName
+
+ if (packageName == null || !isPackageInForeground(context, packageName)) {
+ return
+ }
+
+ val activityIntent = Intent(context, ControlsRequestDialog::class.java).apply {
+ Intent.EXTRA_COMPONENT_NAME.let {
+ putExtra(it, intent.getParcelableExtra<ComponentName>(it))
+ }
+ ControlsProviderService.EXTRA_CONTROL.let {
+ putExtra(it, intent.getParcelableExtra<Control>(it))
+ }
+ }
+ activityIntent.putExtra(Intent.EXTRA_USER_ID, context.userId)
+
+ context.startActivityAsUser(activityIntent, UserHandle.SYSTEM)
+ }
+} \ No newline at end of file
diff --git a/packages/SystemUI/src/com/android/systemui/controls/management/ManagementPageIndicator.kt b/packages/SystemUI/src/com/android/systemui/controls/management/ManagementPageIndicator.kt
new file mode 100644
index 000000000000..4289274cb3e4
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/controls/management/ManagementPageIndicator.kt
@@ -0,0 +1,43 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.controls.management
+
+import android.content.Context
+import android.util.AttributeSet
+import android.view.View
+import com.android.systemui.qs.PageIndicator
+
+/**
+ * Page indicator for management screens.
+ *
+ * Adds RTL support to [PageIndicator]. To be used with [ViewPager2].
+ */
+class ManagementPageIndicator(
+ context: Context,
+ attrs: AttributeSet
+) : PageIndicator(context, attrs) {
+
+ override fun setLocation(location: Float) {
+ // Location doesn't know about RTL
+ if (layoutDirection == View.LAYOUT_DIRECTION_RTL) {
+ val numPages = childCount
+ super.setLocation(numPages - 1 - location)
+ } else {
+ super.setLocation(location)
+ }
+ }
+} \ No newline at end of file
diff --git a/packages/SystemUI/src/com/android/systemui/controls/management/StructureAdapter.kt b/packages/SystemUI/src/com/android/systemui/controls/management/StructureAdapter.kt
new file mode 100644
index 000000000000..cb67454195ec
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/controls/management/StructureAdapter.kt
@@ -0,0 +1,73 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.controls.management
+
+import android.view.LayoutInflater
+import android.view.View
+import android.view.ViewGroup
+import androidx.recyclerview.widget.GridLayoutManager
+import androidx.recyclerview.widget.RecyclerView
+import com.android.systemui.R
+
+class StructureAdapter(
+ private val models: List<StructureContainer>
+) : RecyclerView.Adapter<StructureAdapter.StructureHolder>() {
+
+ override fun onCreateViewHolder(parent: ViewGroup, p1: Int): StructureHolder {
+ val layoutInflater = LayoutInflater.from(parent.context)
+ return StructureHolder(
+ layoutInflater.inflate(R.layout.controls_structure_page, parent, false)
+ )
+ }
+
+ override fun getItemCount() = models.size
+
+ override fun onBindViewHolder(holder: StructureHolder, index: Int) {
+ holder.bind(models[index].model)
+ }
+
+ class StructureHolder(view: View) : RecyclerView.ViewHolder(view) {
+
+ private val recyclerView: RecyclerView
+ private val controlAdapter: ControlAdapter
+
+ init {
+ recyclerView = itemView.requireViewById<RecyclerView>(R.id.listAll)
+ val elevation = itemView.context.resources.getFloat(R.dimen.control_card_elevation)
+ controlAdapter = ControlAdapter(elevation)
+ setUpRecyclerView()
+ }
+
+ fun bind(model: ControlsModel) {
+ controlAdapter.changeModel(model)
+ }
+
+ private fun setUpRecyclerView() {
+ val margin = itemView.context.resources
+ .getDimensionPixelSize(R.dimen.controls_card_margin)
+ val itemDecorator = MarginItemDecorator(margin, margin)
+
+ recyclerView.apply {
+ this.adapter = controlAdapter
+ layoutManager = GridLayoutManager(recyclerView.context, 2).apply {
+ spanSizeLookup = controlAdapter.spanSizeLookup
+ }
+ addItemDecoration(itemDecorator)
+ }
+ }
+ }
+} \ No newline at end of file
diff --git a/packages/SystemUI/src/com/android/systemui/controls/ui/ChallengeDialogs.kt b/packages/SystemUI/src/com/android/systemui/controls/ui/ChallengeDialogs.kt
new file mode 100644
index 000000000000..2494fd119670
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/controls/ui/ChallengeDialogs.kt
@@ -0,0 +1,102 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.controls.ui
+
+import android.app.AlertDialog
+import android.app.Dialog
+import android.content.DialogInterface
+import android.service.controls.actions.BooleanAction
+import android.service.controls.actions.CommandAction
+import android.service.controls.actions.ControlAction
+import android.service.controls.actions.FloatAction
+import android.service.controls.actions.ModeAction
+import android.text.InputType
+import android.util.Log
+import android.view.WindowManager
+import android.widget.CheckBox
+import android.widget.EditText
+
+import com.android.systemui.R
+
+/**
+ * Creates all dialogs for challengeValues that can occur from a call to
+ * {@link ControlsProviderService#performControlAction}. The types of challenge
+ * responses are listed in {@link ControlAction.ResponseResult}.
+ */
+object ChallengeDialogs {
+
+ fun createPinDialog(cvh: ControlViewHolder): Dialog? {
+ val lastAction = cvh.lastAction
+ if (lastAction == null) {
+ Log.e(ControlsUiController.TAG,
+ "PIN Dialog attempted but no last action is set. Will not show")
+ return null
+ }
+ val builder = AlertDialog.Builder(
+ cvh.context,
+ android.R.style.Theme_DeviceDefault_Dialog_Alert
+ ).apply {
+ setTitle(R.string.controls_pin_verify)
+ setView(R.layout.controls_dialog_pin)
+ setPositiveButton(
+ android.R.string.ok,
+ DialogInterface.OnClickListener { dialog, _ ->
+ if (dialog is Dialog) {
+ dialog.requireViewById<EditText>(R.id.controls_pin_input)
+ val pin = dialog.requireViewById<EditText>(R.id.controls_pin_input)
+ .getText().toString()
+ cvh.action(addChallengeValue(lastAction, pin))
+ dialog.dismiss()
+ }
+ })
+ setNegativeButton(
+ android.R.string.cancel,
+ DialogInterface.OnClickListener { dialog, _ -> dialog.cancel() }
+ )
+ }
+ return builder.create().apply {
+ getWindow().apply {
+ setType(WindowManager.LayoutParams.TYPE_VOLUME_OVERLAY)
+ setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_STATE_VISIBLE)
+ }
+ setOnShowListener(DialogInterface.OnShowListener { _ ->
+ val editText = requireViewById<EditText>(R.id.controls_pin_input)
+ requireViewById<CheckBox>(R.id.controls_pin_use_alpha).setOnClickListener { v ->
+ if ((v as CheckBox).isChecked) {
+ editText.setInputType(
+ InputType.TYPE_CLASS_TEXT or InputType.TYPE_TEXT_VARIATION_PASSWORD)
+ } else {
+ editText.setInputType(
+ InputType.TYPE_CLASS_NUMBER or InputType.TYPE_NUMBER_VARIATION_PASSWORD)
+ }
+ }
+ editText.requestFocus()
+ })
+ }
+ }
+
+ private fun addChallengeValue(action: ControlAction, challengeValue: String): ControlAction {
+ val id = action.getTemplateId()
+ return when (action) {
+ is BooleanAction -> BooleanAction(id, action.getNewState(), challengeValue)
+ is FloatAction -> FloatAction(id, action.getNewValue(), challengeValue)
+ is CommandAction -> CommandAction(id, challengeValue)
+ is ModeAction -> ModeAction(id, action.getNewMode(), challengeValue)
+ else -> throw IllegalStateException("'action' is not a known type: $action")
+ }
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/controls/ui/ControlActionCoordinator.kt b/packages/SystemUI/src/com/android/systemui/controls/ui/ControlActionCoordinator.kt
index eb84a8bcbfbd..680d0066fc56 100644
--- a/packages/SystemUI/src/com/android/systemui/controls/ui/ControlActionCoordinator.kt
+++ b/packages/SystemUI/src/com/android/systemui/controls/ui/ControlActionCoordinator.kt
@@ -20,6 +20,7 @@ import android.app.PendingIntent
import android.content.Intent
import android.provider.Settings
import android.service.controls.actions.BooleanAction
+import android.service.controls.actions.CommandAction
import android.util.Log
import android.view.HapticFeedbackConstants
@@ -36,6 +37,10 @@ object ControlActionCoordinator {
cvh.clipLayer.setLevel(nextLevel)
}
+ fun touch(cvh: ControlViewHolder, templateId: String) {
+ cvh.action(CommandAction(templateId))
+ }
+
fun longPress(cvh: ControlViewHolder) {
// Long press snould only be called when there is valid control state, otherwise ignore
cvh.cws.control?.let {
diff --git a/packages/SystemUI/src/com/android/systemui/controls/ui/ControlViewHolder.kt b/packages/SystemUI/src/com/android/systemui/controls/ui/ControlViewHolder.kt
index f2c84906c868..fc5663fe8c97 100644
--- a/packages/SystemUI/src/com/android/systemui/controls/ui/ControlViewHolder.kt
+++ b/packages/SystemUI/src/com/android/systemui/controls/ui/ControlViewHolder.kt
@@ -19,13 +19,12 @@ package com.android.systemui.controls.ui
import android.content.Context
import android.graphics.BlendMode
import android.graphics.drawable.ClipDrawable
-import android.graphics.drawable.Icon
import android.graphics.drawable.LayerDrawable
import android.service.controls.Control
import android.service.controls.actions.ControlAction
import android.service.controls.templates.ControlTemplate
+import android.service.controls.templates.StatelessTemplate
import android.service.controls.templates.TemperatureControlTemplate
-import android.service.controls.templates.ThumbnailTemplate
import android.service.controls.templates.ToggleRangeTemplate
import android.service.controls.templates.ToggleTemplate
import android.view.View
@@ -57,6 +56,7 @@ class ControlViewHolder(
lateinit var cws: ControlWithState
var cancelUpdate: Runnable? = null
var behavior: Behavior? = null
+ var lastAction: ControlAction? = null
init {
val ld = layout.getBackground() as LayerDrawable
@@ -97,15 +97,7 @@ class ControlViewHolder(
}
fun actionResponse(@ControlAction.ResponseResult response: Int) {
- val text = when (response) {
- ControlAction.RESPONSE_OK -> "Success"
- ControlAction.RESPONSE_FAIL -> "Error"
- else -> ""
- }
-
- if (!text.isEmpty()) {
- setTransientStatus(text)
- }
+ // TODO: b/150931809 - handle response codes
}
fun setTransientStatus(tempStatus: String) {
@@ -122,6 +114,7 @@ class ControlViewHolder(
}
fun action(action: ControlAction) {
+ lastAction = action
controlsController.action(cws.componentName, cws.ci, action)
}
@@ -129,20 +122,25 @@ class ControlViewHolder(
return when {
status == Control.STATUS_UNKNOWN -> UnknownBehavior::class
template is ToggleTemplate -> ToggleBehavior::class
+ template is StatelessTemplate -> TouchBehavior::class
template is ToggleRangeTemplate -> ToggleRangeBehavior::class
template is TemperatureControlTemplate -> TemperatureControlBehavior::class
- template is ThumbnailTemplate -> StaticBehavior::class
else -> DefaultBehavior::class
}
}
- internal fun applyRenderInfo(ri: RenderInfo) {
+ internal fun applyRenderInfo(enabled: Boolean, offset: Int = 0) {
+ setEnabled(enabled)
+
+ val deviceType = cws.control?.let { it.getDeviceType() } ?: cws.ci.deviceType
+ val ri = RenderInfo.lookup(context, cws.componentName, deviceType, enabled, offset)
+
val fg = context.getResources().getColorStateList(ri.foreground, context.getTheme())
val bg = context.getResources().getColorStateList(ri.background, context.getTheme())
status.setTextColor(fg)
statusExtra.setTextColor(fg)
- icon.setImageIcon(Icon.createWithResource(context, ri.iconResourceId))
+ icon.setImageDrawable(ri.icon)
icon.setImageTintList(fg)
clipLayer.getDrawable().apply {
@@ -151,7 +149,7 @@ class ControlViewHolder(
}
}
- fun setEnabled(enabled: Boolean) {
+ private fun setEnabled(enabled: Boolean) {
status.setEnabled(enabled)
icon.setEnabled(enabled)
}
diff --git a/packages/SystemUI/src/com/android/systemui/controls/ui/ControlsUiControllerImpl.kt b/packages/SystemUI/src/com/android/systemui/controls/ui/ControlsUiControllerImpl.kt
index c7157da26ea3..bde966ca067e 100644
--- a/packages/SystemUI/src/com/android/systemui/controls/ui/ControlsUiControllerImpl.kt
+++ b/packages/SystemUI/src/com/android/systemui/controls/ui/ControlsUiControllerImpl.kt
@@ -16,17 +16,15 @@
package com.android.systemui.controls.ui
-import android.accounts.Account
-import android.accounts.AccountManager
+import android.app.Dialog
import android.content.ComponentName
import android.content.Context
import android.content.Intent
-import android.content.ServiceConnection
import android.content.SharedPreferences
import android.graphics.drawable.Drawable
-import android.os.IBinder
+import android.graphics.drawable.LayerDrawable
import android.service.controls.Control
-import android.service.controls.TokenProvider
+import android.service.controls.actions.ControlAction
import android.util.Log
import android.view.ContextThemeWrapper
import android.view.LayoutInflater
@@ -48,8 +46,8 @@ import com.android.systemui.controls.management.ControlsListingController
import com.android.systemui.controls.management.ControlsProviderSelectorActivity
import com.android.systemui.dagger.qualifiers.Background
import com.android.systemui.dagger.qualifiers.Main
-import com.android.systemui.R
import com.android.systemui.util.concurrency.DelayableExecutor
+import com.android.systemui.R
import dagger.Lazy
@@ -58,68 +56,6 @@ import java.text.Collator
import javax.inject.Inject
import javax.inject.Singleton
-// TEMP CODE for MOCK
-private const val TOKEN = "https://www.googleapis.com/auth/assistant"
-private const val SCOPE = "oauth2:" + TOKEN
-private var tokenProviderConnection: TokenProviderConnection? = null
-class TokenProviderConnection(
- val cc: ControlsController,
- val context: Context,
- val structure: StructureInfo?
-) : ServiceConnection {
- private var mTokenProvider: TokenProvider? = null
-
- override fun onServiceConnected(cName: ComponentName, binder: IBinder) {
- Thread({
- Log.i(ControlsUiController.TAG, "TokenProviderConnection connected")
- mTokenProvider = TokenProvider.Stub.asInterface(binder)
-
- val mLastAccountName = mTokenProvider?.getAccountName()
-
- if (mLastAccountName == null || mLastAccountName.isEmpty()) {
- Log.e(ControlsUiController.TAG, "NO ACCOUNT IS SET. Open HomeMock app")
- } else {
- mTokenProvider?.setAuthToken(getAuthToken(mLastAccountName))
- structure?.let {
- cc.subscribeToFavorites(it)
- }
- }
- }, "TokenProviderThread").start()
- }
-
- override fun onServiceDisconnected(cName: ComponentName) {
- mTokenProvider = null
- }
-
- fun getAuthToken(accountName: String): String? {
- val am = AccountManager.get(context)
- val accounts = am.getAccountsByType("com.google")
- if (accounts == null || accounts.size == 0) {
- Log.w(ControlsUiController.TAG, "No com.google accounts found")
- return null
- }
-
- var account: Account? = null
- for (a in accounts) {
- if (a.name.equals(accountName)) {
- account = a
- break
- }
- }
-
- if (account == null) {
- account = accounts[0]
- }
-
- try {
- return am.blockingGetAuthToken(account!!, SCOPE, true)
- } catch (e: Throwable) {
- Log.e(ControlsUiController.TAG, "Error getting auth token", e)
- return null
- }
- }
-}
-
private data class ControlKey(val componentName: ComponentName, val controlId: String)
@Singleton
@@ -151,13 +87,20 @@ class ControlsUiControllerImpl @Inject constructor (
private lateinit var parent: ViewGroup
private lateinit var lastItems: List<SelectionItem>
private var popup: ListPopupWindow? = null
+ private var activeDialog: Dialog? = null
+ private val addControlsItem: SelectionItem
- private val addControlsItem = SelectionItem(
- context.resources.getString(R.string.controls_providers_title),
- "",
- context.getDrawable(R.drawable.ic_add),
- EMPTY_COMPONENT
- )
+ init {
+ val addDrawable = context.getDrawable(R.drawable.ic_add).apply {
+ setTint(context.resources.getColor(R.color.control_secondary_text, null))
+ }
+ addControlsItem = SelectionItem(
+ context.resources.getString(R.string.controls_providers_title),
+ "",
+ addDrawable,
+ EMPTY_COMPONENT
+ )
+ }
override val available: Boolean
get() = controlsController.get().available
@@ -205,21 +148,10 @@ class ControlsUiControllerImpl @Inject constructor (
ControlKey(selectedStructure.componentName, it.ci.controlId)
}
listingCallback = createCallback(::showControlsView)
+ controlsController.get().subscribeToFavorites(selectedStructure)
}
controlsListingController.get().addCallback(listingCallback)
-
- // Temp code to pass auth
- tokenProviderConnection = TokenProviderConnection(controlsController.get(), context,
- selectedStructure)
-
- val serviceIntent = Intent()
- serviceIntent.setComponent(ComponentName("com.android.systemui.home.mock",
- "com.android.systemui.home.mock.AuthService"))
- if (!context.bindService(serviceIntent, tokenProviderConnection!!,
- Context.BIND_AUTO_CREATE)) {
- controlsController.get().subscribeToFavorites(selectedStructure)
- }
}
private fun showInitialSetupView(items: List<SelectionItem>) {
@@ -256,36 +188,23 @@ class ControlsUiControllerImpl @Inject constructor (
parent.removeAllViews()
controlViewsById.clear()
- val inflater = LayoutInflater.from(context)
- inflater.inflate(R.layout.controls_with_favorites, parent, true)
+ createListView()
+ createDropDown(items)
+ }
- val listView = parent.requireViewById(R.id.global_actions_controls_list) as ViewGroup
- var lastRow: ViewGroup = createRow(inflater, listView)
- selectedStructure.controls.forEach {
- if (lastRow.getChildCount() == 2) {
- lastRow = createRow(inflater, listView)
- }
- val item = inflater.inflate(
- R.layout.controls_base_item, lastRow, false) as ViewGroup
- lastRow.addView(item)
- val cvh = ControlViewHolder(item, controlsController.get(), uiExecutor, bgExecutor)
- val key = ControlKey(selectedStructure.componentName, it.controlId)
- cvh.bindData(controlsById.getValue(key))
- controlViewsById.put(key, cvh)
+ private fun createDropDown(items: List<SelectionItem>) {
+ items.forEach {
+ RenderInfo.registerComponentIcon(it.componentName, it.icon)
}
- // add spacer if necessary to keep control size consistent
- if ((selectedStructure.controls.size % 2) == 1) {
- lastRow.addView(Space(context), LinearLayout.LayoutParams(0, 0, 1f))
+ val itemsByComponent = items.associateBy { it.componentName }
+ val itemsWithStructure = allStructures.mapNotNull {
+ itemsByComponent.get(it.componentName)?.copy(structure = it.structure)
}
+ val selectionItem = findSelectionItem(selectedStructure, itemsWithStructure) ?: items[0]
- val itemsByComponent = items.associateBy { it.componentName }
var adapter = ItemAdapter(context, R.layout.controls_spinner_item).apply {
- val listItems = allStructures.mapNotNull {
- itemsByComponent.get(it.componentName)?.copy(structure = it.structure)
- }
-
- addAll(listItems + addControlsItem)
+ addAll(itemsWithStructure + addControlsItem)
}
/*
@@ -293,13 +212,15 @@ class ControlsUiControllerImpl @Inject constructor (
* for this dialog. Use a textView with the ListPopupWindow to achieve
* a similar effect
*/
- val item = adapter.findSelectionItem(selectedStructure) ?: adapter.getItem(0)
parent.requireViewById<TextView>(R.id.app_or_structure_spinner).apply {
- setText(item.getTitle())
+ setText(selectionItem.getTitle())
+ // override the default color on the dropdown drawable
+ (getBackground() as LayerDrawable).getDrawable(1)
+ .setTint(context.resources.getColor(R.color.control_spinner_dropdown, null))
}
parent.requireViewById<ImageView>(R.id.app_icon).apply {
- setContentDescription(item.getTitle())
- setImageDrawable(item.icon)
+ setContentDescription(selectionItem.getTitle())
+ setImageDrawable(selectionItem.icon)
}
val anchor = parent.requireViewById<ViewGroup>(R.id.controls_header)
anchor.setOnClickListener(object : View.OnClickListener {
@@ -337,6 +258,36 @@ class ControlsUiControllerImpl @Inject constructor (
})
}
+ private fun createListView() {
+ val inflater = LayoutInflater.from(context)
+ inflater.inflate(R.layout.controls_with_favorites, parent, true)
+
+ val listView = parent.requireViewById(R.id.global_actions_controls_list) as ViewGroup
+ var lastRow: ViewGroup = createRow(inflater, listView)
+ selectedStructure.controls.forEach {
+ if (lastRow.getChildCount() == 2) {
+ lastRow = createRow(inflater, listView)
+ }
+ val baseLayout = inflater.inflate(
+ R.layout.controls_base_item, lastRow, false) as ViewGroup
+ lastRow.addView(baseLayout)
+ val cvh = ControlViewHolder(
+ baseLayout,
+ controlsController.get(),
+ uiExecutor,
+ bgExecutor
+ )
+ val key = ControlKey(selectedStructure.componentName, it.controlId)
+ cvh.bindData(controlsById.getValue(key))
+ controlViewsById.put(key, cvh)
+ }
+
+ // add spacer if necessary to keep control size consistent
+ if ((selectedStructure.controls.size % 2) == 1) {
+ lastRow.addView(Space(context), LinearLayout.LayoutParams(0, 0, 1f))
+ }
+ }
+
private fun loadPreference(structures: List<StructureInfo>): StructureInfo {
if (structures.isEmpty()) return EMPTY_STRUCTURE
@@ -368,7 +319,8 @@ class ControlsUiControllerImpl @Inject constructor (
if (newSelection != selectedStructure) {
selectedStructure = newSelection
updatePreferences(selectedStructure)
- showControlsView(lastItems)
+ controlsListingController.get().removeCallback(listingCallback)
+ show(parent)
}
}
}
@@ -376,15 +328,16 @@ class ControlsUiControllerImpl @Inject constructor (
override fun hide() {
Log.d(ControlsUiController.TAG, "hide()")
popup?.dismiss()
+ activeDialog?.dismiss()
controlsController.get().unsubscribe()
- context.unbindService(tokenProviderConnection)
- tokenProviderConnection = null
parent.removeAllViews()
controlsById.clear()
controlViewsById.clear()
controlsListingController.get().removeCallback(listingCallback)
+
+ RenderInfo.clearCache()
}
override fun onRefreshState(componentName: ComponentName, controls: List<Control>) {
@@ -406,7 +359,15 @@ class ControlsUiControllerImpl @Inject constructor (
override fun onActionResponse(componentName: ComponentName, controlId: String, response: Int) {
val key = ControlKey(componentName, controlId)
uiExecutor.execute {
- controlViewsById.get(key)?.actionResponse(response)
+ controlViewsById.get(key)?.let { cvh ->
+ when (response) {
+ ControlAction.RESPONSE_CHALLENGE_PIN -> {
+ activeDialog = ChallengeDialogs.createPinDialog(cvh)
+ activeDialog?.show()
+ }
+ else -> cvh.actionResponse(response)
+ }
+ }
}
}
@@ -415,6 +376,11 @@ class ControlsUiControllerImpl @Inject constructor (
listView.addView(row)
return row
}
+
+ private fun findSelectionItem(si: StructureInfo, items: List<SelectionItem>): SelectionItem? =
+ items.firstOrNull {
+ it.componentName == si.componentName && it.structure == si.structure
+ }
}
private data class SelectionItem(
@@ -445,17 +411,4 @@ private class ItemAdapter(
}
return view
}
-
- fun findSelectionItem(si: StructureInfo): SelectionItem? {
- var i = 0
- while (i < getCount()) {
- val item = getItem(i)
- if (item.componentName == si.componentName &&
- item.structure == si.structure) {
- return item
- }
- i++
- }
- return null
- }
}
diff --git a/packages/SystemUI/src/com/android/systemui/controls/ui/DefaultBehavior.kt b/packages/SystemUI/src/com/android/systemui/controls/ui/DefaultBehavior.kt
index 17479293f7dc..e850a6a559d6 100644
--- a/packages/SystemUI/src/com/android/systemui/controls/ui/DefaultBehavior.kt
+++ b/packages/SystemUI/src/com/android/systemui/controls/ui/DefaultBehavior.kt
@@ -25,7 +25,6 @@ class DefaultBehavior : Behavior {
override fun bind(cws: ControlWithState) {
cvh.status.setText(cws.control?.getStatusText() ?: "")
- cvh.setEnabled(false)
- cvh.applyRenderInfo(RenderInfo.lookup(cws.ci.deviceType, false))
+ cvh.applyRenderInfo(false)
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/controls/ui/RenderInfo.kt b/packages/SystemUI/src/com/android/systemui/controls/ui/RenderInfo.kt
index da52c6f8ee21..56267beb1b71 100644
--- a/packages/SystemUI/src/com/android/systemui/controls/ui/RenderInfo.kt
+++ b/packages/SystemUI/src/com/android/systemui/controls/ui/RenderInfo.kt
@@ -16,8 +16,14 @@
package com.android.systemui.controls.ui
+import android.annotation.MainThread
+import android.content.ComponentName
+import android.content.Context
+import android.graphics.drawable.Drawable
import android.service.controls.DeviceTypes
import android.service.controls.templates.TemperatureControlTemplate
+import android.util.ArrayMap
+import android.util.SparseArray
import com.android.systemui.R
@@ -31,18 +37,54 @@ data class IconState(val disabledResourceId: Int, val enabledResourceId: Int) {
}
}
-data class RenderInfo(val iconResourceId: Int, val foreground: Int, val background: Int) {
+data class RenderInfo(val icon: Drawable, val foreground: Int, val background: Int) {
companion object {
- fun lookup(deviceType: Int, enabled: Boolean): RenderInfo {
- val iconState = deviceIconMap.getValue(deviceType)
+ const val APP_ICON_ID = -1
+ private val iconMap = SparseArray<Drawable>()
+ private val appIconMap = ArrayMap<ComponentName, Drawable>()
+
+ @MainThread
+ fun lookup(
+ context: Context,
+ componentName: ComponentName,
+ deviceType: Int,
+ enabled: Boolean,
+ offset: Int = 0
+ ): RenderInfo {
val (fg, bg) = deviceColorMap.getValue(deviceType)
- return RenderInfo(iconState[enabled], fg, bg)
+
+ val iconKey = if (offset > 0) {
+ deviceType * BUCKET_SIZE + offset
+ } else deviceType
+
+ val iconState = deviceIconMap.getValue(iconKey)
+ val resourceId = iconState[enabled]
+ var icon: Drawable? = null
+ if (resourceId == APP_ICON_ID) {
+ icon = appIconMap.get(componentName)
+ if (icon == null) {
+ icon = context.resources
+ .getDrawable(R.drawable.ic_device_unknown_gm2_24px, null)
+ appIconMap.put(componentName, icon)
+ }
+ } else {
+ icon = iconMap.get(resourceId)
+ if (icon == null) {
+ icon = context.resources.getDrawable(resourceId, null)
+ iconMap.put(resourceId, icon)
+ }
+ }
+ return RenderInfo(icon!!, fg, bg)
}
- fun lookup(deviceType: Int, offset: Int, enabled: Boolean): RenderInfo {
- val key = deviceType * BUCKET_SIZE + offset
- return lookup(key, enabled)
+ fun registerComponentIcon(componentName: ComponentName, icon: Drawable) {
+ appIconMap.put(componentName, icon)
+ }
+
+ fun clearCache() {
+ iconMap.clear()
+ appIconMap.clear()
}
}
}
@@ -116,6 +158,10 @@ private val deviceIconMap = mapOf<Int, IconState>(
DeviceTypes.TYPE_MOP to IconState(
R.drawable.ic_vacuum_gm2_24px,
R.drawable.ic_vacuum_gm2_24px
+ ),
+ DeviceTypes.TYPE_ROUTINE to IconState(
+ RenderInfo.APP_ICON_ID,
+ RenderInfo.APP_ICON_ID
)
).withDefault {
IconState(
diff --git a/packages/SystemUI/src/com/android/systemui/controls/ui/StaticBehavior.kt b/packages/SystemUI/src/com/android/systemui/controls/ui/StaticBehavior.kt
deleted file mode 100644
index c006d6fca7e2..000000000000
--- a/packages/SystemUI/src/com/android/systemui/controls/ui/StaticBehavior.kt
+++ /dev/null
@@ -1,67 +0,0 @@
-/*
- * Copyright (C) 2020 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.systemui.controls.ui
-
-import android.graphics.drawable.ClipDrawable
-import android.graphics.drawable.LayerDrawable
-import android.service.controls.Control
-import android.service.controls.templates.ThumbnailTemplate
-
-import com.android.systemui.R
-import com.android.systemui.controls.ui.ControlActionCoordinator.MAX_LEVEL
-
-/**
- * Used for controls that cannot be interacted with. Information is presented to the user
- * but no actions can be taken. If using a ThumbnailTemplate, the background image will
- * be changed.
- */
-class StaticBehavior() : Behavior {
- lateinit var control: Control
- lateinit var cvh: ControlViewHolder
-
- override fun initialize(cvh: ControlViewHolder) {
- this.cvh = cvh
- }
-
- override fun bind(cws: ControlWithState) {
- this.control = cws.control!!
-
- cvh.status.setText(control.getStatusText())
-
- val ld = cvh.layout.getBackground() as LayerDrawable
- val clipLayer = ld.findDrawableByLayerId(R.id.clip_layer) as ClipDrawable
-
- clipLayer.setLevel(MAX_LEVEL)
- cvh.setEnabled(true)
- cvh.applyRenderInfo(RenderInfo.lookup(control.getDeviceType(), true))
-
- val template = control.getControlTemplate()
- if (template is ThumbnailTemplate) {
- cvh.bgExecutor.execute {
- // clear the default tinting in favor of only using alpha
- val drawable = template.getThumbnail().loadDrawable(cvh.context)
- drawable.setTintList(null)
- drawable.setAlpha((0.45 * 255).toInt())
- cvh.uiExecutor.execute {
- val radius = cvh.context.getResources()
- .getDimensionPixelSize(R.dimen.control_corner_radius).toFloat()
- clipLayer.setDrawable(CornerDrawable(drawable, radius))
- }
- }
- }
- }
-}
diff --git a/packages/SystemUI/src/com/android/systemui/controls/ui/TemperatureControlBehavior.kt b/packages/SystemUI/src/com/android/systemui/controls/ui/TemperatureControlBehavior.kt
index 239d2e5477bf..15c1dabf71bd 100644
--- a/packages/SystemUI/src/com/android/systemui/controls/ui/TemperatureControlBehavior.kt
+++ b/packages/SystemUI/src/com/android/systemui/controls/ui/TemperatureControlBehavior.kt
@@ -47,10 +47,7 @@ class TemperatureControlBehavior : Behavior {
val activeMode = template.getCurrentActiveMode()
val enabled = activeMode != 0 && activeMode != TemperatureControlTemplate.MODE_OFF
- val deviceType = control.getDeviceType()
-
clipLayer.setLevel(if (enabled) MAX_LEVEL else MIN_LEVEL)
- cvh.setEnabled(enabled)
- cvh.applyRenderInfo(RenderInfo.lookup(deviceType, activeMode, enabled))
+ cvh.applyRenderInfo(enabled, activeMode)
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/controls/ui/ToggleBehavior.kt b/packages/SystemUI/src/com/android/systemui/controls/ui/ToggleBehavior.kt
index d306d7c84e7f..a3368ef77a56 100644
--- a/packages/SystemUI/src/com/android/systemui/controls/ui/ToggleBehavior.kt
+++ b/packages/SystemUI/src/com/android/systemui/controls/ui/ToggleBehavior.kt
@@ -34,7 +34,7 @@ class ToggleBehavior : Behavior {
override fun initialize(cvh: ControlViewHolder) {
this.cvh = cvh
- cvh.setEnabled(false)
+ cvh.applyRenderInfo(false)
cvh.layout.setOnClickListener(View.OnClickListener() {
ControlActionCoordinator.toggle(cvh, template.getTemplateId(), template.isChecked())
@@ -51,10 +51,7 @@ class ToggleBehavior : Behavior {
clipLayer = ld.findDrawableByLayerId(R.id.clip_layer)
val checked = template.isChecked()
- val deviceType = control.getDeviceType()
-
clipLayer.setLevel(if (checked) MAX_LEVEL else MIN_LEVEL)
- cvh.setEnabled(checked)
- cvh.applyRenderInfo(RenderInfo.lookup(deviceType, checked))
+ cvh.applyRenderInfo(checked)
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/controls/ui/ToggleRangeBehavior.kt b/packages/SystemUI/src/com/android/systemui/controls/ui/ToggleRangeBehavior.kt
index cca56c219972..6595b55a691d 100644
--- a/packages/SystemUI/src/com/android/systemui/controls/ui/ToggleRangeBehavior.kt
+++ b/packages/SystemUI/src/com/android/systemui/controls/ui/ToggleRangeBehavior.kt
@@ -56,7 +56,7 @@ class ToggleRangeBehavior : Behavior {
status = cvh.status
context = status.getContext()
- cvh.setEnabled(false)
+ cvh.applyRenderInfo(false)
val gestureListener = ToggleRangeGestureListener(cvh.layout)
val gestureDetector = GestureDetector(context, gestureListener)
@@ -89,14 +89,11 @@ class ToggleRangeBehavior : Behavior {
rangeTemplate = template.getRange()
val checked = template.isChecked()
- val deviceType = control.getDeviceType()
-
val currentRatio = rangeTemplate.getCurrentValue() /
(rangeTemplate.getMaxValue() - rangeTemplate.getMinValue())
updateRange(currentRatio, checked)
- cvh.setEnabled(checked)
- cvh.applyRenderInfo(RenderInfo.lookup(deviceType, checked))
+ cvh.applyRenderInfo(checked)
}
fun beginUpdateRange() {
diff --git a/packages/SystemUI/src/com/android/systemui/controls/ui/TouchBehavior.kt b/packages/SystemUI/src/com/android/systemui/controls/ui/TouchBehavior.kt
new file mode 100644
index 000000000000..d64a5f060487
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/controls/ui/TouchBehavior.kt
@@ -0,0 +1,58 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.controls.ui
+
+import android.graphics.drawable.Drawable
+import android.graphics.drawable.LayerDrawable
+import android.view.View
+import android.service.controls.Control
+import android.service.controls.templates.StatelessTemplate
+
+import com.android.systemui.R
+import com.android.systemui.controls.ui.ControlActionCoordinator.MIN_LEVEL
+
+/**
+ * Supports touch events, but has no notion of state as the {@link ToggleBehavior} does. Must be
+ * used with {@link StatelessTemplate}.
+ */
+class TouchBehavior : Behavior {
+ lateinit var clipLayer: Drawable
+ lateinit var template: StatelessTemplate
+ lateinit var control: Control
+ lateinit var cvh: ControlViewHolder
+
+ override fun initialize(cvh: ControlViewHolder) {
+ this.cvh = cvh
+ cvh.applyRenderInfo(false)
+
+ cvh.layout.setOnClickListener(View.OnClickListener() {
+ ControlActionCoordinator.touch(cvh, template.getTemplateId())
+ })
+ }
+
+ override fun bind(cws: ControlWithState) {
+ this.control = cws.control!!
+ cvh.status.setText(control.getStatusText())
+ template = control.getControlTemplate() as StatelessTemplate
+
+ val ld = cvh.layout.getBackground() as LayerDrawable
+ clipLayer = ld.findDrawableByLayerId(R.id.clip_layer)
+ clipLayer.setLevel(MIN_LEVEL)
+
+ cvh.applyRenderInfo(false)
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/controls/ui/UnknownBehavior.kt b/packages/SystemUI/src/com/android/systemui/controls/ui/UnknownBehavior.kt
index 1f33b8515dc7..c3572491f9f1 100644
--- a/packages/SystemUI/src/com/android/systemui/controls/ui/UnknownBehavior.kt
+++ b/packages/SystemUI/src/com/android/systemui/controls/ui/UnknownBehavior.kt
@@ -25,7 +25,6 @@ class UnknownBehavior : Behavior {
override fun bind(cws: ControlWithState) {
cvh.status.setText(cvh.context.getString(com.android.internal.R.string.loading))
- cvh.setEnabled(false)
- cvh.applyRenderInfo(RenderInfo.lookup(cws.ci.deviceType, false))
+ cvh.applyRenderInfo(false)
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/dagger/DependencyBinder.java b/packages/SystemUI/src/com/android/systemui/dagger/DependencyBinder.java
index 2877ed045479..5b3d5c565472 100644
--- a/packages/SystemUI/src/com/android/systemui/dagger/DependencyBinder.java
+++ b/packages/SystemUI/src/com/android/systemui/dagger/DependencyBinder.java
@@ -44,8 +44,6 @@ import com.android.systemui.statusbar.phone.ManagedProfileControllerImpl;
import com.android.systemui.statusbar.phone.StatusBarIconController;
import com.android.systemui.statusbar.phone.StatusBarIconControllerImpl;
import com.android.systemui.statusbar.phone.StatusBarRemoteInputCallback;
-import com.android.systemui.statusbar.policy.BatteryController;
-import com.android.systemui.statusbar.policy.BatteryControllerImpl;
import com.android.systemui.statusbar.policy.BluetoothController;
import com.android.systemui.statusbar.policy.BluetoothControllerImpl;
import com.android.systemui.statusbar.policy.CastController;
@@ -179,12 +177,6 @@ public abstract class DependencyBinder {
/**
*/
@Binds
- public abstract BatteryController provideBatteryController(
- BatteryControllerImpl controllerImpl);
-
- /**
- */
- @Binds
public abstract ManagedProfileController provideManagedProfileController(
ManagedProfileControllerImpl controllerImpl);
diff --git a/packages/SystemUI/src/com/android/systemui/dagger/SystemUIDefaultModule.java b/packages/SystemUI/src/com/android/systemui/dagger/SystemUIDefaultModule.java
index 3e257b6173eb..956b4aa177ea 100644
--- a/packages/SystemUI/src/com/android/systemui/dagger/SystemUIDefaultModule.java
+++ b/packages/SystemUI/src/com/android/systemui/dagger/SystemUIDefaultModule.java
@@ -23,6 +23,7 @@ import android.content.Context;
import androidx.annotation.Nullable;
+import com.android.keyguard.KeyguardViewController;
import com.android.systemui.dock.DockManager;
import com.android.systemui.dock.DockManagerImpl;
import com.android.systemui.plugins.statusbar.StatusBarStateController;
@@ -41,6 +42,9 @@ import com.android.systemui.statusbar.phone.KeyguardEnvironmentImpl;
import com.android.systemui.statusbar.phone.NotificationGroupManager;
import com.android.systemui.statusbar.phone.ShadeController;
import com.android.systemui.statusbar.phone.ShadeControllerImpl;
+import com.android.systemui.statusbar.phone.StatusBarKeyguardViewManager;
+import com.android.systemui.statusbar.policy.BatteryController;
+import com.android.systemui.statusbar.policy.BatteryControllerImpl;
import com.android.systemui.statusbar.policy.ConfigurationController;
import com.android.systemui.statusbar.policy.DeviceProvisionedController;
import com.android.systemui.statusbar.policy.DeviceProvisionedControllerImpl;
@@ -76,6 +80,11 @@ public abstract class SystemUIDefaultModule {
NotificationLockscreenUserManagerImpl notificationLockscreenUserManager);
@Binds
+ @Singleton
+ public abstract BatteryController provideBatteryController(
+ BatteryControllerImpl controllerImpl);
+
+ @Binds
abstract DockManager bindDockManager(DockManagerImpl dockManager);
@Binds
@@ -117,4 +126,8 @@ public abstract class SystemUIDefaultModule {
@Binds
abstract DeviceProvisionedController bindDeviceProvisionedController(
DeviceProvisionedControllerImpl deviceProvisionedController);
+
+ @Binds
+ abstract KeyguardViewController bindKeyguardViewController(
+ StatusBarKeyguardViewManager statusBarKeyguardViewManager);
}
diff --git a/packages/SystemUI/src/com/android/systemui/doze/DozeSensors.java b/packages/SystemUI/src/com/android/systemui/doze/DozeSensors.java
index 44e5d3de5ca7..c28a719b9826 100644
--- a/packages/SystemUI/src/com/android/systemui/doze/DozeSensors.java
+++ b/packages/SystemUI/src/com/android/systemui/doze/DozeSensors.java
@@ -261,7 +261,7 @@ public class DozeSensors {
private final ContentObserver mSettingsObserver = new ContentObserver(mHandler) {
@Override
- public void onChange(boolean selfChange, Uri uri, int userId) {
+ public void onChange(boolean selfChange, Iterable<Uri> uris, int flags, int userId) {
if (userId != ActivityManager.getCurrentUser()) {
return;
}
diff --git a/packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsDialog.java b/packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsDialog.java
index 24f505d5a395..786ad2c7d82a 100644
--- a/packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsDialog.java
+++ b/packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsDialog.java
@@ -1574,7 +1574,6 @@ public class GlobalActionsDialog implements DialogInterface.OnDismissListener,
private ControlsUiController mControlsUiController;
private ViewGroup mControlsView;
- private ViewGroup mContainerView;
ActionsDialog(Context context, MyAdapter adapter,
GlobalActionsPanelPlugin.PanelViewController plugin, BlurUtils blurUtils,
@@ -1671,7 +1670,6 @@ public class GlobalActionsDialog implements DialogInterface.OnDismissListener,
mControlsView = findViewById(com.android.systemui.R.id.global_actions_controls);
mGlobalActionsLayout = findViewById(com.android.systemui.R.id.global_actions_view);
mGlobalActionsLayout.setOutsideTouchListener(view -> dismiss());
- ((View) mGlobalActionsLayout.getParent()).setOnClickListener(view -> dismiss());
mGlobalActionsLayout.setListViewAccessibilityDelegate(new View.AccessibilityDelegate() {
@Override
public boolean dispatchPopulateAccessibilityEvent(
@@ -1684,6 +1682,15 @@ public class GlobalActionsDialog implements DialogInterface.OnDismissListener,
mGlobalActionsLayout.setRotationListener(this::onRotate);
mGlobalActionsLayout.setAdapter(mAdapter);
+ View globalActionsParent = (View) mGlobalActionsLayout.getParent();
+ globalActionsParent.setOnClickListener(v -> dismiss());
+
+ // add fall-through dismiss handling to root view
+ View rootView = findViewById(com.android.systemui.R.id.global_actions_grid_root);
+ if (rootView != null) {
+ rootView.setOnClickListener(v -> dismiss());
+ }
+
if (shouldUsePanel()) {
initializePanel();
}
@@ -1692,14 +1699,6 @@ public class GlobalActionsDialog implements DialogInterface.OnDismissListener,
mScrimAlpha = ScrimController.BUSY_SCRIM_ALPHA;
}
getWindow().setBackgroundDrawable(mBackgroundDrawable);
-
- if (mControlsView != null) {
- mContainerView = findViewById(com.android.systemui.R.id.global_actions_container);
- mContainerView.setOnTouchListener((v, e) -> {
- dismiss();
- return true;
- });
- }
}
private void fixNavBarClipping() {
diff --git a/packages/SystemUI/src/com/android/systemui/globalactions/MinHeightScrollView.java b/packages/SystemUI/src/com/android/systemui/globalactions/MinHeightScrollView.java
new file mode 100644
index 000000000000..622fa658f1b0
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/globalactions/MinHeightScrollView.java
@@ -0,0 +1,43 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.globalactions;
+
+import android.content.Context;
+import android.util.AttributeSet;
+import android.view.View;
+import android.widget.ScrollView;
+
+/**
+ * When measured, this view sets the minimum height of its first child to be equal to its own
+ * target height.
+ *
+ * This ensures fall-through click handlers can be placed on this view's child component.
+ */
+public class MinHeightScrollView extends ScrollView {
+ public MinHeightScrollView(Context context, AttributeSet attrs) {
+ super(context, attrs);
+ }
+
+ @Override
+ public void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
+ View firstChild = getChildAt(0);
+ if (firstChild != null) {
+ firstChild.setMinimumHeight(MeasureSpec.getSize(heightMeasureSpec));
+ }
+ super.onMeasure(widthMeasureSpec, heightMeasureSpec);
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java
index c129035e66a7..3d708a91dbf0 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java
@@ -80,6 +80,7 @@ import com.android.keyguard.KeyguardDisplayManager;
import com.android.keyguard.KeyguardSecurityView;
import com.android.keyguard.KeyguardUpdateMonitor;
import com.android.keyguard.KeyguardUpdateMonitorCallback;
+import com.android.keyguard.KeyguardViewController;
import com.android.keyguard.ViewMediatorCallback;
import com.android.systemui.Dumpable;
import com.android.systemui.R;
@@ -95,7 +96,6 @@ import com.android.systemui.statusbar.phone.KeyguardBypassController;
import com.android.systemui.statusbar.phone.NotificationPanelViewController;
import com.android.systemui.statusbar.phone.NotificationShadeWindowController;
import com.android.systemui.statusbar.phone.StatusBar;
-import com.android.systemui.statusbar.phone.StatusBarKeyguardViewManager;
import com.android.systemui.util.DeviceConfigProxy;
import com.android.systemui.util.InjectionInflationController;
@@ -236,7 +236,7 @@ public class KeyguardViewMediator extends SystemUI implements Dumpable {
*/
private PowerManager.WakeLock mShowKeyguardWakeLock;
- private final Lazy<StatusBarKeyguardViewManager> mStatusBarKeyguardViewManagerLazy;
+ private final Lazy<KeyguardViewController> mKeyguardViewControllerLazy;
// these are protected by synchronized (this)
@@ -601,7 +601,7 @@ public class KeyguardViewMediator extends SystemUI implements Dumpable {
@Override
public void setNeedsInput(boolean needsInput) {
- mStatusBarKeyguardViewManagerLazy.get().setNeedsInput(needsInput);
+ mKeyguardViewControllerLazy.get().setNeedsInput(needsInput);
}
@Override
@@ -615,7 +615,7 @@ public class KeyguardViewMediator extends SystemUI implements Dumpable {
mKeyguardDonePending = true;
mHideAnimationRun = true;
mHideAnimationRunning = true;
- mStatusBarKeyguardViewManagerLazy.get()
+ mKeyguardViewControllerLazy.get()
.startPreHideAnimation(mHideAnimationFinishedRunnable);
mHandler.sendEmptyMessageDelayed(KEYGUARD_DONE_PENDING_TIMEOUT,
KEYGUARD_DONE_PENDING_TIMEOUT_MS);
@@ -647,7 +647,7 @@ public class KeyguardViewMediator extends SystemUI implements Dumpable {
@Override
public void onCancelClicked() {
- mStatusBarKeyguardViewManagerLazy.get().onCancelClicked();
+ mKeyguardViewControllerLazy.get().onCancelClicked();
}
@Override
@@ -715,7 +715,7 @@ public class KeyguardViewMediator extends SystemUI implements Dumpable {
LockPatternUtils lockPatternUtils,
BroadcastDispatcher broadcastDispatcher,
NotificationShadeWindowController notificationShadeWindowController,
- Lazy<StatusBarKeyguardViewManager> statusBarKeyguardViewManagerLazy,
+ Lazy<KeyguardViewController> statusBarKeyguardViewManagerLazy,
DismissCallbackRegistry dismissCallbackRegistry,
KeyguardUpdateMonitor keyguardUpdateMonitor, DumpManager dumpManager,
@UiBackground Executor uiBgExecutor, PowerManager powerManager,
@@ -726,7 +726,7 @@ public class KeyguardViewMediator extends SystemUI implements Dumpable {
mLockPatternUtils = lockPatternUtils;
mBroadcastDispatcher = broadcastDispatcher;
mNotificationShadeWindowController = notificationShadeWindowController;
- mStatusBarKeyguardViewManagerLazy = statusBarKeyguardViewManagerLazy;
+ mKeyguardViewControllerLazy = statusBarKeyguardViewManagerLazy;
mDismissCallbackRegistry = dismissCallbackRegistry;
mUiBgExecutor = uiBgExecutor;
mUpdateMonitor = keyguardUpdateMonitor;
@@ -1288,7 +1288,7 @@ public class KeyguardViewMediator extends SystemUI implements Dumpable {
if (mOccluded != isOccluded) {
mOccluded = isOccluded;
mUpdateMonitor.setKeyguardOccluded(isOccluded);
- mStatusBarKeyguardViewManagerLazy.get().setOccluded(isOccluded, animate
+ mKeyguardViewControllerLazy.get().setOccluded(isOccluded, animate
&& mDeviceInteractive);
adjustStatusBarLocked();
}
@@ -1359,7 +1359,7 @@ public class KeyguardViewMediator extends SystemUI implements Dumpable {
}
// if the keyguard is already showing, don't bother
- if (mStatusBarKeyguardViewManagerLazy.get().isShowing()) {
+ if (mKeyguardViewControllerLazy.get().isShowing()) {
if (DEBUG) Log.d(TAG, "doKeyguard: not showing because it is already showing");
resetStateLocked();
return;
@@ -1423,7 +1423,7 @@ public class KeyguardViewMediator extends SystemUI implements Dumpable {
mDismissCallbackRegistry.addCallback(callback);
}
mCustomMessage = message;
- mStatusBarKeyguardViewManagerLazy.get().dismissAndCollapse();
+ mKeyguardViewControllerLazy.get().dismissAndCollapse();
} else if (callback != null) {
new DismissCallbackWrapper(callback).notifyDismissError();
}
@@ -1690,7 +1690,7 @@ public class KeyguardViewMediator extends SystemUI implements Dumpable {
} else if (!mHideAnimationRun) {
mHideAnimationRun = true;
mHideAnimationRunning = true;
- mStatusBarKeyguardViewManagerLazy.get()
+ mKeyguardViewControllerLazy.get()
.startPreHideAnimation(mHideAnimationFinishedRunnable);
}
}
@@ -1847,7 +1847,7 @@ public class KeyguardViewMediator extends SystemUI implements Dumpable {
mHiding = false;
mWakeAndUnlocking = false;
setShowingLocked(true);
- mStatusBarKeyguardViewManagerLazy.get().show(options);
+ mKeyguardViewControllerLazy.get().show(options);
resetKeyguardDonePendingLocked();
mHideAnimationRun = false;
adjustStatusBarLocked();
@@ -1872,22 +1872,22 @@ public class KeyguardViewMediator extends SystemUI implements Dumpable {
public void run() {
Trace.beginSection("KeyguardViewMediator.mKeyGuardGoingAwayRunnable");
if (DEBUG) Log.d(TAG, "keyguardGoingAway");
- mStatusBarKeyguardViewManagerLazy.get().keyguardGoingAway();
+ mKeyguardViewControllerLazy.get().keyguardGoingAway();
int flags = 0;
- if (mStatusBarKeyguardViewManagerLazy.get().shouldDisableWindowAnimationsForUnlock()
+ if (mKeyguardViewControllerLazy.get().shouldDisableWindowAnimationsForUnlock()
|| (mWakeAndUnlocking && !mPulsing)) {
flags |= WindowManagerPolicyConstants
.KEYGUARD_GOING_AWAY_FLAG_NO_WINDOW_ANIMATIONS;
}
- if (mStatusBarKeyguardViewManagerLazy.get().isGoingToNotificationShade()
+ if (mKeyguardViewControllerLazy.get().isGoingToNotificationShade()
|| (mWakeAndUnlocking && mPulsing)) {
flags |= WindowManagerPolicyConstants.KEYGUARD_GOING_AWAY_FLAG_TO_SHADE;
}
- if (mStatusBarKeyguardViewManagerLazy.get().isUnlockWithWallpaper()) {
+ if (mKeyguardViewControllerLazy.get().isUnlockWithWallpaper()) {
flags |= WindowManagerPolicyConstants.KEYGUARD_GOING_AWAY_FLAG_WITH_WALLPAPER;
}
- if (mStatusBarKeyguardViewManagerLazy.get().shouldSubtleWindowAnimationsForUnlock()) {
+ if (mKeyguardViewControllerLazy.get().shouldSubtleWindowAnimationsForUnlock()) {
flags |= WindowManagerPolicyConstants
.KEYGUARD_GOING_AWAY_FLAG_SUBTLE_WINDOW_ANIMATIONS;
}
@@ -1973,7 +1973,7 @@ public class KeyguardViewMediator extends SystemUI implements Dumpable {
// Hack level over 9000: To speed up wake-and-unlock sequence, force it to report
// the next draw from here so we don't have to wait for window manager to signal
// this to our ViewRootImpl.
- mStatusBarKeyguardViewManagerLazy.get().getViewRootImpl().setReportNextDraw();
+ mKeyguardViewControllerLazy.get().getViewRootImpl().setReportNextDraw();
notifyDrawn(mDrawnCallback);
mDrawnCallback = null;
}
@@ -1987,7 +1987,7 @@ public class KeyguardViewMediator extends SystemUI implements Dumpable {
setShowingLocked(false);
mWakeAndUnlocking = false;
mDismissCallbackRegistry.notifyDismissSucceeded();
- mStatusBarKeyguardViewManagerLazy.get().hide(startTime, fadeoutDuration);
+ mKeyguardViewControllerLazy.get().hide(startTime, fadeoutDuration);
resetKeyguardDonePendingLocked();
mHideAnimationRun = false;
adjustStatusBarLocked();
@@ -2036,7 +2036,7 @@ public class KeyguardViewMediator extends SystemUI implements Dumpable {
private void handleReset() {
synchronized (KeyguardViewMediator.this) {
if (DEBUG) Log.d(TAG, "handleReset");
- mStatusBarKeyguardViewManagerLazy.get().reset(true /* hideBouncerWhenShowing */);
+ mKeyguardViewControllerLazy.get().reset(true /* hideBouncerWhenShowing */);
}
}
@@ -2049,7 +2049,7 @@ public class KeyguardViewMediator extends SystemUI implements Dumpable {
synchronized (KeyguardViewMediator.this) {
if (DEBUG) Log.d(TAG, "handleVerifyUnlock");
setShowingLocked(true);
- mStatusBarKeyguardViewManagerLazy.get().dismissAndCollapse();
+ mKeyguardViewControllerLazy.get().dismissAndCollapse();
}
Trace.endSection();
}
@@ -2057,7 +2057,7 @@ public class KeyguardViewMediator extends SystemUI implements Dumpable {
private void handleNotifyStartedGoingToSleep() {
synchronized (KeyguardViewMediator.this) {
if (DEBUG) Log.d(TAG, "handleNotifyStartedGoingToSleep");
- mStatusBarKeyguardViewManagerLazy.get().onStartedGoingToSleep();
+ mKeyguardViewControllerLazy.get().onStartedGoingToSleep();
}
}
@@ -2068,7 +2068,7 @@ public class KeyguardViewMediator extends SystemUI implements Dumpable {
private void handleNotifyFinishedGoingToSleep() {
synchronized (KeyguardViewMediator.this) {
if (DEBUG) Log.d(TAG, "handleNotifyFinishedGoingToSleep");
- mStatusBarKeyguardViewManagerLazy.get().onFinishedGoingToSleep();
+ mKeyguardViewControllerLazy.get().onFinishedGoingToSleep();
}
}
@@ -2076,7 +2076,7 @@ public class KeyguardViewMediator extends SystemUI implements Dumpable {
Trace.beginSection("KeyguardViewMediator#handleMotifyStartedWakingUp");
synchronized (KeyguardViewMediator.this) {
if (DEBUG) Log.d(TAG, "handleNotifyWakingUp");
- mStatusBarKeyguardViewManagerLazy.get().onStartedWakingUp();
+ mKeyguardViewControllerLazy.get().onStartedWakingUp();
}
Trace.endSection();
}
@@ -2085,7 +2085,7 @@ public class KeyguardViewMediator extends SystemUI implements Dumpable {
Trace.beginSection("KeyguardViewMediator#handleNotifyScreenTurningOn");
synchronized (KeyguardViewMediator.this) {
if (DEBUG) Log.d(TAG, "handleNotifyScreenTurningOn");
- mStatusBarKeyguardViewManagerLazy.get().onScreenTurningOn();
+ mKeyguardViewControllerLazy.get().onScreenTurningOn();
if (callback != null) {
if (mWakeAndUnlocking) {
mDrawnCallback = callback;
@@ -2104,7 +2104,7 @@ public class KeyguardViewMediator extends SystemUI implements Dumpable {
}
synchronized (this) {
if (DEBUG) Log.d(TAG, "handleNotifyScreenTurnedOn");
- mStatusBarKeyguardViewManagerLazy.get().onScreenTurnedOn();
+ mKeyguardViewControllerLazy.get().onScreenTurnedOn();
}
Trace.endSection();
}
@@ -2148,14 +2148,26 @@ public class KeyguardViewMediator extends SystemUI implements Dumpable {
Trace.endSection();
}
- public StatusBarKeyguardViewManager registerStatusBar(StatusBar statusBar,
+ /**
+ * Registers the StatusBar to which the Keyguard View is mounted.
+ *
+ * @param statusBar
+ * @param container
+ * @param panelView
+ * @param biometricUnlockController
+ * @param lockIconContainer
+ * @param notificationContainer
+ * @param bypassController
+ * @return the View Controller for the Keyguard View this class is mediating.
+ */
+ public KeyguardViewController registerStatusBar(StatusBar statusBar,
ViewGroup container, NotificationPanelViewController panelView,
BiometricUnlockController biometricUnlockController, ViewGroup lockIconContainer,
View notificationContainer, KeyguardBypassController bypassController) {
- mStatusBarKeyguardViewManagerLazy.get().registerStatusBar(statusBar, container, panelView,
+ mKeyguardViewControllerLazy.get().registerStatusBar(statusBar, container, panelView,
biometricUnlockController, mDismissCallbackRegistry, lockIconContainer,
notificationContainer, bypassController, mFalsingManager);
- return mStatusBarKeyguardViewManagerLazy.get();
+ return mKeyguardViewControllerLazy.get();
}
public void startKeyguardExitAnimation(long startTime, long fadeoutDuration) {
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/dagger/KeyguardModule.java b/packages/SystemUI/src/com/android/systemui/keyguard/dagger/KeyguardModule.java
index 367f46406ee8..9be478639ed8 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/dagger/KeyguardModule.java
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/dagger/KeyguardModule.java
@@ -22,6 +22,7 @@ import android.os.PowerManager;
import com.android.internal.widget.LockPatternUtils;
import com.android.keyguard.KeyguardUpdateMonitor;
+import com.android.keyguard.KeyguardViewController;
import com.android.systemui.broadcast.BroadcastDispatcher;
import com.android.systemui.dagger.qualifiers.UiBackground;
import com.android.systemui.dump.DumpManager;
@@ -30,7 +31,6 @@ import com.android.systemui.keyguard.KeyguardViewMediator;
import com.android.systemui.plugins.FalsingManager;
import com.android.systemui.statusbar.phone.NotificationShadeWindowController;
import com.android.systemui.statusbar.phone.StatusBar;
-import com.android.systemui.statusbar.phone.StatusBarKeyguardViewManager;
import com.android.systemui.util.DeviceConfigProxy;
import java.util.concurrent.Executor;
@@ -57,7 +57,7 @@ public class KeyguardModule {
LockPatternUtils lockPatternUtils,
BroadcastDispatcher broadcastDispatcher,
NotificationShadeWindowController notificationShadeWindowController,
- Lazy<StatusBarKeyguardViewManager> statusBarKeyguardViewManagerLazy,
+ Lazy<KeyguardViewController> statusBarKeyguardViewManagerLazy,
DismissCallbackRegistry dismissCallbackRegistry,
KeyguardUpdateMonitor updateMonitor,
DumpManager dumpManager,
diff --git a/packages/SystemUI/src/com/android/systemui/media/MediaControlPanel.java b/packages/SystemUI/src/com/android/systemui/media/MediaControlPanel.java
new file mode 100644
index 000000000000..a161d037fb50
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/media/MediaControlPanel.java
@@ -0,0 +1,425 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.media;
+
+import android.annotation.LayoutRes;
+import android.app.PendingIntent;
+import android.content.ComponentName;
+import android.content.Context;
+import android.content.Intent;
+import android.content.pm.PackageManager;
+import android.content.pm.ResolveInfo;
+import android.content.res.ColorStateList;
+import android.graphics.Bitmap;
+import android.graphics.drawable.Drawable;
+import android.graphics.drawable.GradientDrawable;
+import android.graphics.drawable.Icon;
+import android.graphics.drawable.RippleDrawable;
+import android.media.MediaMetadata;
+import android.media.session.MediaController;
+import android.media.session.MediaSession;
+import android.media.session.PlaybackState;
+import android.os.Handler;
+import android.util.Log;
+import android.view.KeyEvent;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.ImageButton;
+import android.widget.ImageView;
+import android.widget.LinearLayout;
+import android.widget.TextView;
+
+import androidx.core.graphics.drawable.RoundedBitmapDrawable;
+import androidx.core.graphics.drawable.RoundedBitmapDrawableFactory;
+
+import com.android.settingslib.media.MediaDevice;
+import com.android.settingslib.media.MediaOutputSliceConstants;
+import com.android.settingslib.widget.AdaptiveIcon;
+import com.android.systemui.Dependency;
+import com.android.systemui.R;
+import com.android.systemui.plugins.ActivityStarter;
+import com.android.systemui.statusbar.NotificationMediaManager;
+
+import java.util.List;
+import java.util.concurrent.Executor;
+
+/**
+ * Base media control panel for System UI
+ */
+public class MediaControlPanel implements NotificationMediaManager.MediaListener {
+ private static final String TAG = "MediaControlPanel";
+ private final NotificationMediaManager mMediaManager;
+ private final Executor mBackgroundExecutor;
+
+ private Context mContext;
+ protected LinearLayout mMediaNotifView;
+ private View mSeamless;
+ private MediaSession.Token mToken;
+ private MediaController mController;
+ private int mForegroundColor;
+ private int mBackgroundColor;
+ protected ComponentName mRecvComponent;
+
+ private final int[] mActionIds;
+
+ // Button IDs used in notifications
+ protected static final int[] NOTIF_ACTION_IDS = {
+ com.android.internal.R.id.action0,
+ com.android.internal.R.id.action1,
+ com.android.internal.R.id.action2,
+ com.android.internal.R.id.action3,
+ com.android.internal.R.id.action4
+ };
+
+ private MediaController.Callback mSessionCallback = new MediaController.Callback() {
+ @Override
+ public void onSessionDestroyed() {
+ Log.d(TAG, "session destroyed");
+ mController.unregisterCallback(mSessionCallback);
+ clearControls();
+ }
+ };
+
+ /**
+ * Initialize a new control panel
+ * @param context
+ * @param parent
+ * @param manager
+ * @param layoutId layout resource to use for this control panel
+ * @param actionIds resource IDs for action buttons in the layout
+ * @param backgroundExecutor background executor, used for processing artwork
+ */
+ public MediaControlPanel(Context context, ViewGroup parent, NotificationMediaManager manager,
+ @LayoutRes int layoutId, int[] actionIds, Executor backgroundExecutor) {
+ mContext = context;
+ LayoutInflater inflater = LayoutInflater.from(mContext);
+ mMediaNotifView = (LinearLayout) inflater.inflate(layoutId, parent, false);
+ mMediaManager = manager;
+ mActionIds = actionIds;
+ mBackgroundExecutor = backgroundExecutor;
+ }
+
+ /**
+ * Get the view used to display media controls
+ * @return the view
+ */
+ public View getView() {
+ return mMediaNotifView;
+ }
+
+ /**
+ * Get the context
+ * @return context
+ */
+ public Context getContext() {
+ return mContext;
+ }
+
+ /**
+ * Update the media panel view for the given media session
+ * @param token
+ * @param icon
+ * @param iconColor
+ * @param bgColor
+ * @param contentIntent
+ * @param appNameString
+ * @param device
+ */
+ public void setMediaSession(MediaSession.Token token, Icon icon, int iconColor,
+ int bgColor, PendingIntent contentIntent, String appNameString, MediaDevice device) {
+ mToken = token;
+ mForegroundColor = iconColor;
+ mBackgroundColor = bgColor;
+ mController = new MediaController(mContext, mToken);
+
+ MediaMetadata mediaMetadata = mController.getMetadata();
+
+ // Try to find a receiver for the media button that matches this app
+ PackageManager pm = mContext.getPackageManager();
+ Intent it = new Intent(Intent.ACTION_MEDIA_BUTTON);
+ List<ResolveInfo> info = pm.queryBroadcastReceiversAsUser(it, 0, mContext.getUser());
+ if (info != null) {
+ for (ResolveInfo inf : info) {
+ if (inf.activityInfo.packageName.equals(mController.getPackageName())) {
+ mRecvComponent = inf.getComponentInfo().getComponentName();
+ }
+ }
+ }
+
+ mController.registerCallback(mSessionCallback);
+
+ if (mediaMetadata == null) {
+ Log.e(TAG, "Media metadata was null");
+ return;
+ }
+
+ ImageView albumView = mMediaNotifView.findViewById(R.id.album_art);
+ if (albumView != null) {
+ // Resize art in a background thread
+ mBackgroundExecutor.execute(() -> processAlbumArt(mediaMetadata, albumView));
+ }
+ mMediaNotifView.setBackgroundTintList(ColorStateList.valueOf(mBackgroundColor));
+
+ // Click action
+ mMediaNotifView.setOnClickListener(v -> {
+ try {
+ contentIntent.send();
+ // Also close shade
+ mContext.sendBroadcast(new Intent(Intent.ACTION_CLOSE_SYSTEM_DIALOGS));
+ } catch (PendingIntent.CanceledException e) {
+ Log.e(TAG, "Pending intent was canceled", e);
+ }
+ });
+
+ // App icon
+ ImageView appIcon = mMediaNotifView.findViewById(R.id.icon);
+ Drawable iconDrawable = icon.loadDrawable(mContext);
+ iconDrawable.setTint(mForegroundColor);
+ appIcon.setImageDrawable(iconDrawable);
+
+ // Song name
+ TextView titleText = mMediaNotifView.findViewById(R.id.header_title);
+ String songName = mediaMetadata.getString(MediaMetadata.METADATA_KEY_TITLE);
+ titleText.setText(songName);
+ titleText.setTextColor(mForegroundColor);
+
+ // Not in mini player:
+ // App title
+ TextView appName = mMediaNotifView.findViewById(R.id.app_name);
+ if (appName != null) {
+ appName.setText(appNameString);
+ appName.setTextColor(mForegroundColor);
+ }
+
+ // Artist name
+ TextView artistText = mMediaNotifView.findViewById(R.id.header_artist);
+ if (artistText != null) {
+ String artistName = mediaMetadata.getString(MediaMetadata.METADATA_KEY_ARTIST);
+ artistText.setText(artistName);
+ artistText.setTextColor(mForegroundColor);
+ }
+
+ // Transfer chip
+ mSeamless = mMediaNotifView.findViewById(R.id.media_seamless);
+ if (mSeamless != null) {
+ mSeamless.setVisibility(View.VISIBLE);
+ updateDevice(device);
+ ActivityStarter mActivityStarter = Dependency.get(ActivityStarter.class);
+ mSeamless.setOnClickListener(v -> {
+ final Intent intent = new Intent()
+ .setAction(MediaOutputSliceConstants.ACTION_MEDIA_OUTPUT)
+ .putExtra(MediaOutputSliceConstants.EXTRA_PACKAGE_NAME,
+ mController.getPackageName())
+ .putExtra(MediaOutputSliceConstants.KEY_MEDIA_SESSION_TOKEN, mToken);
+ mActivityStarter.startActivity(intent, false, true /* dismissShade */,
+ Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK);
+ });
+ }
+
+ // Ensure is only added once
+ mMediaManager.removeCallback(this);
+ mMediaManager.addCallback(this);
+ }
+
+ /**
+ * Return the token for the current media session
+ * @return the token
+ */
+ public MediaSession.Token getMediaSessionToken() {
+ return mToken;
+ }
+
+ /**
+ * Get the current media controller
+ * @return the controller
+ */
+ public MediaController getController() {
+ return mController;
+ }
+
+ /**
+ * Get the name of the package associated with the current media controller
+ * @return the package name
+ */
+ public String getMediaPlayerPackage() {
+ return mController.getPackageName();
+ }
+
+ /**
+ * Check whether this player has an attached media session.
+ * @return whether there is a controller with a current media session.
+ */
+ public boolean hasMediaSession() {
+ return mController != null && mController.getPlaybackState() != null;
+ }
+
+ /**
+ * Check whether the media controlled by this player is currently playing
+ * @return whether it is playing, or false if no controller information
+ */
+ public boolean isPlaying() {
+ return isPlaying(mController);
+ }
+
+ /**
+ * Check whether the given controller is currently playing
+ * @param controller media controller to check
+ * @return whether it is playing, or false if no controller information
+ */
+ protected boolean isPlaying(MediaController controller) {
+ if (controller == null) {
+ return false;
+ }
+
+ PlaybackState state = controller.getPlaybackState();
+ if (state == null) {
+ return false;
+ }
+
+ return (state.getState() == PlaybackState.STATE_PLAYING);
+ }
+
+ /**
+ * Process album art for layout
+ * @param metadata media metadata
+ * @param albumView view to hold the album art
+ */
+ private void processAlbumArt(MediaMetadata metadata, ImageView albumView) {
+ Bitmap albumArt = metadata.getBitmap(MediaMetadata.METADATA_KEY_ALBUM_ART);
+ float radius = mContext.getResources().getDimension(R.dimen.qs_media_corner_radius);
+ RoundedBitmapDrawable roundedDrawable = null;
+ if (albumArt != null) {
+ Bitmap original = albumArt.copy(Bitmap.Config.ARGB_8888, true);
+ int albumSize = (int) mContext.getResources().getDimension(
+ R.dimen.qs_media_album_size);
+ Bitmap scaled = Bitmap.createScaledBitmap(original, albumSize, albumSize, false);
+ roundedDrawable = RoundedBitmapDrawableFactory.create(mContext.getResources(), scaled);
+ roundedDrawable.setCornerRadius(radius);
+ } else {
+ Log.e(TAG, "No album art available");
+ }
+
+ // Now that it's resized, update the UI
+ final RoundedBitmapDrawable result = roundedDrawable;
+ albumView.getHandler().post(() -> {
+ if (result != null) {
+ albumView.setImageDrawable(result);
+ albumView.setVisibility(View.VISIBLE);
+ } else {
+ albumView.setImageDrawable(null);
+ albumView.setVisibility(View.GONE);
+ }
+ });
+ }
+
+ /**
+ * Update the current device information
+ * @param device device information to display
+ */
+ public void updateDevice(MediaDevice device) {
+ if (mSeamless == null) {
+ return;
+ }
+ Handler handler = mSeamless.getHandler();
+ handler.post(() -> {
+ updateChipInternal(device);
+ });
+ }
+
+ private void updateChipInternal(MediaDevice device) {
+ ColorStateList fgTintList = ColorStateList.valueOf(mForegroundColor);
+
+ // Update the outline color
+ LinearLayout viewLayout = (LinearLayout) mSeamless;
+ RippleDrawable bkgDrawable = (RippleDrawable) viewLayout.getBackground();
+ GradientDrawable rect = (GradientDrawable) bkgDrawable.getDrawable(0);
+ rect.setStroke(2, mForegroundColor);
+ rect.setColor(mBackgroundColor);
+
+ ImageView iconView = mSeamless.findViewById(R.id.media_seamless_image);
+ TextView deviceName = mSeamless.findViewById(R.id.media_seamless_text);
+ deviceName.setTextColor(fgTintList);
+
+ if (device != null) {
+ Drawable icon = device.getIcon();
+ iconView.setVisibility(View.VISIBLE);
+ iconView.setImageTintList(fgTintList);
+
+ if (icon instanceof AdaptiveIcon) {
+ AdaptiveIcon aIcon = (AdaptiveIcon) icon;
+ aIcon.setBackgroundColor(mBackgroundColor);
+ iconView.setImageDrawable(aIcon);
+ } else {
+ iconView.setImageDrawable(icon);
+ }
+ deviceName.setText(device.getName());
+ } else {
+ // Reset to default
+ iconView.setVisibility(View.GONE);
+ deviceName.setText(com.android.internal.R.string.ext_media_seamless_action);
+ }
+ }
+
+ /**
+ * Put controls into a resumption state
+ */
+ public void clearControls() {
+ // Hide all the old buttons
+ for (int i = 0; i < mActionIds.length; i++) {
+ ImageButton thisBtn = mMediaNotifView.findViewById(mActionIds[i]);
+ if (thisBtn != null) {
+ thisBtn.setVisibility(View.GONE);
+ }
+ }
+
+ // Add a restart button
+ ImageButton btn = mMediaNotifView.findViewById(mActionIds[0]);
+ btn.setOnClickListener(v -> {
+ Log.d(TAG, "Attempting to restart session");
+ // Send a media button event to previously found receiver
+ if (mRecvComponent != null) {
+ Intent intent = new Intent(Intent.ACTION_MEDIA_BUTTON);
+ intent.setComponent(mRecvComponent);
+ int keyCode = KeyEvent.KEYCODE_MEDIA_PLAY;
+ intent.putExtra(
+ Intent.EXTRA_KEY_EVENT,
+ new KeyEvent(KeyEvent.ACTION_DOWN, keyCode));
+ mContext.sendBroadcast(intent);
+ } else {
+ Log.d(TAG, "No receiver to restart");
+ // If we don't have a receiver, try relaunching the activity instead
+ try {
+ mController.getSessionActivity().send();
+ } catch (PendingIntent.CanceledException e) {
+ Log.e(TAG, "Pending intent was canceled", e);
+ }
+ }
+ });
+ btn.setImageDrawable(mContext.getResources().getDrawable(R.drawable.lb_ic_play));
+ btn.setImageTintList(ColorStateList.valueOf(mForegroundColor));
+ btn.setVisibility(View.VISIBLE);
+ }
+
+ @Override
+ public void onMetadataOrStateChanged(MediaMetadata metadata, int state) {
+ if (state == PlaybackState.STATE_NONE) {
+ clearControls();
+ mMediaManager.removeCallback(this);
+ }
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/pip/PipAnimationController.java b/packages/SystemUI/src/com/android/systemui/pip/PipAnimationController.java
index 1fc1fe45bbb3..67802bc9888d 100644
--- a/packages/SystemUI/src/com/android/systemui/pip/PipAnimationController.java
+++ b/packages/SystemUI/src/com/android/systemui/pip/PipAnimationController.java
@@ -19,11 +19,8 @@ package com.android.systemui.pip;
import android.animation.Animator;
import android.animation.ValueAnimator;
import android.annotation.IntDef;
-import android.annotation.MainThread;
import android.content.Context;
import android.graphics.Rect;
-import android.os.RemoteException;
-import android.view.IWindowContainer;
import android.view.SurfaceControl;
import android.view.animation.AnimationUtils;
import android.view.animation.Interpolator;
@@ -40,7 +37,6 @@ public class PipAnimationController {
private static final float FRACTION_START = 0f;
private static final float FRACTION_END = 1f;
- public static final int DURATION_NONE = 0;
public static final int DURATION_DEFAULT_MS = 425;
public static final int ANIM_TYPE_BOUNDS = 0;
public static final int ANIM_TYPE_ALPHA = 1;
@@ -52,6 +48,20 @@ public class PipAnimationController {
@Retention(RetentionPolicy.SOURCE)
public @interface AnimationType {}
+ static final int TRANSITION_DIRECTION_NONE = 0;
+ static final int TRANSITION_DIRECTION_SAME = 1;
+ static final int TRANSITION_DIRECTION_TO_PIP = 2;
+ static final int TRANSITION_DIRECTION_TO_FULLSCREEN = 3;
+
+ @IntDef(prefix = { "TRANSITION_DIRECTION_" }, value = {
+ TRANSITION_DIRECTION_NONE,
+ TRANSITION_DIRECTION_SAME,
+ TRANSITION_DIRECTION_TO_PIP,
+ TRANSITION_DIRECTION_TO_FULLSCREEN
+ })
+ @Retention(RetentionPolicy.SOURCE)
+ @interface TransitionDirection {}
+
private final Interpolator mFastOutSlowInInterpolator;
private PipTransitionAnimator mCurrentAnimator;
@@ -61,31 +71,28 @@ public class PipAnimationController {
com.android.internal.R.interpolator.fast_out_slow_in);
}
- @MainThread
- PipTransitionAnimator getAnimator(IWindowContainer wc, boolean scheduleFinishPip,
+ @SuppressWarnings("unchecked")
+ PipTransitionAnimator getAnimator(SurfaceControl leash,
Rect destinationBounds, float alphaStart, float alphaEnd) {
if (mCurrentAnimator == null) {
mCurrentAnimator = setupPipTransitionAnimator(
- PipTransitionAnimator.ofAlpha(wc, scheduleFinishPip,
- destinationBounds, alphaStart, alphaEnd));
+ PipTransitionAnimator.ofAlpha(leash, destinationBounds, alphaStart, alphaEnd));
} else if (mCurrentAnimator.getAnimationType() == ANIM_TYPE_ALPHA
&& mCurrentAnimator.isRunning()) {
mCurrentAnimator.updateEndValue(alphaEnd);
} else {
mCurrentAnimator.cancel();
mCurrentAnimator = setupPipTransitionAnimator(
- PipTransitionAnimator.ofAlpha(wc, scheduleFinishPip,
- destinationBounds, alphaStart, alphaEnd));
+ PipTransitionAnimator.ofAlpha(leash, destinationBounds, alphaStart, alphaEnd));
}
return mCurrentAnimator;
}
- @MainThread
- PipTransitionAnimator getAnimator(IWindowContainer wc, boolean scheduleFinishPip,
- Rect startBounds, Rect endBounds) {
+ @SuppressWarnings("unchecked")
+ PipTransitionAnimator getAnimator(SurfaceControl leash, Rect startBounds, Rect endBounds) {
if (mCurrentAnimator == null) {
mCurrentAnimator = setupPipTransitionAnimator(
- PipTransitionAnimator.ofBounds(wc, scheduleFinishPip, startBounds, endBounds));
+ PipTransitionAnimator.ofBounds(leash, startBounds, endBounds));
} else if (mCurrentAnimator.getAnimationType() == ANIM_TYPE_BOUNDS
&& mCurrentAnimator.isRunning()) {
mCurrentAnimator.setDestinationBounds(endBounds);
@@ -94,7 +101,7 @@ public class PipAnimationController {
} else {
mCurrentAnimator.cancel();
mCurrentAnimator = setupPipTransitionAnimator(
- PipTransitionAnimator.ofBounds(wc, scheduleFinishPip, startBounds, endBounds));
+ PipTransitionAnimator.ofBounds(leash, startBounds, endBounds));
}
return mCurrentAnimator;
}
@@ -116,18 +123,18 @@ public class PipAnimationController {
/**
* Called when PiP animation is started.
*/
- public void onPipAnimationStart(IWindowContainer wc, PipTransitionAnimator animator) {}
+ public void onPipAnimationStart(PipTransitionAnimator animator) {}
/**
* Called when PiP animation is ended.
*/
- public void onPipAnimationEnd(IWindowContainer wc, SurfaceControl.Transaction tx,
+ public void onPipAnimationEnd(SurfaceControl.Transaction tx,
PipTransitionAnimator animator) {}
/**
* Called when PiP animation is cancelled.
*/
- public void onPipAnimationCancel(IWindowContainer wc, PipTransitionAnimator animator) {}
+ public void onPipAnimationCancel(PipTransitionAnimator animator) {}
}
/**
@@ -137,8 +144,6 @@ public class PipAnimationController {
public abstract static class PipTransitionAnimator<T> extends ValueAnimator implements
ValueAnimator.AnimatorUpdateListener,
ValueAnimator.AnimatorListener {
- private final IWindowContainer mWindowContainer;
- private final boolean mScheduleFinishPip;
private final SurfaceControl mLeash;
private final @AnimationType int mAnimationType;
private final Rect mDestinationBounds = new Rect();
@@ -148,24 +153,20 @@ public class PipAnimationController {
private T mCurrentValue;
private PipAnimationCallback mPipAnimationCallback;
private SurfaceControlTransactionFactory mSurfaceControlTransactionFactory;
+ private @TransitionDirection int mTransitionDirection;
+ private int mCornerRadius;
- private PipTransitionAnimator(IWindowContainer wc, boolean scheduleFinishPip,
- @AnimationType int animationType, Rect destinationBounds,
- T startValue, T endValue) {
- mWindowContainer = wc;
- mScheduleFinishPip = scheduleFinishPip;
- try {
- mLeash = wc.getLeash();
- mAnimationType = animationType;
- mDestinationBounds.set(destinationBounds);
- mStartValue = startValue;
- mEndValue = endValue;
- addListener(this);
- addUpdateListener(this);
- mSurfaceControlTransactionFactory = SurfaceControl.Transaction::new;
- } catch (RemoteException e) {
- throw new RuntimeException(e);
- }
+ private PipTransitionAnimator(SurfaceControl leash, @AnimationType int animationType,
+ Rect destinationBounds, T startValue, T endValue) {
+ mLeash = leash;
+ mAnimationType = animationType;
+ mDestinationBounds.set(destinationBounds);
+ mStartValue = startValue;
+ mEndValue = endValue;
+ addListener(this);
+ addUpdateListener(this);
+ mSurfaceControlTransactionFactory = SurfaceControl.Transaction::new;
+ mTransitionDirection = TRANSITION_DIRECTION_NONE;
}
@Override
@@ -173,7 +174,7 @@ public class PipAnimationController {
mCurrentValue = mStartValue;
applySurfaceControlTransaction(mLeash, newSurfaceControlTransaction(), FRACTION_START);
if (mPipAnimationCallback != null) {
- mPipAnimationCallback.onPipAnimationStart(mWindowContainer, this);
+ mPipAnimationCallback.onPipAnimationStart(this);
}
}
@@ -189,14 +190,14 @@ public class PipAnimationController {
final SurfaceControl.Transaction tx = newSurfaceControlTransaction();
applySurfaceControlTransaction(mLeash, tx, FRACTION_END);
if (mPipAnimationCallback != null) {
- mPipAnimationCallback.onPipAnimationEnd(mWindowContainer, tx, this);
+ mPipAnimationCallback.onPipAnimationEnd(tx, this);
}
}
@Override
public void onAnimationCancel(Animator animation) {
if (mPipAnimationCallback != null) {
- mPipAnimationCallback.onPipAnimationCancel(mWindowContainer, this);
+ mPipAnimationCallback.onPipAnimationCancel(this);
}
}
@@ -211,8 +212,15 @@ public class PipAnimationController {
return this;
}
- boolean shouldScheduleFinishPip() {
- return mScheduleFinishPip;
+ @TransitionDirection int getTransitionDirection() {
+ return mTransitionDirection;
+ }
+
+ PipTransitionAnimator<T> setTransitionDirection(@TransitionDirection int direction) {
+ if (direction != TRANSITION_DIRECTION_SAME) {
+ mTransitionDirection = direction;
+ }
+ return this;
}
T getStartValue() {
@@ -235,6 +243,19 @@ public class PipAnimationController {
mCurrentValue = value;
}
+ int getCornerRadius() {
+ return mCornerRadius;
+ }
+
+ PipTransitionAnimator<T> setCornerRadius(int cornerRadius) {
+ mCornerRadius = cornerRadius;
+ return this;
+ }
+
+ boolean shouldApplyCornerRadius() {
+ return mTransitionDirection != TRANSITION_DIRECTION_TO_FULLSCREEN;
+ }
+
/**
* Updates the {@link #mEndValue}.
*
@@ -260,9 +281,9 @@ public class PipAnimationController {
abstract void applySurfaceControlTransaction(SurfaceControl leash,
SurfaceControl.Transaction tx, float fraction);
- static PipTransitionAnimator<Float> ofAlpha(IWindowContainer wc, boolean scheduleFinishPip,
+ static PipTransitionAnimator<Float> ofAlpha(SurfaceControl leash,
Rect destinationBounds, float startValue, float endValue) {
- return new PipTransitionAnimator<Float>(wc, scheduleFinishPip, ANIM_TYPE_ALPHA,
+ return new PipTransitionAnimator<Float>(leash, ANIM_TYPE_ALPHA,
destinationBounds, startValue, endValue) {
@Override
void applySurfaceControlTransaction(SurfaceControl leash,
@@ -275,16 +296,18 @@ public class PipAnimationController {
final Rect bounds = getDestinationBounds();
tx.setPosition(leash, bounds.left, bounds.top)
.setWindowCrop(leash, bounds.width(), bounds.height());
+ tx.setCornerRadius(leash,
+ shouldApplyCornerRadius() ? getCornerRadius() : 0);
}
tx.apply();
}
};
}
- static PipTransitionAnimator<Rect> ofBounds(IWindowContainer wc, boolean scheduleFinishPip,
+ static PipTransitionAnimator<Rect> ofBounds(SurfaceControl leash,
Rect startValue, Rect endValue) {
// construct new Rect instances in case they are recycled
- return new PipTransitionAnimator<Rect>(wc, scheduleFinishPip, ANIM_TYPE_BOUNDS,
+ return new PipTransitionAnimator<Rect>(leash, ANIM_TYPE_BOUNDS,
endValue, new Rect(startValue), new Rect(endValue)) {
private final Rect mTmpRect = new Rect();
@@ -308,6 +331,8 @@ public class PipAnimationController {
if (Float.compare(fraction, FRACTION_START) == 0) {
// Ensure the start condition
tx.setAlpha(leash, 1f);
+ tx.setCornerRadius(leash,
+ shouldApplyCornerRadius() ? getCornerRadius() : 0);
}
tx.apply();
}
diff --git a/packages/SystemUI/src/com/android/systemui/pip/PipBoundsHandler.java b/packages/SystemUI/src/com/android/systemui/pip/PipBoundsHandler.java
index 60c1a940d2c6..fb348f483c46 100644
--- a/packages/SystemUI/src/com/android/systemui/pip/PipBoundsHandler.java
+++ b/packages/SystemUI/src/com/android/systemui/pip/PipBoundsHandler.java
@@ -42,6 +42,8 @@ import android.view.WindowManagerGlobal;
import java.io.PrintWriter;
+import javax.inject.Inject;
+
/**
* Handles bounds calculation for PIP on Phone and other form factors, it keeps tracking variant
* state changes originated from Window Manager and is the source of truth for PiP window bounds.
@@ -81,9 +83,10 @@ public class PipBoundsHandler {
private boolean mIsShelfShowing;
private int mShelfHeight;
- public PipBoundsHandler(Context context) {
+ @Inject
+ public PipBoundsHandler(Context context, PipSnapAlgorithm pipSnapAlgorithm) {
mContext = context;
- mSnapAlgorithm = new PipSnapAlgorithm(context);
+ mSnapAlgorithm = pipSnapAlgorithm;
mWindowManager = WindowManagerGlobal.getWindowManagerService();
reloadResources();
// Initialize the aspect ratio to the default aspect ratio. Don't do this in reload
@@ -225,8 +228,8 @@ public class PipBoundsHandler {
*/
Rect getDestinationBounds(float aspectRatio, Rect bounds) {
final Rect destinationBounds;
+ final Rect defaultBounds = getDefaultBounds(mReentrySnapFraction, mReentrySize);
if (bounds == null) {
- final Rect defaultBounds = getDefaultBounds(mReentrySnapFraction, mReentrySize);
destinationBounds = new Rect(defaultBounds);
} else {
destinationBounds = new Rect(bounds);
diff --git a/packages/SystemUI/src/com/android/systemui/pip/PipSnapAlgorithm.java b/packages/SystemUI/src/com/android/systemui/pip/PipSnapAlgorithm.java
index 6b89718acee8..6df6b5ae76cc 100644
--- a/packages/SystemUI/src/com/android/systemui/pip/PipSnapAlgorithm.java
+++ b/packages/SystemUI/src/com/android/systemui/pip/PipSnapAlgorithm.java
@@ -19,14 +19,13 @@ package com.android.systemui.pip;
import android.content.Context;
import android.content.res.Configuration;
import android.content.res.Resources;
-import android.graphics.Point;
import android.graphics.PointF;
import android.graphics.Rect;
import android.util.Size;
-import android.view.Gravity;
import java.io.PrintWriter;
-import java.util.ArrayList;
+
+import javax.inject.Inject;
/**
* Calculates the snap targets and the snap position for the PIP given a position and a velocity.
@@ -34,35 +33,15 @@ import java.util.ArrayList;
*/
public class PipSnapAlgorithm {
- // The below SNAP_MODE_* constants correspond to the config resource value
- // config_pictureInPictureSnapMode and should not be changed independently.
- // Allows snapping to the four corners
- private static final int SNAP_MODE_CORNERS_ONLY = 0;
- // Allows snapping to the four corners and the mid-points on the long edge in each orientation
- private static final int SNAP_MODE_CORNERS_AND_SIDES = 1;
- // Allows snapping to anywhere along the edge of the screen
- private static final int SNAP_MODE_EDGE = 2;
- // Allows snapping anywhere along the edge of the screen and magnets towards corners
- private static final int SNAP_MODE_EDGE_MAGNET_CORNERS = 3;
- // Allows snapping on the long edge in each orientation and magnets towards corners
- private static final int SNAP_MODE_LONG_EDGE_MAGNET_CORNERS = 4;
-
- // Threshold to magnet to a corner
- private static final float CORNER_MAGNET_THRESHOLD = 0.3f;
-
private final Context mContext;
- private final ArrayList<Integer> mSnapGravities = new ArrayList<>();
- private final int mDefaultSnapMode = SNAP_MODE_EDGE_MAGNET_CORNERS;
- private int mSnapMode = mDefaultSnapMode;
-
private final float mDefaultSizePercent;
private final float mMinAspectRatioForMinSize;
private final float mMaxAspectRatioForMinSize;
- private final int mFlingDeceleration;
private int mOrientation = Configuration.ORIENTATION_UNDEFINED;
+ @Inject
public PipSnapAlgorithm(Context context) {
Resources res = context.getResources();
mContext = context;
@@ -71,8 +50,6 @@ public class PipSnapAlgorithm {
mMaxAspectRatioForMinSize = res.getFloat(
com.android.internal.R.dimen.config_pictureInPictureAspectRatioLimitForMinSize);
mMinAspectRatioForMinSize = 1f / mMaxAspectRatioForMinSize;
- mFlingDeceleration = mContext.getResources().getDimensionPixelSize(
- com.android.internal.R.dimen.pip_fling_deceleration);
onConfigurationChanged();
}
@@ -82,144 +59,6 @@ public class PipSnapAlgorithm {
public void onConfigurationChanged() {
Resources res = mContext.getResources();
mOrientation = res.getConfiguration().orientation;
- mSnapMode = res.getInteger(com.android.internal.R.integer.config_pictureInPictureSnapMode);
- calculateSnapTargets();
- }
-
- /**
- * @return the closest absolute snap stack bounds for the given {@param stackBounds} moving at
- * the given {@param velocityX} and {@param velocityY}. The {@param movementBounds} should be
- * those for the given {@param stackBounds}.
- */
- public Rect findClosestSnapBounds(Rect movementBounds, Rect stackBounds, float velocityX,
- float velocityY, Point dragStartPosition) {
- final Rect intersectStackBounds = new Rect(stackBounds);
- final Point intersect = getEdgeIntersect(stackBounds, movementBounds, velocityX, velocityY,
- dragStartPosition);
- intersectStackBounds.offsetTo(intersect.x, intersect.y);
- return findClosestSnapBounds(movementBounds, intersectStackBounds);
- }
-
- /**
- * @return The point along the {@param movementBounds} that the PIP would intersect with based
- * on the provided {@param velX}, {@param velY} along with the position of the PIP when
- * the gesture started, {@param dragStartPosition}.
- */
- public Point getEdgeIntersect(Rect stackBounds, Rect movementBounds, float velX, float velY,
- Point dragStartPosition) {
- final boolean isLandscape = mOrientation == Configuration.ORIENTATION_LANDSCAPE;
- final int x = stackBounds.left;
- final int y = stackBounds.top;
-
- // Find the line of movement the PIP is on. Line defined by: y = slope * x + yIntercept
- final float slope = velY / velX; // slope = rise / run
- final float yIntercept = y - slope * x; // rearrange line equation for yIntercept
- // The PIP can have two intercept points:
- // 1) Where the line intersects with one of the edges of the screen (vertical line)
- Point vertPoint = new Point();
- // 2) Where the line intersects with the top or bottom of the screen (horizontal line)
- Point horizPoint = new Point();
-
- // Find the vertical line intersection, x will be one of the edges
- vertPoint.x = velX > 0 ? movementBounds.right : movementBounds.left;
- // Sub in x in our line equation to determine y position
- vertPoint.y = findY(slope, yIntercept, vertPoint.x);
-
- // Find the horizontal line intersection, y will be the top or bottom of the screen
- horizPoint.y = velY > 0 ? movementBounds.bottom : movementBounds.top;
- // Sub in y in our line equation to determine x position
- horizPoint.x = findX(slope, yIntercept, horizPoint.y);
-
- // Now pick one of these points -- first determine if we're flinging along the current edge.
- // Only fling along current edge if it's a direction with space for the PIP to move to
- int maxDistance;
- if (isLandscape) {
- maxDistance = velX > 0
- ? movementBounds.right - stackBounds.left
- : stackBounds.left - movementBounds.left;
- } else {
- maxDistance = velY > 0
- ? movementBounds.bottom - stackBounds.top
- : stackBounds.top - movementBounds.top;
- }
- if (maxDistance > 0) {
- // Only fling along the current edge if the start and end point are on the same side
- final int startPoint = isLandscape ? dragStartPosition.y : dragStartPosition.x;
- final int endPoint = isLandscape ? horizPoint.y : horizPoint.x;
- final int center = movementBounds.centerX();
- if ((startPoint < center && endPoint < center)
- || (startPoint > center && endPoint > center)) {
- // We are flinging along the current edge, figure out how far it should travel
- // based on velocity and assumed deceleration.
- int distance = (int) (0 - Math.pow(isLandscape ? velX : velY, 2))
- / (2 * mFlingDeceleration);
- distance = Math.min(distance, maxDistance);
- // Adjust the point for the distance
- if (isLandscape) {
- horizPoint.x = stackBounds.left + (velX > 0 ? distance : -distance);
- } else {
- horizPoint.y = stackBounds.top + (velY > 0 ? distance : -distance);
- }
- return horizPoint;
- }
- }
- // If we're not flinging along the current edge, find the closest point instead.
- final double distanceVert = Math.hypot(vertPoint.x - x, vertPoint.y - y);
- final double distanceHoriz = Math.hypot(horizPoint.x - x, horizPoint.y - y);
- return Math.abs(distanceVert) > Math.abs(distanceHoriz) ? horizPoint : vertPoint;
- }
-
- private int findY(float slope, float yIntercept, float x) {
- return (int) ((slope * x) + yIntercept);
- }
-
- private int findX(float slope, float yIntercept, float y) {
- return (int) ((y - yIntercept) / slope);
- }
-
- /**
- * @return the closest absolute snap stack bounds for the given {@param stackBounds}. The
- * {@param movementBounds} should be those for the given {@param stackBounds}.
- */
- public Rect findClosestSnapBounds(Rect movementBounds, Rect stackBounds) {
- final Rect pipBounds = new Rect(movementBounds.left, movementBounds.top,
- movementBounds.right + stackBounds.width(),
- movementBounds.bottom + stackBounds.height());
- final Rect newBounds = new Rect(stackBounds);
- if (mSnapMode == SNAP_MODE_LONG_EDGE_MAGNET_CORNERS
- || mSnapMode == SNAP_MODE_EDGE_MAGNET_CORNERS) {
- final Rect tmpBounds = new Rect();
- final Point[] snapTargets = new Point[mSnapGravities.size()];
- for (int i = 0; i < mSnapGravities.size(); i++) {
- Gravity.apply(mSnapGravities.get(i), stackBounds.width(), stackBounds.height(),
- pipBounds, 0, 0, tmpBounds);
- snapTargets[i] = new Point(tmpBounds.left, tmpBounds.top);
- }
- Point snapTarget = findClosestPoint(stackBounds.left, stackBounds.top, snapTargets);
- float distance = distanceToPoint(snapTarget, stackBounds.left, stackBounds.top);
- final float thresh = Math.max(stackBounds.width(), stackBounds.height())
- * CORNER_MAGNET_THRESHOLD;
- if (distance < thresh) {
- newBounds.offsetTo(snapTarget.x, snapTarget.y);
- } else {
- snapRectToClosestEdge(stackBounds, movementBounds, newBounds);
- }
- } else if (mSnapMode == SNAP_MODE_EDGE) {
- // Find the closest edge to the given stack bounds and snap to it
- snapRectToClosestEdge(stackBounds, movementBounds, newBounds);
- } else {
- // Find the closest snap point
- final Rect tmpBounds = new Rect();
- final Point[] snapTargets = new Point[mSnapGravities.size()];
- for (int i = 0; i < mSnapGravities.size(); i++) {
- Gravity.apply(mSnapGravities.get(i), stackBounds.width(), stackBounds.height(),
- pipBounds, 0, 0, tmpBounds);
- snapTargets[i] = new Point(tmpBounds.left, tmpBounds.top);
- }
- Point snapTarget = findClosestPoint(stackBounds.left, stackBounds.top, snapTargets);
- newBounds.offsetTo(snapTarget.x, snapTarget.y);
- }
- return newBounds;
}
/**
@@ -356,26 +195,10 @@ public class PipSnapAlgorithm {
}
/**
- * @return the closest point in {@param points} to the given {@param x} and {@param y}.
- */
- private Point findClosestPoint(int x, int y, Point[] points) {
- Point closestPoint = null;
- float minDistance = Float.MAX_VALUE;
- for (Point p : points) {
- float distance = distanceToPoint(p, x, y);
- if (distance < minDistance) {
- closestPoint = p;
- minDistance = distance;
- }
- }
- return closestPoint;
- }
-
- /**
* Snaps the {@param stackBounds} to the closest edge of the {@param movementBounds} and writes
* the new bounds out to {@param boundsOut}.
*/
- private void snapRectToClosestEdge(Rect stackBounds, Rect movementBounds, Rect boundsOut) {
+ public void snapRectToClosestEdge(Rect stackBounds, Rect movementBounds, Rect boundsOut) {
final int boundedLeft = Math.max(movementBounds.left, Math.min(movementBounds.right,
stackBounds.left));
final int boundedTop = Math.max(movementBounds.top, Math.min(movementBounds.bottom,
@@ -387,15 +210,7 @@ public class PipSnapAlgorithm {
final int fromTop = Math.abs(stackBounds.top - movementBounds.top);
final int fromRight = Math.abs(movementBounds.right - stackBounds.left);
final int fromBottom = Math.abs(movementBounds.bottom - stackBounds.top);
- int shortest;
- if (mSnapMode == SNAP_MODE_LONG_EDGE_MAGNET_CORNERS) {
- // Only check longest edges
- shortest = (mOrientation == Configuration.ORIENTATION_LANDSCAPE)
- ? Math.min(fromTop, fromBottom)
- : Math.min(fromLeft, fromRight);
- } else {
- shortest = Math.min(Math.min(fromLeft, fromRight), Math.min(fromTop, fromBottom));
- }
+ final int shortest = Math.min(Math.min(fromLeft, fromRight), Math.min(fromTop, fromBottom));
if (shortest == fromLeft) {
boundsOut.offsetTo(movementBounds.left, boundedTop);
} else if (shortest == fromTop) {
@@ -407,46 +222,9 @@ public class PipSnapAlgorithm {
}
}
- /**
- * @return the distance between point {@param p} and the given {@param x} and {@param y}.
- */
- private float distanceToPoint(Point p, int x, int y) {
- return PointF.length(p.x - x, p.y - y);
- }
-
- /**
- * Calculate the snap targets for the discrete snap modes.
- */
- private void calculateSnapTargets() {
- mSnapGravities.clear();
- switch (mSnapMode) {
- case SNAP_MODE_CORNERS_AND_SIDES:
- if (mOrientation == Configuration.ORIENTATION_LANDSCAPE) {
- mSnapGravities.add(Gravity.TOP | Gravity.CENTER_HORIZONTAL);
- mSnapGravities.add(Gravity.BOTTOM | Gravity.CENTER_HORIZONTAL);
- } else {
- mSnapGravities.add(Gravity.CENTER_VERTICAL | Gravity.LEFT);
- mSnapGravities.add(Gravity.CENTER_VERTICAL | Gravity.RIGHT);
- }
- // Fall through
- case SNAP_MODE_CORNERS_ONLY:
- case SNAP_MODE_EDGE_MAGNET_CORNERS:
- case SNAP_MODE_LONG_EDGE_MAGNET_CORNERS:
- mSnapGravities.add(Gravity.TOP | Gravity.LEFT);
- mSnapGravities.add(Gravity.TOP | Gravity.RIGHT);
- mSnapGravities.add(Gravity.BOTTOM | Gravity.LEFT);
- mSnapGravities.add(Gravity.BOTTOM | Gravity.RIGHT);
- break;
- default:
- // Skip otherwise
- break;
- }
- }
-
public void dump(PrintWriter pw, String prefix) {
final String innerPrefix = prefix + " ";
pw.println(prefix + PipSnapAlgorithm.class.getSimpleName());
- pw.println(innerPrefix + "mSnapMode=" + mSnapMode);
pw.println(innerPrefix + "mOrientation=" + mOrientation);
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/pip/PipTaskOrganizer.java b/packages/SystemUI/src/com/android/systemui/pip/PipTaskOrganizer.java
index 836485a46e36..cc5664249f00 100644
--- a/packages/SystemUI/src/com/android/systemui/pip/PipTaskOrganizer.java
+++ b/packages/SystemUI/src/com/android/systemui/pip/PipTaskOrganizer.java
@@ -19,6 +19,10 @@ package com.android.systemui.pip;
import static com.android.systemui.pip.PipAnimationController.ANIM_TYPE_ALPHA;
import static com.android.systemui.pip.PipAnimationController.ANIM_TYPE_BOUNDS;
import static com.android.systemui.pip.PipAnimationController.DURATION_DEFAULT_MS;
+import static com.android.systemui.pip.PipAnimationController.TRANSITION_DIRECTION_NONE;
+import static com.android.systemui.pip.PipAnimationController.TRANSITION_DIRECTION_SAME;
+import static com.android.systemui.pip.PipAnimationController.TRANSITION_DIRECTION_TO_FULLSCREEN;
+import static com.android.systemui.pip.PipAnimationController.TRANSITION_DIRECTION_TO_PIP;
import android.annotation.NonNull;
import android.annotation.Nullable;
@@ -29,18 +33,25 @@ import android.app.PictureInPictureParams;
import android.content.Context;
import android.graphics.Rect;
import android.os.Handler;
+import android.os.IBinder;
import android.os.Looper;
import android.os.RemoteException;
import android.util.Log;
-import android.view.DisplayInfo;
import android.view.ITaskOrganizer;
import android.view.IWindowContainer;
import android.view.SurfaceControl;
import android.view.WindowContainerTransaction;
+import com.android.internal.os.SomeArgs;
+import com.android.systemui.R;
+import com.android.systemui.pip.phone.PipUpdateThread;
+
import java.util.ArrayList;
+import java.util.HashMap;
import java.util.List;
+import java.util.Map;
import java.util.Objects;
+import java.util.function.Consumer;
/**
* Manages PiP tasks such as resize and offset.
@@ -56,19 +67,26 @@ import java.util.Objects;
public class PipTaskOrganizer extends ITaskOrganizer.Stub {
private static final String TAG = PipTaskOrganizer.class.getSimpleName();
+ private static final int MSG_RESIZE_IMMEDIATE = 1;
+ private static final int MSG_RESIZE_ANIMATE = 2;
+ private static final int MSG_OFFSET_ANIMATE = 3;
+ private static final int MSG_FINISH_RESIZE = 4;
+
private final Handler mMainHandler;
+ private final Handler mUpdateHandler;
private final ITaskOrganizerController mTaskOrganizerController;
private final PipBoundsHandler mPipBoundsHandler;
private final PipAnimationController mPipAnimationController;
private final List<PipTransitionCallback> mPipTransitionCallbacks = new ArrayList<>();
- private final Rect mDisplayBounds = new Rect();
private final Rect mLastReportedBounds = new Rect();
+ private final int mCornerRadius;
+ private final Map<IBinder, Rect> mBoundsToRestore = new HashMap<>();
+ // These callbacks are called on the update thread
private final PipAnimationController.PipAnimationCallback mPipAnimationCallback =
new PipAnimationController.PipAnimationCallback() {
@Override
- public void onPipAnimationStart(IWindowContainer wc,
- PipAnimationController.PipTransitionAnimator animator) {
+ public void onPipAnimationStart(PipAnimationController.PipTransitionAnimator animator) {
mMainHandler.post(() -> {
for (int i = mPipTransitionCallbacks.size() - 1; i >= 0; i--) {
final PipTransitionCallback callback = mPipTransitionCallbacks.get(i);
@@ -78,7 +96,7 @@ public class PipTaskOrganizer extends ITaskOrganizer.Stub {
}
@Override
- public void onPipAnimationEnd(IWindowContainer wc, SurfaceControl.Transaction tx,
+ public void onPipAnimationEnd(SurfaceControl.Transaction tx,
PipAnimationController.PipTransitionAnimator animator) {
mMainHandler.post(() -> {
for (int i = mPipTransitionCallbacks.size() - 1; i >= 0; i--) {
@@ -86,13 +104,11 @@ public class PipTaskOrganizer extends ITaskOrganizer.Stub {
callback.onPipTransitionFinished();
}
});
- final Rect destinationBounds = animator.getDestinationBounds();
- finishResizeInternal(destinationBounds, wc, tx, animator.shouldScheduleFinishPip());
+ finishResize(tx, animator.getDestinationBounds(), animator.getTransitionDirection());
}
@Override
- public void onPipAnimationCancel(IWindowContainer wc,
- PipAnimationController.PipTransitionAnimator animator) {
+ public void onPipAnimationCancel(PipAnimationController.PipTransitionAnimator animator) {
mMainHandler.post(() -> {
for (int i = mPipTransitionCallbacks.size() - 1; i >= 0; i--) {
final PipTransitionCallback callback = mPipTransitionCallbacks.get(i);
@@ -102,28 +118,72 @@ public class PipTaskOrganizer extends ITaskOrganizer.Stub {
}
};
+ @SuppressWarnings("unchecked")
+ private Handler.Callback mUpdateCallbacks = (msg) -> {
+ SomeArgs args = (SomeArgs) msg.obj;
+ Consumer<Rect> updateBoundsCallback = (Consumer<Rect>) args.arg1;
+ switch (msg.what) {
+ case MSG_RESIZE_IMMEDIATE: {
+ Rect toBounds = (Rect) args.arg2;
+ resizePip(toBounds);
+ if (updateBoundsCallback != null) {
+ updateBoundsCallback.accept(toBounds);
+ }
+ break;
+ }
+ case MSG_RESIZE_ANIMATE: {
+ Rect currentBounds = (Rect) args.arg2;
+ Rect toBounds = (Rect) args.arg3;
+ int duration = args.argi2;
+ animateResizePip(currentBounds, toBounds, args.argi1 /* direction */, duration);
+ if (updateBoundsCallback != null) {
+ updateBoundsCallback.accept(toBounds);
+ }
+ break;
+ }
+ case MSG_OFFSET_ANIMATE: {
+ Rect originalBounds = (Rect) args.arg2;
+ final int offset = args.argi1;
+ final int duration = args.argi2;
+ offsetPip(originalBounds, 0 /* xOffset */, offset, duration);
+ Rect toBounds = new Rect(originalBounds);
+ toBounds.offset(0, offset);
+ if (updateBoundsCallback != null) {
+ updateBoundsCallback.accept(toBounds);
+ }
+ break;
+ }
+ case MSG_FINISH_RESIZE: {
+ SurfaceControl.Transaction tx = (SurfaceControl.Transaction) args.arg2;
+ Rect toBounds = (Rect) args.arg3;
+ finishResize(tx, toBounds, args.argi1 /* direction */);
+ if (updateBoundsCallback != null) {
+ updateBoundsCallback.accept(toBounds);
+ }
+ break;
+ }
+ }
+ args.recycle();
+ return true;
+ };
+
private ActivityManager.RunningTaskInfo mTaskInfo;
+ private IWindowContainer mToken;
+ private SurfaceControl mLeash;
+ private boolean mInPip;
private @PipAnimationController.AnimationType int mOneShotAnimationType = ANIM_TYPE_BOUNDS;
public PipTaskOrganizer(Context context, @NonNull PipBoundsHandler boundsHandler) {
mMainHandler = new Handler(Looper.getMainLooper());
+ mUpdateHandler = new Handler(PipUpdateThread.get().getLooper(), mUpdateCallbacks);
mTaskOrganizerController = ActivityTaskManager.getTaskOrganizerController();
mPipBoundsHandler = boundsHandler;
mPipAnimationController = new PipAnimationController(context);
+ mCornerRadius = context.getResources().getDimensionPixelSize(R.dimen.pip_corner_radius);
}
- /**
- * Offset the PiP window, animate if the given duration is not {@link #DURATION_NONE}
- */
- public void offsetPinnedStack(Rect originalBounds, int xOffset, int yOffset, int durationMs) {
- if (mTaskInfo == null) {
- Log.w(TAG, "mTaskInfo is not set");
- return;
- }
- final Rect destinationBounds = new Rect(originalBounds);
- destinationBounds.offset(xOffset, yOffset);
- animateResizePipInternal(mTaskInfo.token, false /* scheduleFinishPip*/,
- originalBounds, destinationBounds, durationMs);
+ public Handler getUpdateHandler() {
+ return mUpdateHandler;
}
/**
@@ -135,35 +195,14 @@ public class PipTaskOrganizer extends ITaskOrganizer.Stub {
/**
* Sets the preferred animation type for one time.
- * This is typically used to set the animation type to {@link #ANIM_TYPE_ALPHA}.
+ * This is typically used to set the animation type to
+ * {@link PipAnimationController#ANIM_TYPE_ALPHA}.
*/
public void setOneShotAnimationType(@PipAnimationController.AnimationType int animationType) {
mOneShotAnimationType = animationType;
}
/**
- * Updates the display dimension with given {@link DisplayInfo}
- */
- public void onDisplayInfoChanged(DisplayInfo displayInfo) {
- final Rect newDisplayBounds = new Rect(0, 0,
- displayInfo.logicalWidth, displayInfo.logicalHeight);
- if (!mDisplayBounds.equals(newDisplayBounds)) {
- // Updates the exiting PiP animation in case the screen rotation changes in the middle.
- // It's a legit case that PiP window is in portrait mode on home screen and
- // the application requests landscape onces back to fullscreen mode.
- final PipAnimationController.PipTransitionAnimator animator =
- mPipAnimationController.getCurrentAnimator();
- if (animator != null
- && animator.getAnimationType() == ANIM_TYPE_BOUNDS
- && animator.getDestinationBounds().equals(mDisplayBounds)) {
- animator.updateEndValue(newDisplayBounds);
- animator.setDestinationBounds(newDisplayBounds);
- }
- }
- mDisplayBounds.set(newDisplayBounds);
- }
-
- /**
* Callback to issue the final {@link WindowContainerTransaction} on end of movements.
* @param destinationBounds the final bounds.
*/
@@ -171,7 +210,7 @@ public class PipTaskOrganizer extends ITaskOrganizer.Stub {
try {
mLastReportedBounds.set(destinationBounds);
final WindowContainerTransaction wct = new WindowContainerTransaction();
- wct.setBounds(mTaskInfo.token, destinationBounds);
+ wct.setBounds(mToken, destinationBounds);
mTaskOrganizerController.applyContainerTransaction(wct, null /* ITaskOrganizer */);
} catch (RemoteException e) {
Log.w(TAG, "Failed to apply window container transaction", e);
@@ -185,14 +224,23 @@ public class PipTaskOrganizer extends ITaskOrganizer.Stub {
getAspectRatioOrDefault(info.pictureInPictureParams), null /* bounds */);
Objects.requireNonNull(destinationBounds, "Missing destination bounds");
mTaskInfo = info;
+ mToken = mTaskInfo.token;
+ mInPip = true;
+ try {
+ mLeash = mToken.getLeash();
+ } catch (RemoteException e) {
+ throw new RuntimeException("Unable to get leash", e);
+ }
+ final Rect currentBounds = mTaskInfo.configuration.windowConfiguration.getBounds();
+ mBoundsToRestore.put(mToken.asBinder(), currentBounds);
if (mOneShotAnimationType == ANIM_TYPE_BOUNDS) {
- final Rect currentBounds = mTaskInfo.configuration.windowConfiguration.getBounds();
- animateResizePipInternal(mTaskInfo.token, true /* scheduleFinishPip */,
- currentBounds, destinationBounds, DURATION_DEFAULT_MS);
+ scheduleAnimateResizePip(currentBounds, destinationBounds,
+ TRANSITION_DIRECTION_TO_PIP, DURATION_DEFAULT_MS, null);
} else if (mOneShotAnimationType == ANIM_TYPE_ALPHA) {
- mMainHandler.post(() -> mPipAnimationController
- .getAnimator(mTaskInfo.token, true /* scheduleFinishPip */,
- destinationBounds, 0f, 1f)
+ mUpdateHandler.post(() -> mPipAnimationController
+ .getAnimator(mLeash, destinationBounds, 0f, 1f)
+ .setTransitionDirection(TRANSITION_DIRECTION_TO_PIP)
+ .setCornerRadius(mCornerRadius)
.setPipAnimationCallback(mPipAnimationCallback)
.setDuration(DURATION_DEFAULT_MS)
.start());
@@ -205,12 +253,14 @@ public class PipTaskOrganizer extends ITaskOrganizer.Stub {
@Override
public void taskVanished(IWindowContainer token) {
Objects.requireNonNull(token, "Requires valid IWindowContainer");
- if (token.asBinder() != mTaskInfo.token.asBinder()) {
+ if (token.asBinder() != mToken.asBinder()) {
Log.wtf(TAG, "Unrecognized token: " + token);
return;
}
- animateResizePipInternal(token, false /* scheduleFinishPip */,
- mLastReportedBounds, mDisplayBounds, DURATION_DEFAULT_MS);
+ final Rect boundsToRestore = mBoundsToRestore.remove(mToken.asBinder());
+ scheduleAnimateResizePip(mLastReportedBounds, boundsToRestore,
+ TRANSITION_DIRECTION_TO_FULLSCREEN, DURATION_DEFAULT_MS, null);
+ mInPip = false;
}
@Override
@@ -227,7 +277,7 @@ public class PipTaskOrganizer extends ITaskOrganizer.Stub {
final Rect destinationBounds = mPipBoundsHandler.getDestinationBounds(
getAspectRatioOrDefault(newParams), null /* bounds */);
Objects.requireNonNull(destinationBounds, "Missing destination bounds");
- animateResizePip(destinationBounds, DURATION_DEFAULT_MS);
+ scheduleAnimateResizePip(destinationBounds, DURATION_DEFAULT_MS, null);
}
/**
@@ -243,102 +293,160 @@ public class PipTaskOrganizer extends ITaskOrganizer.Stub {
}
/**
- * Directly perform manipulation/resize on the leash. This will not perform any
- * {@link WindowContainerTransaction} until {@link #finishResize} is called.
+ * Animates resizing of the pinned stack given the duration.
*/
- public void resizePip(Rect destinationBounds) {
- Objects.requireNonNull(mTaskInfo, "Requires valid IWindowContainer");
- resizePipInternal(mTaskInfo.token, destinationBounds);
+ public void scheduleAnimateResizePip(Rect toBounds, int duration,
+ Consumer<Rect> updateBoundsCallback) {
+ scheduleAnimateResizePip(mLastReportedBounds, toBounds,
+ TRANSITION_DIRECTION_NONE, duration, updateBoundsCallback);
}
- private void resizePipInternal(IWindowContainer wc,
- Rect destinationBounds) {
- Objects.requireNonNull(mTaskInfo, "Requires valid IWindowContainer");
- try {
- // Could happen when dismissPip
- if (wc == null || wc.getLeash() == null) {
- Log.w(TAG, "Abort animation, invalid leash");
- return;
- }
- final SurfaceControl leash = wc.getLeash();
- new SurfaceControl.Transaction()
- .setPosition(leash, destinationBounds.left, destinationBounds.top)
- .setWindowCrop(leash, destinationBounds.width(), destinationBounds.height())
- .apply();
- } catch (RemoteException e) {
- Log.w(TAG, "Abort animation, invalid window container", e);
- } catch (Exception e) {
- Log.e(TAG, "Should not reach here, terrible thing happened", e);
+ private void scheduleAnimateResizePip(Rect currentBounds, Rect destinationBounds,
+ @PipAnimationController.TransitionDirection int direction, int durationMs,
+ Consumer<Rect> updateBoundsCallback) {
+ Objects.requireNonNull(mToken, "Requires valid IWindowContainer");
+ if (!mInPip) {
+ // Ignore animation when we are no longer in PIP
+ return;
}
+ SomeArgs args = SomeArgs.obtain();
+ args.arg1 = updateBoundsCallback;
+ args.arg2 = currentBounds;
+ args.arg3 = destinationBounds;
+ args.argi1 = direction;
+ args.argi2 = durationMs;
+ mUpdateHandler.sendMessage(mUpdateHandler.obtainMessage(MSG_RESIZE_ANIMATE, args));
+ }
+
+ /**
+ * Directly perform manipulation/resize on the leash. This will not perform any
+ * {@link WindowContainerTransaction} until {@link #scheduleFinishResizePip} is called.
+ */
+ public void scheduleResizePip(Rect toBounds, Consumer<Rect> updateBoundsCallback) {
+ Objects.requireNonNull(mToken, "Requires valid IWindowContainer");
+ SomeArgs args = SomeArgs.obtain();
+ args.arg1 = updateBoundsCallback;
+ args.arg2 = toBounds;
+ mUpdateHandler.sendMessage(mUpdateHandler.obtainMessage(MSG_RESIZE_IMMEDIATE, args));
}
/**
* Finish a intermediate resize operation. This is expected to be called after
- * {@link #resizePip}.
+ * {@link #scheduleResizePip}.
*/
- public void finishResize(Rect destinationBounds) {
- try {
- final IWindowContainer wc = mTaskInfo.token;
- SurfaceControl.Transaction tx = new SurfaceControl.Transaction()
- .setPosition(wc.getLeash(), destinationBounds.left,
- destinationBounds.top)
- .setWindowCrop(wc.getLeash(), destinationBounds.width(),
- destinationBounds.height());
- finishResizeInternal(destinationBounds, wc, tx, false);
- } catch (RemoteException e) {
- Log.e(TAG, "Failed to obtain leash");
+ public void scheduleFinishResizePip(Rect destinationBounds) {
+ Objects.requireNonNull(mToken, "Requires valid IWindowContainer");
+ SurfaceControl.Transaction tx = new SurfaceControl.Transaction()
+ .setPosition(mLeash, destinationBounds.left, destinationBounds.top)
+ .setWindowCrop(mLeash, destinationBounds.width(), destinationBounds.height())
+ .setCornerRadius(mLeash, mInPip ? mCornerRadius : 0);
+ scheduleFinishResizePip(tx, destinationBounds, TRANSITION_DIRECTION_NONE, null);
+ }
+
+ private void scheduleFinishResizePip(SurfaceControl.Transaction tx,
+ Rect destinationBounds, @PipAnimationController.TransitionDirection int direction,
+ Consumer<Rect> updateBoundsCallback) {
+ Objects.requireNonNull(mToken, "Requires valid IWindowContainer");
+ SomeArgs args = SomeArgs.obtain();
+ args.arg1 = updateBoundsCallback;
+ args.arg2 = tx;
+ args.arg3 = destinationBounds;
+ args.argi1 = direction;
+ mUpdateHandler.sendMessage(mUpdateHandler.obtainMessage(MSG_FINISH_RESIZE, args));
+ }
+
+ /**
+ * Offset the PiP window by a given offset on Y-axis, triggered also from screen rotation.
+ */
+ public void scheduleOffsetPip(Rect originalBounds, int offset, int duration,
+ Consumer<Rect> updateBoundsCallback) {
+ if (!mInPip) {
+ // Ignore offsets when we are no longer in PIP
+ return;
+ }
+ Objects.requireNonNull(mToken, "Requires valid IWindowContainer");
+ SomeArgs args = SomeArgs.obtain();
+ args.arg1 = updateBoundsCallback;
+ args.arg2 = originalBounds;
+ // offset would be zero if triggered from screen rotation.
+ args.argi1 = offset;
+ args.argi2 = duration;
+ mUpdateHandler.sendMessage(mUpdateHandler.obtainMessage(MSG_OFFSET_ANIMATE, args));
+ }
+
+ private void offsetPip(Rect originalBounds, int xOffset, int yOffset, int durationMs) {
+ if (Looper.myLooper() != mUpdateHandler.getLooper()) {
+ throw new RuntimeException("Callers should call scheduleOffsetPip() instead of this "
+ + "directly");
+ }
+ if (mTaskInfo == null) {
+ Log.w(TAG, "mTaskInfo is not set");
+ return;
+ }
+ final Rect destinationBounds = new Rect(originalBounds);
+ destinationBounds.offset(xOffset, yOffset);
+ animateResizePip(originalBounds, destinationBounds, TRANSITION_DIRECTION_SAME, durationMs);
+ }
+
+ private void resizePip(Rect destinationBounds) {
+ if (Looper.myLooper() != mUpdateHandler.getLooper()) {
+ throw new RuntimeException("Callers should call scheduleResizePip() instead of this "
+ + "directly");
+ }
+ Objects.requireNonNull(mToken, "Requires valid IWindowContainer");
+ // Could happen when dismissPip
+ if (mToken == null || mLeash == null) {
+ Log.w(TAG, "Abort animation, invalid leash");
+ return;
}
+ new SurfaceControl.Transaction()
+ .setPosition(mLeash, destinationBounds.left, destinationBounds.top)
+ .setWindowCrop(mLeash, destinationBounds.width(), destinationBounds.height())
+ .setCornerRadius(mLeash, mInPip ? mCornerRadius : 0)
+ .apply();
}
- private void finishResizeInternal(Rect destinationBounds, IWindowContainer wc,
- SurfaceControl.Transaction tx, boolean shouldScheduleFinishPip) {
+ private void finishResize(SurfaceControl.Transaction tx, Rect destinationBounds,
+ @PipAnimationController.TransitionDirection int direction) {
+ if (Looper.myLooper() != mUpdateHandler.getLooper()) {
+ throw new RuntimeException("Callers should call scheduleResizePip() instead of this "
+ + "directly");
+ }
mLastReportedBounds.set(destinationBounds);
try {
final WindowContainerTransaction wct = new WindowContainerTransaction();
- if (shouldScheduleFinishPip) {
- wct.scheduleFinishEnterPip(wc, destinationBounds);
+ if (direction == TRANSITION_DIRECTION_TO_PIP) {
+ wct.scheduleFinishEnterPip(mToken, destinationBounds);
} else {
- wct.setBounds(wc, destinationBounds);
+ wct.setBounds(mToken, destinationBounds);
}
- wct.setBoundsChangeTransaction(mTaskInfo.token, tx);
+ wct.setBoundsChangeTransaction(mToken, tx);
mTaskOrganizerController.applyContainerTransaction(wct, null /* ITaskOrganizer */);
} catch (RemoteException e) {
Log.e(TAG, "Failed to apply container transaction", e);
}
}
- /**
- * Animates resizing of the pinned stack given the duration.
- */
- public void animateResizePip(Rect destinationBounds, int durationMs) {
- Objects.requireNonNull(mTaskInfo, "Requires valid IWindowContainer");
- animateResizePipInternal(mTaskInfo.token, false, mLastReportedBounds,
- destinationBounds, durationMs);
- }
-
- private void animateResizePipInternal(IWindowContainer wc, boolean scheduleFinishPip,
- Rect currentBounds, Rect destinationBounds, int durationMs) {
- try {
- // Could happen when dismissPip
- if (wc == null || wc.getLeash() == null) {
- Log.w(TAG, "Abort animation, invalid leash");
- return;
- }
- final SurfaceControl leash = wc.getLeash();
-
- mMainHandler.post(() -> mPipAnimationController
- .getAnimator(wc, scheduleFinishPip, currentBounds, destinationBounds)
- .setPipAnimationCallback(mPipAnimationCallback)
- .setDuration(durationMs)
- .start());
- } catch (RemoteException e) {
- Log.w(TAG, "Abort animation, invalid window container", e);
- } catch (Exception e) {
- Log.e(TAG, "Should not reach here, terrible thing happened", e);
+ private void animateResizePip(Rect currentBounds, Rect destinationBounds,
+ @PipAnimationController.TransitionDirection int direction, int durationMs) {
+ if (Looper.myLooper() != mUpdateHandler.getLooper()) {
+ throw new RuntimeException("Callers should call scheduleAnimateResizePip() instead of "
+ + "this directly");
}
+ // Could happen when dismissPip
+ if (mToken == null || mLeash == null) {
+ Log.w(TAG, "Abort animation, invalid leash");
+ return;
+ }
+ mUpdateHandler.post(() -> mPipAnimationController
+ .getAnimator(mLeash, currentBounds, destinationBounds)
+ .setTransitionDirection(direction)
+ .setCornerRadius(mCornerRadius)
+ .setPipAnimationCallback(mPipAnimationCallback)
+ .setDuration(durationMs)
+ .start());
}
-
private float getAspectRatioOrDefault(@Nullable PictureInPictureParams params) {
return params == null
? mPipBoundsHandler.getDefaultAspectRatio()
diff --git a/packages/SystemUI/src/com/android/systemui/pip/phone/PipManager.java b/packages/SystemUI/src/com/android/systemui/pip/phone/PipManager.java
index 6b3b7481b9c9..eed81bfc07f9 100644
--- a/packages/SystemUI/src/com/android/systemui/pip/phone/PipManager.java
+++ b/packages/SystemUI/src/com/android/systemui/pip/phone/PipManager.java
@@ -41,6 +41,7 @@ import com.android.systemui.UiOffloadThread;
import com.android.systemui.broadcast.BroadcastDispatcher;
import com.android.systemui.pip.BasePipManager;
import com.android.systemui.pip.PipBoundsHandler;
+import com.android.systemui.pip.PipSnapAlgorithm;
import com.android.systemui.pip.PipTaskOrganizer;
import com.android.systemui.shared.recents.IPinnedStackAnimationListener;
import com.android.systemui.shared.system.ActivityManagerWrapper;
@@ -168,7 +169,7 @@ public class PipManager implements BasePipManager, PipTaskOrganizer.PipTransitio
// bounds. We want to restore to the unexpanded bounds when re-entering pip,
// so we save the bounds before expansion (normal) instead of the current
// bounds.
- mReentryBounds.set(mTouchHandler.getMinBounds());
+ mReentryBounds.set(mTouchHandler.getNormalBounds());
// Apply the snap fraction of the current bounds to the normal bounds.
float snapFraction = mPipBoundsHandler.getSnapFraction(bounds);
mPipBoundsHandler.applySnapFraction(mReentryBounds, snapFraction);
@@ -184,10 +185,7 @@ public class PipManager implements BasePipManager, PipTaskOrganizer.PipTransitio
@Override
public void onDisplayInfoChanged(DisplayInfo displayInfo) {
- mHandler.post(() -> {
- mPipBoundsHandler.onDisplayInfoChanged(displayInfo);
- mPipTaskOrganizer.onDisplayInfoChanged(displayInfo);
- });
+ mHandler.post(() -> mPipBoundsHandler.onDisplayInfoChanged(displayInfo));
}
@Override
@@ -205,7 +203,9 @@ public class PipManager implements BasePipManager, PipTaskOrganizer.PipTransitio
public PipManager(Context context, BroadcastDispatcher broadcastDispatcher,
DisplayController displayController,
FloatingContentCoordinator floatingContentCoordinator,
- DeviceConfigProxy deviceConfig) {
+ DeviceConfigProxy deviceConfig,
+ PipBoundsHandler pipBoundsHandler,
+ PipSnapAlgorithm pipSnapAlgorithm) {
mContext = context;
mActivityManager = ActivityManager.getService();
@@ -218,7 +218,7 @@ public class PipManager implements BasePipManager, PipTaskOrganizer.PipTransitio
ActivityManagerWrapper.getInstance().registerTaskStackListener(mTaskStackListener);
final IActivityTaskManager activityTaskManager = ActivityTaskManager.getService();
- mPipBoundsHandler = new PipBoundsHandler(context);
+ mPipBoundsHandler = pipBoundsHandler;
mPipTaskOrganizer = new PipTaskOrganizer(mContext, mPipBoundsHandler);
mPipTaskOrganizer.registerPipTransitionCallback(this);
mInputConsumerController = InputConsumerController.getPipInputConsumer();
@@ -227,7 +227,7 @@ public class PipManager implements BasePipManager, PipTaskOrganizer.PipTransitio
mInputConsumerController);
mTouchHandler = new PipTouchHandler(context, mActivityManager, activityTaskManager,
mMenuController, mInputConsumerController, mPipBoundsHandler, mPipTaskOrganizer,
- floatingContentCoordinator, deviceConfig);
+ floatingContentCoordinator, deviceConfig, pipSnapAlgorithm);
mAppOpsListener = new PipAppOpsListener(context, mActivityManager,
mTouchHandler.getMotionHelper());
displayController.addDisplayChangingController(mRotationController);
@@ -349,7 +349,6 @@ public class PipManager implements BasePipManager, PipTaskOrganizer.PipTransitio
mTouchHandler.onMovementBoundsChanged(mTmpInsetBounds, mTmpNormalBounds,
animatingBounds, fromImeAdjustment, fromShelfAdjustment,
mTmpDisplayInfo.rotation);
- mPipTaskOrganizer.onDisplayInfoChanged(mTmpDisplayInfo);
}
public void dump(PrintWriter pw) {
diff --git a/packages/SystemUI/src/com/android/systemui/pip/phone/PipMenuActivity.java b/packages/SystemUI/src/com/android/systemui/pip/phone/PipMenuActivity.java
index 81e8a0b91211..fc04f795c056 100644
--- a/packages/SystemUI/src/com/android/systemui/pip/phone/PipMenuActivity.java
+++ b/packages/SystemUI/src/com/android/systemui/pip/phone/PipMenuActivity.java
@@ -60,6 +60,7 @@ import android.os.RemoteException;
import android.os.UserHandle;
import android.util.Log;
import android.util.Pair;
+import android.view.KeyEvent;
import android.view.LayoutInflater;
import android.view.MotionEvent;
import android.view.View;
@@ -226,6 +227,15 @@ public class PipMenuActivity extends Activity {
}
@Override
+ public boolean onKeyUp(int keyCode, KeyEvent event) {
+ if (keyCode == KeyEvent.KEYCODE_ESCAPE) {
+ hideMenu();
+ return true;
+ }
+ return super.onKeyUp(keyCode, event);
+ }
+
+ @Override
protected void onNewIntent(Intent intent) {
super.onNewIntent(intent);
updateFromIntent(intent);
diff --git a/packages/SystemUI/src/com/android/systemui/pip/phone/PipMotionHelper.java b/packages/SystemUI/src/com/android/systemui/pip/phone/PipMotionHelper.java
index dece8503cc3a..33760be3f469 100644
--- a/packages/SystemUI/src/com/android/systemui/pip/phone/PipMotionHelper.java
+++ b/packages/SystemUI/src/com/android/systemui/pip/phone/PipMotionHelper.java
@@ -28,16 +28,11 @@ import android.graphics.Point;
import android.graphics.PointF;
import android.graphics.Rect;
import android.os.Debug;
-import android.os.Handler;
-import android.os.Message;
import android.os.RemoteException;
import android.util.Log;
-import android.view.Choreographer;
import androidx.dynamicanimation.animation.SpringForce;
-import com.android.internal.graphics.SfVsyncFrameCallbackProvider;
-import com.android.internal.os.SomeArgs;
import com.android.systemui.pip.PipSnapAlgorithm;
import com.android.systemui.pip.PipTaskOrganizer;
import com.android.systemui.shared.system.WindowManagerWrapper;
@@ -47,11 +42,12 @@ import com.android.systemui.util.animation.FloatProperties;
import com.android.systemui.util.animation.PhysicsAnimator;
import java.io.PrintWriter;
+import java.util.function.Consumer;
/**
* A helper to animate and manipulate the PiP.
*/
-public class PipMotionHelper implements Handler.Callback, PipAppOpsListener.Callback,
+public class PipMotionHelper implements PipAppOpsListener.Callback,
FloatingContentCoordinator.FloatingContent {
private static final String TAG = "PipMotionHelper";
@@ -68,14 +64,9 @@ public class PipMotionHelper implements Handler.Callback, PipAppOpsListener.Call
// The fraction of the stack height that the user has to drag offscreen to dismiss the PiP
private static final float DISMISS_OFFSCREEN_FRACTION = 0.3f;
- private static final int MSG_RESIZE_IMMEDIATE = 1;
- private static final int MSG_RESIZE_ANIMATE = 2;
- private static final int MSG_OFFSET_ANIMATE = 3;
-
private final Context mContext;
private final IActivityTaskManager mActivityTaskManager;
private final PipTaskOrganizer mPipTaskOrganizer;
- private final Handler mHandler;
private PipMenuActivityController mMenuController;
private PipSnapAlgorithm mSnapAlgorithm;
@@ -92,9 +83,6 @@ public class PipMotionHelper implements Handler.Callback, PipAppOpsListener.Call
/** The region that all of PIP must stay within. */
private Rect mFloatingAllowedArea = new Rect();
- private final SfVsyncFrameCallbackProvider mSfVsyncFrameProvider =
- new SfVsyncFrameCallbackProvider();
-
/**
* Bounds that are animated using the physics animator.
*/
@@ -112,16 +100,11 @@ public class PipMotionHelper implements Handler.Callback, PipAppOpsListener.Call
private PhysicsAnimator<Rect> mAnimatedBoundsPhysicsAnimator = PhysicsAnimator.getInstance(
mAnimatedBounds);
- /** Callback that re-sizes PIP to the animated bounds. */
- private final Choreographer.FrameCallback mResizePipVsyncCallback =
- l -> resizePipUnchecked(mAnimatedBounds);
-
/**
- * Update listener that posts a vsync frame callback to resize PIP to {@link #mAnimatedBounds}.
+ * Update listener that resizes the PIP to {@link #mAnimatedBounds}.
*/
- private final PhysicsAnimator.UpdateListener<Rect> mResizePipVsyncUpdateListener =
- (target, values) ->
- mSfVsyncFrameProvider.postFrameCallback(mResizePipVsyncCallback);
+ private final PhysicsAnimator.UpdateListener<Rect> mResizePipUpdateListener =
+ (target, values) -> resizePipUnchecked(mAnimatedBounds);
/** FlingConfig instances provided to PhysicsAnimator for fling gestures. */
private PhysicsAnimator.FlingConfig mFlingConfigX;
@@ -137,12 +120,13 @@ public class PipMotionHelper implements Handler.Callback, PipAppOpsListener.Call
new PhysicsAnimator.SpringConfig(
SpringForce.STIFFNESS_LOW, SpringForce.DAMPING_RATIO_LOW_BOUNCY);
+ private final Consumer<Rect> mUpdateBoundsCallback = (toBounds) -> mBounds.set(toBounds);
+
public PipMotionHelper(Context context, IActivityTaskManager activityTaskManager,
PipTaskOrganizer pipTaskOrganizer, PipMenuActivityController menuController,
PipSnapAlgorithm snapAlgorithm, FlingAnimationUtils flingAnimationUtils,
FloatingContentCoordinator floatingContentCoordinator) {
mContext = context;
- mHandler = new Handler(ForegroundThread.get().getLooper(), this);
mActivityTaskManager = activityTaskManager;
mPipTaskOrganizer = pipTaskOrganizer;
mMenuController = menuController;
@@ -234,7 +218,7 @@ public class PipMotionHelper implements Handler.Callback, PipAppOpsListener.Call
}
cancelAnimations();
mMenuController.hideMenuWithoutResize();
- mHandler.post(() -> {
+ mPipTaskOrganizer.getUpdateHandler().post(() -> {
try {
mActivityTaskManager.dismissPip(!skipAnimation, EXPAND_STACK_TO_FULLSCREEN_DURATION);
} catch (RemoteException e) {
@@ -253,7 +237,7 @@ public class PipMotionHelper implements Handler.Callback, PipAppOpsListener.Call
}
cancelAnimations();
mMenuController.hideMenuWithoutResize();
- mHandler.post(() -> {
+ mPipTaskOrganizer.getUpdateHandler().post(() -> {
try {
mActivityTaskManager.removeStacksInWindowingModes(
new int[]{ WINDOWING_MODE_PINNED });
@@ -328,7 +312,8 @@ public class PipMotionHelper implements Handler.Callback, PipAppOpsListener.Call
* Animates the PiP to the closest snap target.
*/
void animateToClosestSnapTarget() {
- final Rect newBounds = mSnapAlgorithm.findClosestSnapBounds(mMovementBounds, mBounds);
+ final Rect newBounds = new Rect();
+ mSnapAlgorithm.snapRectToClosestEdge(mBounds, mMovementBounds, newBounds);
animateToBounds(newBounds, mSpringConfig);
}
@@ -405,17 +390,13 @@ public class PipMotionHelper implements Handler.Callback, PipAppOpsListener.Call
* Animates the PiP to offset it from the IME or shelf.
*/
void animateToOffset(Rect originalBounds, int offset) {
+ if (DEBUG) {
+ Log.d(TAG, "animateToOffset: originalBounds=" + originalBounds + " offset=" + offset
+ + " callers=\n" + Debug.getCallers(5, " "));
+ }
cancelAnimations();
- adjustAndAnimatePipOffset(originalBounds, offset, SHIFT_DURATION);
- }
-
- private void adjustAndAnimatePipOffset(Rect originalBounds, int offset, int duration) {
- SomeArgs args = SomeArgs.obtain();
- args.arg1 = originalBounds;
- // offset would be zero if triggered from screen rotation.
- args.argi1 = offset;
- args.argi2 = duration;
- mHandler.sendMessage(mHandler.obtainMessage(MSG_OFFSET_ANIMATE, args));
+ mPipTaskOrganizer.scheduleOffsetPip(originalBounds, offset, SHIFT_DURATION,
+ mUpdateBoundsCallback);
}
/**
@@ -436,8 +417,7 @@ public class PipMotionHelper implements Handler.Callback, PipAppOpsListener.Call
/**
* Starts the physics animator which will update the animated PIP bounds using physics
- * animations, as well as the TimeAnimator which will apply those bounds to PIP at intervals
- * synchronized with the SurfaceFlinger vsync frame provider.
+ * animations, as well as the TimeAnimator which will apply those bounds to PIP.
*
* This will also add end actions to the bounds animator that cancel the TimeAnimator and update
* the 'real' bounds to equal the final animated bounds.
@@ -447,7 +427,7 @@ public class PipMotionHelper implements Handler.Callback, PipAppOpsListener.Call
mAnimatedBoundsPhysicsAnimator
.withEndActions(() -> mPipTaskOrganizer.onMotionMovementEnd(mAnimatedBounds))
- .addUpdateListener(mResizePipVsyncUpdateListener)
+ .addUpdateListener(mResizePipUpdateListener)
.start();
}
@@ -470,9 +450,7 @@ public class PipMotionHelper implements Handler.Callback, PipAppOpsListener.Call
+ " callers=\n" + Debug.getCallers(5, " "));
}
if (!toBounds.equals(mBounds)) {
- SomeArgs args = SomeArgs.obtain();
- args.arg1 = toBounds;
- mHandler.sendMessage(mHandler.obtainMessage(MSG_RESIZE_IMMEDIATE, args));
+ mPipTaskOrganizer.scheduleResizePip(toBounds, mUpdateBoundsCallback);
}
}
@@ -485,10 +463,7 @@ public class PipMotionHelper implements Handler.Callback, PipAppOpsListener.Call
+ " duration=" + duration + " callers=\n" + Debug.getCallers(5, " "));
}
if (!toBounds.equals(mBounds)) {
- SomeArgs args = SomeArgs.obtain();
- args.arg1 = toBounds;
- args.argi1 = duration;
- mHandler.sendMessage(mHandler.obtainMessage(MSG_RESIZE_ANIMATE, args));
+ mPipTaskOrganizer.scheduleAnimateResizePip(toBounds, duration, mUpdateBoundsCallback);
setAnimatingToBounds(toBounds);
}
}
@@ -537,70 +512,6 @@ public class PipMotionHelper implements Handler.Callback, PipAppOpsListener.Call
return dismissArea.contains(endpoint.x, endpoint.y);
}
- /**
- * Handles messages to be processed on the background thread.
- */
- public boolean handleMessage(Message msg) {
- switch (msg.what) {
- case MSG_RESIZE_IMMEDIATE: {
- SomeArgs args = (SomeArgs) msg.obj;
- Rect toBounds = (Rect) args.arg1;
- mPipTaskOrganizer.resizePip(toBounds);
- mBounds.set(toBounds);
- return true;
- }
-
- case MSG_RESIZE_ANIMATE: {
- SomeArgs args = (SomeArgs) msg.obj;
- Rect toBounds = (Rect) args.arg1;
- int duration = args.argi1;
- try {
- StackInfo stackInfo = mActivityTaskManager.getStackInfo(
- WINDOWING_MODE_PINNED, ACTIVITY_TYPE_UNDEFINED);
- if (stackInfo == null) {
- // In the case where we've already re-expanded or dismissed the PiP, then
- // just skip the resize
- return true;
- }
-
- mPipTaskOrganizer.animateResizePip(toBounds, duration);
- mBounds.set(toBounds);
- } catch (RemoteException e) {
- Log.e(TAG, "Could not animate resize pinned stack to bounds: " + toBounds, e);
- }
- return true;
- }
-
- case MSG_OFFSET_ANIMATE: {
- SomeArgs args = (SomeArgs) msg.obj;
- Rect originalBounds = (Rect) args.arg1;
- final int offset = args.argi1;
- final int duration = args.argi2;
- try {
- StackInfo stackInfo = mActivityTaskManager.getStackInfo(
- WINDOWING_MODE_PINNED, ACTIVITY_TYPE_UNDEFINED);
- if (stackInfo == null) {
- // In the case where we've already re-expanded or dismissed the PiP, then
- // just skip the resize
- return true;
- }
-
- mPipTaskOrganizer.offsetPinnedStack(originalBounds,
- 0 /* xOffset */, offset, duration);
- Rect toBounds = new Rect(originalBounds);
- toBounds.offset(0, offset);
- mBounds.set(toBounds);
- } catch (RemoteException e) {
- Log.e(TAG, "Could not animate offset pinned stack with offset: " + offset, e);
- }
- return true;
- }
-
- default:
- return false;
- }
- }
-
public void dump(PrintWriter pw, String prefix) {
final String innerPrefix = prefix + " ";
pw.println(prefix + TAG);
diff --git a/packages/SystemUI/src/com/android/systemui/pip/phone/PipResizeGestureHandler.java b/packages/SystemUI/src/com/android/systemui/pip/phone/PipResizeGestureHandler.java
index 5926b8922173..8fff419af5a1 100644
--- a/packages/SystemUI/src/com/android/systemui/pip/phone/PipResizeGestureHandler.java
+++ b/packages/SystemUI/src/com/android/systemui/pip/phone/PipResizeGestureHandler.java
@@ -65,7 +65,6 @@ public class PipResizeGestureHandler {
private final PointF mDownPoint = new PointF();
private final Point mMaxSize = new Point();
private final Point mMinSize = new Point();
- private final Rect mLastResizeBounds = new Rect();
private final Rect mTmpBounds = new Rect();
private final int mDelta;
@@ -194,7 +193,11 @@ public class PipResizeGestureHandler {
}
} else if (mAllowGesture) {
-
+ final Rect currentPipBounds = mMotionHelper.getBounds();
+ Rect newSize = TaskResizingAlgorithm.resizeDrag(ev.getX(), ev.getY(), mDownPoint.x,
+ mDownPoint.y, currentPipBounds, mCtrlType, mMinSize.x, mMinSize.y, mMaxSize,
+ true, true);
+ mPipBoundsHandler.transformBoundsToAspectRatio(newSize);
switch (action) {
case MotionEvent.ACTION_POINTER_DOWN:
// We do not support multi touch for resizing via drag
@@ -203,18 +206,12 @@ public class PipResizeGestureHandler {
case MotionEvent.ACTION_MOVE:
// Capture inputs
mInputMonitor.pilferPointers();
- final Rect currentPipBounds = mMotionHelper.getBounds();
- mLastResizeBounds.set(TaskResizingAlgorithm.resizeDrag(ev.getX(), ev.getY(),
- mDownPoint.x, mDownPoint.y, currentPipBounds, mCtrlType, mMinSize.x,
- mMinSize.y, mMaxSize, true, true));
- mPipBoundsHandler.transformBoundsToAspectRatio(mLastResizeBounds);
- mPipTaskOrganizer.resizePip(mLastResizeBounds);
-
+ //TODO: Actually do resize here.
break;
case MotionEvent.ACTION_UP:
case MotionEvent.ACTION_CANCEL:
- mPipTaskOrganizer.finishResize(mLastResizeBounds);
- mLastResizeBounds.setEmpty();
+ //TODO: Finish resize operation here.
+ mMotionHelper.synchronizePinnedStackBounds();
mCtrlType = CTRL_NONE;
mAllowGesture = false;
break;
@@ -226,7 +223,7 @@ public class PipResizeGestureHandler {
mMaxSize.set(maxX, maxY);
}
- void updateMinSize(int minX, int minY) {
+ void updateMiniSize(int minX, int minY) {
mMinSize.set(minX, minY);
}
diff --git a/packages/SystemUI/src/com/android/systemui/pip/phone/PipTouchHandler.java b/packages/SystemUI/src/com/android/systemui/pip/phone/PipTouchHandler.java
index bd224800e858..90db91a7a29e 100644
--- a/packages/SystemUI/src/com/android/systemui/pip/phone/PipTouchHandler.java
+++ b/packages/SystemUI/src/com/android/systemui/pip/phone/PipTouchHandler.java
@@ -41,7 +41,6 @@ import android.view.accessibility.AccessibilityManager;
import android.view.accessibility.AccessibilityNodeInfo;
import android.view.accessibility.AccessibilityWindowInfo;
-import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.os.logging.MetricsLoggerWrapper;
import com.android.systemui.R;
import com.android.systemui.pip.PipBoundsHandler;
@@ -74,7 +73,7 @@ public class PipTouchHandler {
private final Context mContext;
private final IActivityManager mActivityManager;
private final PipBoundsHandler mPipBoundsHandler;
- private PipResizeGestureHandler mPipResizeGestureHandler;
+ private final PipResizeGestureHandler mPipResizeGestureHandler;
private IPinnedStackController mPinnedStackController;
private final PipMenuActivityController mMenuController;
@@ -85,22 +84,14 @@ public class PipTouchHandler {
// The current movement bounds
private Rect mMovementBounds = new Rect();
- // The current resized bounds, changed by user resize.
- // Note that this is not necessarily the same as PipMotionHelper#getBounds, since it's possible
- // that PIP is currently is in a expanded state (max size) but we still need mResizeBounds to
- // know what size to restore to once expand animation times out.
- @VisibleForTesting Rect mResizedBounds = new Rect();
// The reference inset bounds, used to determine the dismiss fraction
private Rect mInsetBounds = new Rect();
-
- // The reference bounds used to calculate the minimum/maximum target bounds
- // The bound in which PIP enters is the starting/minimum bound, while the expanded/auto-resized
- // bound is the maximum bound.
- private Rect mMinBounds = new Rect();
- @VisibleForTesting Rect mMinMovementBounds = new Rect();
- private Rect mMaxBounds = new Rect();
- @VisibleForTesting Rect mMaxMovementBounds = new Rect();
+ // The reference bounds used to calculate the normal/expanded target bounds
+ private Rect mNormalBounds = new Rect();
+ private Rect mNormalMovementBounds = new Rect();
+ private Rect mExpandedBounds = new Rect();
+ private Rect mExpandedMovementBounds = new Rect();
private int mExpandedShortestEdgeSize;
// Used to workaround an issue where the WM rotation happens before we are notified, allowing
@@ -135,7 +126,7 @@ public class PipTouchHandler {
private final PipTouchState mTouchState;
private final FlingAnimationUtils mFlingAnimationUtils;
private final FloatingContentCoordinator mFloatingContentCoordinator;
- private PipMotionHelper mMotionHelper;
+ private final PipMotionHelper mMotionHelper;
private PipTouchGesture mGesture;
// Temp vars
@@ -175,7 +166,8 @@ public class PipTouchHandler {
PipBoundsHandler pipBoundsHandler,
PipTaskOrganizer pipTaskOrganizer,
FloatingContentCoordinator floatingContentCoordinator,
- DeviceConfigProxy deviceConfig) {
+ DeviceConfigProxy deviceConfig,
+ PipSnapAlgorithm pipSnapAlgorithm) {
// Initialize the Pip input consumer
mContext = context;
mActivityManager = activityManager;
@@ -183,7 +175,7 @@ public class PipTouchHandler {
mMenuController = menuController;
mMenuController.addListener(new PipMenuListener());
mDismissViewController = new PipDismissViewController(context);
- mSnapAlgorithm = new PipSnapAlgorithm(mContext);
+ mSnapAlgorithm = pipSnapAlgorithm;
mFlingAnimationUtils = new FlingAnimationUtils(context.getResources().getDisplayMetrics(),
2.5f);
mGesture = new DefaultPipTouchGesture();
@@ -244,16 +236,14 @@ public class PipTouchHandler {
mFloatingContentCoordinator.onContentRemoved(mMotionHelper);
}
- mResizedBounds.setEmpty();
mPipResizeGestureHandler.onActivityUnpinned();
}
public void onPinnedStackAnimationEnded() {
// Always synchronize the motion helper bounds once PiP animations finish
mMotionHelper.synchronizePinnedStackBounds();
-
- updateMovementBounds();
- mResizedBounds.set(mMinBounds);
+ mPipResizeGestureHandler.updateMiniSize(mMotionHelper.getBounds().width(),
+ mMotionHelper.getBounds().height());
if (mShowPipMenuOnAnimationEnd) {
mMenuController.showMenu(MENU_STATE_CLOSE, mMotionHelper.getBounds(),
@@ -277,10 +267,7 @@ public class PipTouchHandler {
mShelfHeight = shelfHeight;
}
- /**
- * Update all the cached bounds (movement, min, max, etc.)
- */
- public void onMovementBoundsChanged(Rect insetBounds, Rect minBounds, Rect curBounds,
+ public void onMovementBoundsChanged(Rect insetBounds, Rect normalBounds, Rect curBounds,
boolean fromImeAdjustment, boolean fromShelfAdjustment, int displayRotation) {
final int bottomOffset = mIsImeShowing ? mImeHeight : 0;
final boolean fromDisplayRotationChanged = (mDisplayRotation != displayRotation);
@@ -289,25 +276,23 @@ public class PipTouchHandler {
}
// Re-calculate the expanded bounds
- mMinBounds.set(minBounds);
- Rect minMovementBounds = new Rect();
- mSnapAlgorithm.getMovementBounds(mMinBounds, insetBounds, minMovementBounds,
+ mNormalBounds = normalBounds;
+ Rect normalMovementBounds = new Rect();
+ mSnapAlgorithm.getMovementBounds(mNormalBounds, insetBounds, normalMovementBounds,
bottomOffset);
// Calculate the expanded size
- float aspectRatio = (float) minBounds.width() / minBounds.height();
+ float aspectRatio = (float) normalBounds.width() / normalBounds.height();
Point displaySize = new Point();
mContext.getDisplay().getRealSize(displaySize);
- Size maxSize = mSnapAlgorithm.getSizeForAspectRatio(aspectRatio,
+ Size expandedSize = mSnapAlgorithm.getSizeForAspectRatio(aspectRatio,
mExpandedShortestEdgeSize, displaySize.x, displaySize.y);
- mMaxBounds.set(0, 0, maxSize.getWidth(), maxSize.getHeight());
- Rect maxMovementBounds = new Rect();
- mSnapAlgorithm.getMovementBounds(mMaxBounds, insetBounds, maxMovementBounds,
+ mExpandedBounds.set(0, 0, expandedSize.getWidth(), expandedSize.getHeight());
+ mPipResizeGestureHandler.updateMaxSize(expandedSize.getWidth(), expandedSize.getHeight());
+ Rect expandedMovementBounds = new Rect();
+ mSnapAlgorithm.getMovementBounds(mExpandedBounds, insetBounds, expandedMovementBounds,
bottomOffset);
- mPipResizeGestureHandler.updateMinSize(minBounds.width(), minBounds.height());
- mPipResizeGestureHandler.updateMaxSize(mMaxBounds.width(), mMaxBounds.height());
-
// The extra offset does not really affect the movement bounds, but are applied based on the
// current state (ime showing, or shelf offset) when we need to actually shift
int extraOffset = Math.max(
@@ -324,8 +309,8 @@ public class PipTouchHandler {
final float offsetBufferPx = BOTTOM_OFFSET_BUFFER_DP
* mContext.getResources().getDisplayMetrics().density;
final Rect toMovementBounds = mMenuState == MENU_STATE_FULL && willResizeMenu()
- ? new Rect(maxMovementBounds)
- : new Rect(minMovementBounds);
+ ? new Rect(expandedMovementBounds)
+ : new Rect(normalMovementBounds);
final int prevBottom = mMovementBounds.bottom - mMovementBoundsExtraOffsets;
final int toBottom = toMovementBounds.bottom < toMovementBounds.top
? toMovementBounds.bottom
@@ -339,17 +324,17 @@ public class PipTouchHandler {
// Update the movement bounds after doing the calculations based on the old movement bounds
// above
- mMinMovementBounds = minMovementBounds;
- mMaxMovementBounds = maxMovementBounds;
+ mNormalMovementBounds = normalMovementBounds;
+ mExpandedMovementBounds = expandedMovementBounds;
mDisplayRotation = displayRotation;
mInsetBounds.set(insetBounds);
- updateMovementBounds();
+ updateMovementBounds(mMenuState);
mMovementBoundsExtraOffsets = extraOffset;
// If we have a deferred resize, apply it now
if (mDeferResizeToNormalBoundsUntilRotation == displayRotation) {
- mMotionHelper.animateToUnexpandedState(minBounds, mSavedSnapFraction,
- mMinMovementBounds, mMovementBounds, true /* immediate */);
+ mMotionHelper.animateToUnexpandedState(normalBounds, mSavedSnapFraction,
+ mNormalMovementBounds, mMovementBounds, true /* immediate */);
mSavedSnapFraction = -1f;
mDeferResizeToNormalBoundsUntilRotation = -1;
}
@@ -403,7 +388,7 @@ public class PipTouchHandler {
case MotionEvent.ACTION_UP: {
// Update the movement bounds again if the state has changed since the user started
// dragging (ie. when the IME shows)
- updateMovementBounds();
+ updateMovementBounds(mMenuState);
if (mGesture.onUp(mTouchState)) {
break;
@@ -501,13 +486,11 @@ public class PipTouchHandler {
if (menuState == MENU_STATE_FULL && mMenuState != MENU_STATE_FULL) {
// Save the current snap fraction and if we do not drag or move the PiP, then
// we store back to this snap fraction. Otherwise, we'll reset the snap
- // fraction and snap to the closest edge.
- // Also save the current resized bounds so when the menu disappears, we can restore it.
+ // fraction and snap to the closest edge
+ Rect expandedBounds = new Rect(mExpandedBounds);
if (resize) {
- mResizedBounds.set(mMotionHelper.getBounds());
- Rect expandedBounds = new Rect(mMaxBounds);
mSavedSnapFraction = mMotionHelper.animateToExpandedState(expandedBounds,
- mMovementBounds, mMaxMovementBounds);
+ mMovementBounds, mExpandedMovementBounds);
}
} else if (menuState == MENU_STATE_NONE && mMenuState == MENU_STATE_FULL) {
// Try and restore the PiP to the closest edge, using the saved snap fraction
@@ -533,9 +516,9 @@ public class PipTouchHandler {
}
if (mDeferResizeToNormalBoundsUntilRotation == -1) {
- Rect normalBounds = new Rect(mResizedBounds);
+ Rect normalBounds = new Rect(mNormalBounds);
mMotionHelper.animateToUnexpandedState(normalBounds, mSavedSnapFraction,
- mMinMovementBounds, mMovementBounds, false /* immediate */);
+ mNormalMovementBounds, mMovementBounds, false /* immediate */);
mSavedSnapFraction = -1f;
}
} else {
@@ -546,7 +529,7 @@ public class PipTouchHandler {
}
}
mMenuState = menuState;
- updateMovementBounds();
+ updateMovementBounds(menuState);
// If pip menu has dismissed, we should register the A11y ActionReplacingConnection for pip
// as well, or it can't handle a11y focus and pip menu can't perform any action.
onRegistrationChanged(menuState == MENU_STATE_NONE);
@@ -562,26 +545,11 @@ public class PipTouchHandler {
return mMotionHelper;
}
- @VisibleForTesting
- PipResizeGestureHandler getPipResizeGestureHandler() {
- return mPipResizeGestureHandler;
- }
-
- @VisibleForTesting
- void setPipResizeGestureHandler(PipResizeGestureHandler pipResizeGestureHandler) {
- mPipResizeGestureHandler = pipResizeGestureHandler;
- }
-
- @VisibleForTesting
- void setPipMotionHelper(PipMotionHelper pipMotionHelper) {
- mMotionHelper = pipMotionHelper;
- }
-
/**
* @return the unexpanded bounds.
*/
- public Rect getMinBounds() {
- return mMinBounds;
+ public Rect getNormalBounds() {
+ return mNormalBounds;
}
/**
@@ -734,17 +702,17 @@ public class PipTouchHandler {
};
/**
- * Updates the current movement bounds based on the current PIP size.
+ * Updates the current movement bounds based on whether the menu is currently visible and
+ * resized.
*/
- private void updateMovementBounds() {
- Rect movementBounds = new Rect();
- mSnapAlgorithm.getMovementBounds(mMotionHelper.getBounds(), mInsetBounds,
- movementBounds, mIsImeShowing ? mImeHeight : 0);
- mMotionHelper.setCurrentMovementBounds(movementBounds);
-
- boolean isMenuExpanded = mMenuState == MENU_STATE_FULL;
+ private void updateMovementBounds(int menuState) {
+ boolean isMenuExpanded = menuState == MENU_STATE_FULL;
+ mMovementBounds = isMenuExpanded && willResizeMenu()
+ ? mExpandedMovementBounds
+ : mNormalMovementBounds;
mPipBoundsHandler.setMinEdgeSize(
- isMenuExpanded && willResizeMenu() ? mExpandedShortestEdgeSize : 0);
+ isMenuExpanded ? mExpandedShortestEdgeSize : 0);
+ mMotionHelper.setCurrentMovementBounds(mMovementBounds);
}
/**
@@ -762,18 +730,18 @@ public class PipTouchHandler {
if (!mEnableResize) {
return false;
}
- return mMaxBounds.width() != mMinBounds.width()
- || mMaxBounds.height() != mMinBounds.height();
+ return mExpandedBounds.width() != mNormalBounds.width()
+ || mExpandedBounds.height() != mNormalBounds.height();
}
public void dump(PrintWriter pw, String prefix) {
final String innerPrefix = prefix + " ";
pw.println(prefix + TAG);
pw.println(innerPrefix + "mMovementBounds=" + mMovementBounds);
- pw.println(innerPrefix + "mMinBounds=" + mMinBounds);
- pw.println(innerPrefix + "mMinMovementBounds=" + mMinMovementBounds);
- pw.println(innerPrefix + "mMaxBounds=" + mMaxBounds);
- pw.println(innerPrefix + "mMaxMovementBounds=" + mMaxMovementBounds);
+ pw.println(innerPrefix + "mNormalBounds=" + mNormalBounds);
+ pw.println(innerPrefix + "mNormalMovementBounds=" + mNormalMovementBounds);
+ pw.println(innerPrefix + "mExpandedBounds=" + mExpandedBounds);
+ pw.println(innerPrefix + "mExpandedMovementBounds=" + mExpandedMovementBounds);
pw.println(innerPrefix + "mMenuState=" + mMenuState);
pw.println(innerPrefix + "mIsImeShowing=" + mIsImeShowing);
pw.println(innerPrefix + "mImeHeight=" + mImeHeight);
diff --git a/packages/SystemUI/src/com/android/systemui/pip/phone/ForegroundThread.java b/packages/SystemUI/src/com/android/systemui/pip/phone/PipUpdateThread.java
index 9bf46bb488f3..6c5d84645e92 100644
--- a/packages/SystemUI/src/com/android/systemui/pip/phone/ForegroundThread.java
+++ b/packages/SystemUI/src/com/android/systemui/pip/phone/PipUpdateThread.java
@@ -21,33 +21,38 @@ import android.os.HandlerThread;
/**
* Similar to {@link com.android.internal.os.BackgroundThread}, this is a shared singleton
- * foreground thread for each process.
+ * foreground thread for each process for updating PIP.
*/
-public final class ForegroundThread extends HandlerThread {
- private static ForegroundThread sInstance;
+public final class PipUpdateThread extends HandlerThread {
+ private static PipUpdateThread sInstance;
private static Handler sHandler;
- private ForegroundThread() {
- super("recents.fg");
+ private PipUpdateThread() {
+ super("pip");
}
private static void ensureThreadLocked() {
if (sInstance == null) {
- sInstance = new ForegroundThread();
+ sInstance = new PipUpdateThread();
sInstance.start();
sHandler = new Handler(sInstance.getLooper());
}
}
- public static ForegroundThread get() {
- synchronized (ForegroundThread.class) {
+ /**
+ * @return the static update thread instance
+ */
+ public static PipUpdateThread get() {
+ synchronized (PipUpdateThread.class) {
ensureThreadLocked();
return sInstance;
}
}
-
+ /**
+ * @return the static update thread handler instance
+ */
public static Handler getHandler() {
- synchronized (ForegroundThread.class) {
+ synchronized (PipUpdateThread.class) {
ensureThreadLocked();
return sHandler;
}
diff --git a/packages/SystemUI/src/com/android/systemui/pip/tv/PipManager.java b/packages/SystemUI/src/com/android/systemui/pip/tv/PipManager.java
index f28c3f6e71ec..a5e9dbc41924 100644
--- a/packages/SystemUI/src/com/android/systemui/pip/tv/PipManager.java
+++ b/packages/SystemUI/src/com/android/systemui/pip/tv/PipManager.java
@@ -20,6 +20,8 @@ import static android.app.ActivityTaskManager.INVALID_STACK_ID;
import static android.app.WindowConfiguration.ACTIVITY_TYPE_UNDEFINED;
import static android.app.WindowConfiguration.WINDOWING_MODE_PINNED;
+import static com.android.systemui.pip.PipAnimationController.DURATION_DEFAULT_MS;
+
import android.app.ActivityManager.RunningTaskInfo;
import android.app.ActivityManager.StackInfo;
import android.app.ActivityTaskManager;
@@ -50,7 +52,6 @@ import com.android.systemui.R;
import com.android.systemui.UiOffloadThread;
import com.android.systemui.broadcast.BroadcastDispatcher;
import com.android.systemui.pip.BasePipManager;
-import com.android.systemui.pip.PipAnimationController;
import com.android.systemui.pip.PipBoundsHandler;
import com.android.systemui.pip.PipTaskOrganizer;
import com.android.systemui.shared.system.ActivityManagerWrapper;
@@ -228,13 +229,15 @@ public class PipManager implements BasePipManager, PipTaskOrganizer.PipTransitio
}
@Inject
- public PipManager(Context context, BroadcastDispatcher broadcastDispatcher) {
+ public PipManager(Context context, BroadcastDispatcher broadcastDispatcher,
+ PipBoundsHandler pipBoundsHandler) {
if (mInitialized) {
return;
}
+
mInitialized = true;
mContext = context;
- mPipBoundsHandler = new PipBoundsHandler(context);
+ mPipBoundsHandler = pipBoundsHandler;
mPipTaskOrganizer = new PipTaskOrganizer(mContext, mPipBoundsHandler);
mPipTaskOrganizer.registerPipTransitionCallback(this);
mActivityTaskManager = ActivityTaskManager.getService();
@@ -433,8 +436,7 @@ public class PipManager implements BasePipManager, PipTaskOrganizer.PipTransitio
mCurrentPipBounds = mPipBounds;
break;
}
- mPipTaskOrganizer.animateResizePip(mCurrentPipBounds,
- PipAnimationController.DURATION_DEFAULT_MS);
+ mPipTaskOrganizer.scheduleAnimateResizePip(mCurrentPipBounds, DURATION_DEFAULT_MS, null);
}
/**
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSMediaPlayer.java b/packages/SystemUI/src/com/android/systemui/qs/QSMediaPlayer.java
index 011893d65723..837256bf4052 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QSMediaPlayer.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QSMediaPlayer.java
@@ -17,158 +17,53 @@
package com.android.systemui.qs;
import android.app.Notification;
-import android.app.PendingIntent;
-import android.content.ComponentName;
import android.content.Context;
-import android.content.Intent;
-import android.content.pm.PackageManager;
-import android.content.pm.ResolveInfo;
-import android.content.res.ColorStateList;
-import android.graphics.Bitmap;
-import android.graphics.Canvas;
-import android.graphics.Matrix;
-import android.graphics.Paint;
import android.graphics.drawable.Drawable;
-import android.graphics.drawable.GradientDrawable;
import android.graphics.drawable.Icon;
-import android.graphics.drawable.RippleDrawable;
-import android.media.MediaMetadata;
-import android.media.session.MediaController;
import android.media.session.MediaSession;
-import android.media.session.PlaybackState;
-import android.os.Handler;
import android.util.Log;
-import android.view.KeyEvent;
-import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ImageButton;
-import android.widget.ImageView;
import android.widget.LinearLayout;
-import android.widget.TextView;
-
-import androidx.core.graphics.drawable.RoundedBitmapDrawable;
-import androidx.core.graphics.drawable.RoundedBitmapDrawableFactory;
import com.android.settingslib.media.MediaDevice;
-import com.android.settingslib.media.MediaOutputSliceConstants;
-import com.android.settingslib.widget.AdaptiveIcon;
-import com.android.systemui.Dependency;
import com.android.systemui.R;
-import com.android.systemui.plugins.ActivityStarter;
+import com.android.systemui.media.MediaControlPanel;
+import com.android.systemui.statusbar.NotificationMediaManager;
-import java.util.List;
+import java.util.concurrent.Executor;
/**
* Single media player for carousel in QSPanel
*/
-public class QSMediaPlayer {
+public class QSMediaPlayer extends MediaControlPanel {
private static final String TAG = "QSMediaPlayer";
- private Context mContext;
- private LinearLayout mMediaNotifView;
- private View mSeamless;
- private MediaSession.Token mToken;
- private MediaController mController;
- private int mForegroundColor;
- private int mBackgroundColor;
- private ComponentName mRecvComponent;
- private QSPanel mParent;
-
- private MediaController.Callback mSessionCallback = new MediaController.Callback() {
- @Override
- public void onSessionDestroyed() {
- Log.d(TAG, "session destroyed");
- mController.unregisterCallback(mSessionCallback);
-
- // Hide all the old buttons
- final int[] actionIds = {
- R.id.action0,
- R.id.action1,
- R.id.action2,
- R.id.action3,
- R.id.action4
- };
- for (int i = 0; i < actionIds.length; i++) {
- ImageButton thisBtn = mMediaNotifView.findViewById(actionIds[i]);
- if (thisBtn != null) {
- thisBtn.setVisibility(View.GONE);
- }
- }
-
- // Add a restart button
- ImageButton btn = mMediaNotifView.findViewById(actionIds[0]);
- btn.setOnClickListener(v -> {
- Log.d(TAG, "Attempting to restart session");
- // Send a media button event to previously found receiver
- if (mRecvComponent != null) {
- Intent intent = new Intent(Intent.ACTION_MEDIA_BUTTON);
- intent.setComponent(mRecvComponent);
- int keyCode = KeyEvent.KEYCODE_MEDIA_PLAY;
- intent.putExtra(
- Intent.EXTRA_KEY_EVENT,
- new KeyEvent(KeyEvent.ACTION_DOWN, keyCode));
- mContext.sendBroadcast(intent);
- } else {
- Log.d(TAG, "No receiver to restart");
- // If we don't have a receiver, try relaunching the activity instead
- try {
- mController.getSessionActivity().send();
- } catch (PendingIntent.CanceledException e) {
- Log.e(TAG, "Pending intent was canceled");
- e.printStackTrace();
- }
- }
- });
- btn.setImageDrawable(mContext.getResources().getDrawable(R.drawable.lb_ic_play));
- btn.setImageTintList(ColorStateList.valueOf(mForegroundColor));
- btn.setVisibility(View.VISIBLE);
-
- // Add long-click option to remove the player
- ViewGroup mMediaCarousel = (ViewGroup) mMediaNotifView.getParent();
- mMediaNotifView.setOnLongClickListener(v -> {
- // Replace player view with delete/cancel view
- v.setVisibility(View.GONE);
-
- View options = LayoutInflater.from(mContext).inflate(
- R.layout.qs_media_panel_options, null, false);
- ImageButton btnDelete = options.findViewById(R.id.remove);
- btnDelete.setOnClickListener(b -> {
- mMediaCarousel.removeView(options);
- mParent.removeMediaPlayer(QSMediaPlayer.this);
- });
- ImageButton btnCancel = options.findViewById(R.id.cancel);
- btnCancel.setOnClickListener(b -> {
- mMediaCarousel.removeView(options);
- v.setVisibility(View.VISIBLE);
- });
-
- int pos = mMediaCarousel.indexOfChild(v);
- mMediaCarousel.addView(options, pos, v.getLayoutParams());
- return true; // consumed click
- });
- }
+ // Button IDs for QS controls
+ static final int[] QS_ACTION_IDS = {
+ R.id.action0,
+ R.id.action1,
+ R.id.action2,
+ R.id.action3,
+ R.id.action4
};
/**
- *
+ * Initialize quick shade version of player
* @param context
* @param parent
+ * @param manager
+ * @param backgroundExecutor
*/
- public QSMediaPlayer(Context context, ViewGroup parent) {
- mContext = context;
- LayoutInflater inflater = LayoutInflater.from(mContext);
- mMediaNotifView = (LinearLayout) inflater.inflate(R.layout.qs_media_panel, parent, false);
- }
-
- public View getView() {
- return mMediaNotifView;
+ public QSMediaPlayer(Context context, ViewGroup parent, NotificationMediaManager manager,
+ Executor backgroundExecutor) {
+ super(context, parent, manager, R.layout.qs_media_panel, QS_ACTION_IDS, backgroundExecutor);
}
/**
- * Create or update the player view for the given media session
- * @param parent the parent QSPanel
+ * Update media panel view for the given media session
* @param token token for this media session
* @param icon app notification icon
* @param iconColor foreground color (for text, icons)
@@ -177,114 +72,20 @@ public class QSMediaPlayer {
* @param notif reference to original notification
* @param device current playback device
*/
- public void setMediaSession(QSPanel parent, MediaSession.Token token, Icon icon, int iconColor,
+ public void setMediaSession(MediaSession.Token token, Icon icon, int iconColor,
int bgColor, View actionsContainer, Notification notif, MediaDevice device) {
- mParent = parent;
- mToken = token;
- mForegroundColor = iconColor;
- mBackgroundColor = bgColor;
- mController = new MediaController(mContext, token);
-
- // Try to find a receiver for the media button that matches this app
- PackageManager pm = mContext.getPackageManager();
- Intent it = new Intent(Intent.ACTION_MEDIA_BUTTON);
- List<ResolveInfo> info = pm.queryBroadcastReceiversAsUser(it, 0, mContext.getUser());
- if (info != null) {
- for (ResolveInfo inf : info) {
- if (inf.activityInfo.packageName.equals(mController.getPackageName())) {
- mRecvComponent = inf.getComponentInfo().getComponentName();
- }
- }
- }
-
- // reset in case we had previously restarted the stream
- mMediaNotifView.setOnLongClickListener(null);
- mController.registerCallback(mSessionCallback);
- MediaMetadata mMediaMetadata = mController.getMetadata();
- if (mMediaMetadata == null) {
- Log.e(TAG, "Media metadata was null");
- return;
- }
-
- Notification.Builder builder = Notification.Builder.recoverBuilder(mContext, notif);
- // Album art
- addAlbumArt(mMediaMetadata, bgColor);
-
- LinearLayout headerView = mMediaNotifView.findViewById(R.id.header);
-
- // App icon
- ImageView appIcon = headerView.findViewById(R.id.icon);
- Drawable iconDrawable = icon.loadDrawable(mContext);
- iconDrawable.setTint(iconColor);
- appIcon.setImageDrawable(iconDrawable);
-
- // App title
- TextView appName = headerView.findViewById(R.id.app_name);
- String appNameString = builder.loadHeaderAppName();
- appName.setText(appNameString);
- appName.setTextColor(iconColor);
-
- // Action
- mMediaNotifView.setOnClickListener(v -> {
- try {
- notif.contentIntent.send();
- // Also close shade
- mContext.sendBroadcast(new Intent(Intent.ACTION_CLOSE_SYSTEM_DIALOGS));
- } catch (PendingIntent.CanceledException e) {
- Log.e(TAG, "Pending intent was canceled");
- e.printStackTrace();
- }
- });
-
- // Transfer chip
- mSeamless = headerView.findViewById(R.id.media_seamless);
- mSeamless.setVisibility(View.VISIBLE);
- updateChip(device);
- ActivityStarter mActivityStarter = Dependency.get(ActivityStarter.class);
- mSeamless.setOnClickListener(v -> {
- final Intent intent = new Intent()
- .setAction(MediaOutputSliceConstants.ACTION_MEDIA_OUTPUT)
- .putExtra(MediaOutputSliceConstants.EXTRA_PACKAGE_NAME,
- mController.getPackageName())
- .putExtra(MediaOutputSliceConstants.KEY_MEDIA_SESSION_TOKEN, token);
- mActivityStarter.startActivity(intent, false, true /* dismissShade */,
- Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK);
- });
-
- // Artist name
- TextView artistText = headerView.findViewById(R.id.header_artist);
- String artistName = mMediaMetadata.getString(MediaMetadata.METADATA_KEY_ARTIST);
- artistText.setText(artistName);
- artistText.setTextColor(iconColor);
-
- // Song name
- TextView titleText = headerView.findViewById(R.id.header_text);
- String songName = mMediaMetadata.getString(MediaMetadata.METADATA_KEY_TITLE);
- titleText.setText(songName);
- titleText.setTextColor(iconColor);
+ String appName = Notification.Builder.recoverBuilder(getContext(), notif)
+ .loadHeaderAppName();
+ super.setMediaSession(token, icon, iconColor, bgColor, notif.contentIntent,
+ appName, device);
// Media controls
LinearLayout parentActionsLayout = (LinearLayout) actionsContainer;
- final int[] actionIds = {
- R.id.action0,
- R.id.action1,
- R.id.action2,
- R.id.action3,
- R.id.action4
- };
- final int[] notifActionIds = {
- com.android.internal.R.id.action0,
- com.android.internal.R.id.action1,
- com.android.internal.R.id.action2,
- com.android.internal.R.id.action3,
- com.android.internal.R.id.action4
- };
-
int i = 0;
- for (; i < parentActionsLayout.getChildCount() && i < actionIds.length; i++) {
- ImageButton thisBtn = mMediaNotifView.findViewById(actionIds[i]);
- ImageButton thatBtn = parentActionsLayout.findViewById(notifActionIds[i]);
+ for (; i < parentActionsLayout.getChildCount() && i < QS_ACTION_IDS.length; i++) {
+ ImageButton thisBtn = mMediaNotifView.findViewById(QS_ACTION_IDS[i]);
+ ImageButton thatBtn = parentActionsLayout.findViewById(NOTIF_ACTION_IDS[i]);
if (thatBtn == null || thatBtn.getDrawable() == null
|| thatBtn.getVisibility() != View.VISIBLE) {
thisBtn.setVisibility(View.GONE);
@@ -301,116 +102,9 @@ public class QSMediaPlayer {
}
// Hide any unused buttons
- for (; i < actionIds.length; i++) {
- ImageButton thisBtn = mMediaNotifView.findViewById(actionIds[i]);
+ for (; i < QS_ACTION_IDS.length; i++) {
+ ImageButton thisBtn = mMediaNotifView.findViewById(QS_ACTION_IDS[i]);
thisBtn.setVisibility(View.GONE);
}
}
-
- public MediaSession.Token getMediaSessionToken() {
- return mToken;
- }
-
- public String getMediaPlayerPackage() {
- return mController.getPackageName();
- }
-
- /**
- * Check whether the media controlled by this player is currently playing
- * @return whether it is playing, or false if no controller information
- */
- public boolean isPlaying() {
- if (mController == null) {
- return false;
- }
-
- PlaybackState state = mController.getPlaybackState();
- if (state == null) {
- return false;
- }
-
- return (state.getState() == PlaybackState.STATE_PLAYING);
- }
-
- private void addAlbumArt(MediaMetadata metadata, int bgColor) {
- Bitmap albumArt = metadata.getBitmap(MediaMetadata.METADATA_KEY_ALBUM_ART);
- float radius = mContext.getResources().getDimension(R.dimen.qs_media_corner_radius);
- ImageView albumView = mMediaNotifView.findViewById(R.id.album_art);
- if (albumArt != null) {
- Log.d(TAG, "updating album art");
- Bitmap original = albumArt.copy(Bitmap.Config.ARGB_8888, true);
- int albumSize = (int) mContext.getResources().getDimension(R.dimen.qs_media_album_size);
- Bitmap scaled = scaleBitmap(original, albumSize, albumSize);
- RoundedBitmapDrawable roundedDrawable = RoundedBitmapDrawableFactory.create(
- mContext.getResources(), scaled);
- roundedDrawable.setCornerRadius(radius);
- albumView.setImageDrawable(roundedDrawable);
- } else {
- Log.e(TAG, "No album art available");
- albumView.setImageDrawable(null);
- }
-
- mMediaNotifView.setBackgroundTintList(ColorStateList.valueOf(bgColor));
- }
-
- private Bitmap scaleBitmap(Bitmap original, int width, int height) {
- Bitmap cropped = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888);
- Canvas canvas = new Canvas(cropped);
-
- float scale = (float) cropped.getWidth() / (float) original.getWidth();
- float dy = (cropped.getHeight() - original.getHeight() * scale) / 2.0f;
- Matrix transformation = new Matrix();
- transformation.postTranslate(0, dy);
- transformation.preScale(scale, scale);
-
- Paint paint = new Paint();
- paint.setFilterBitmap(true);
- canvas.drawBitmap(original, transformation, paint);
-
- return cropped;
- }
-
- protected void updateChip(MediaDevice device) {
- if (mSeamless == null) {
- return;
- }
- Handler handler = mSeamless.getHandler();
- handler.post(() -> {
- updateChipInternal(device);
- });
- }
-
- private void updateChipInternal(MediaDevice device) {
- ColorStateList fgTintList = ColorStateList.valueOf(mForegroundColor);
-
- // Update the outline color
- LinearLayout viewLayout = (LinearLayout) mSeamless;
- RippleDrawable bkgDrawable = (RippleDrawable) viewLayout.getBackground();
- GradientDrawable rect = (GradientDrawable) bkgDrawable.getDrawable(0);
- rect.setStroke(2, mForegroundColor);
- rect.setColor(mBackgroundColor);
-
- ImageView iconView = mSeamless.findViewById(R.id.media_seamless_image);
- TextView deviceName = mSeamless.findViewById(R.id.media_seamless_text);
- deviceName.setTextColor(fgTintList);
-
- if (device != null) {
- Drawable icon = device.getIcon();
- iconView.setVisibility(View.VISIBLE);
- iconView.setImageTintList(fgTintList);
-
- if (icon instanceof AdaptiveIcon) {
- AdaptiveIcon aIcon = (AdaptiveIcon) icon;
- aIcon.setBackgroundColor(mBackgroundColor);
- iconView.setImageDrawable(aIcon);
- } else {
- iconView.setImageDrawable(icon);
- }
- deviceName.setText(device.getName());
- } else {
- // Reset to default
- iconView.setVisibility(View.GONE);
- deviceName.setText(com.android.internal.R.string.ext_media_seamless_action);
- }
- }
}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSPanel.java b/packages/SystemUI/src/com/android/systemui/qs/QSPanel.java
index d2d90925cbe2..9ab47145f92d 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QSPanel.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QSPanel.java
@@ -50,6 +50,7 @@ import com.android.systemui.Dependency;
import com.android.systemui.Dumpable;
import com.android.systemui.R;
import com.android.systemui.broadcast.BroadcastDispatcher;
+import com.android.systemui.dagger.qualifiers.Background;
import com.android.systemui.dump.DumpManager;
import com.android.systemui.plugins.qs.DetailAdapter;
import com.android.systemui.plugins.qs.QSTile;
@@ -60,6 +61,7 @@ import com.android.systemui.qs.external.CustomTile;
import com.android.systemui.qs.logging.QSLogger;
import com.android.systemui.settings.BrightnessController;
import com.android.systemui.settings.ToggleSliderView;
+import com.android.systemui.statusbar.NotificationMediaManager;
import com.android.systemui.statusbar.policy.BrightnessMirrorController;
import com.android.systemui.statusbar.policy.BrightnessMirrorController.BrightnessMirrorListener;
import com.android.systemui.tuner.TunerService;
@@ -70,6 +72,7 @@ import java.io.PrintWriter;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
+import java.util.concurrent.Executor;
import java.util.stream.Collectors;
import javax.inject.Inject;
@@ -94,6 +97,8 @@ public class QSPanel extends LinearLayout implements Tunable, Callback, Brightne
private final LinearLayout mMediaCarousel;
private final ArrayList<QSMediaPlayer> mMediaPlayers = new ArrayList<>();
+ private final NotificationMediaManager mNotificationMediaManager;
+ private final Executor mBackgroundExecutor;
private LocalMediaManager mLocalMediaManager;
private MediaDevice mDevice;
private boolean mUpdateCarousel = false;
@@ -128,7 +133,7 @@ public class QSPanel extends LinearLayout implements Tunable, Callback, Brightne
if (mDevice == null || !mDevice.equals(currentDevice)) {
mDevice = currentDevice;
for (QSMediaPlayer p : mMediaPlayers) {
- p.updateChip(mDevice);
+ p.updateDevice(mDevice);
}
}
}
@@ -138,7 +143,7 @@ public class QSPanel extends LinearLayout implements Tunable, Callback, Brightne
if (mDevice == null || !mDevice.equals(device)) {
mDevice = device;
for (QSMediaPlayer p : mMediaPlayers) {
- p.updateChip(mDevice);
+ p.updateDevice(mDevice);
}
}
}
@@ -150,12 +155,16 @@ public class QSPanel extends LinearLayout implements Tunable, Callback, Brightne
AttributeSet attrs,
DumpManager dumpManager,
BroadcastDispatcher broadcastDispatcher,
- QSLogger qsLogger
+ QSLogger qsLogger,
+ NotificationMediaManager notificationMediaManager,
+ @Background Executor backgroundExecutor
) {
super(context, attrs);
mContext = context;
mQSLogger = qsLogger;
mDumpManager = dumpManager;
+ mNotificationMediaManager = notificationMediaManager;
+ mBackgroundExecutor = backgroundExecutor;
setOrientation(VERTICAL);
@@ -255,7 +264,8 @@ public class QSPanel extends LinearLayout implements Tunable, Callback, Brightne
if (player == null) {
Log.d(TAG, "creating new player");
- player = new QSMediaPlayer(mContext, this);
+ player = new QSMediaPlayer(mContext, this, mNotificationMediaManager,
+ mBackgroundExecutor);
if (player.isPlaying()) {
mMediaCarousel.addView(player.getView(), 0, lp); // add in front
@@ -268,7 +278,7 @@ public class QSPanel extends LinearLayout implements Tunable, Callback, Brightne
}
Log.d(TAG, "setting player session");
- player.setMediaSession(this, token, icon, iconColor, bgColor, actionsContainer,
+ player.setMediaSession(token, icon, iconColor, bgColor, actionsContainer,
notif.getNotification(), mDevice);
if (mMediaPlayers.size() > 0) {
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QuickQSMediaPlayer.java b/packages/SystemUI/src/com/android/systemui/qs/QuickQSMediaPlayer.java
index 9018a375c365..4512afb3c178 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QuickQSMediaPlayer.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QuickQSMediaPlayer.java
@@ -17,108 +17,47 @@
package com.android.systemui.qs;
import android.app.PendingIntent;
-import android.content.ComponentName;
import android.content.Context;
-import android.content.Intent;
-import android.content.pm.PackageManager;
-import android.content.pm.ResolveInfo;
-import android.content.res.ColorStateList;
import android.graphics.drawable.Drawable;
import android.graphics.drawable.Icon;
-import android.media.MediaMetadata;
import android.media.session.MediaController;
import android.media.session.MediaSession;
-import android.media.session.PlaybackState;
-import android.util.Log;
-import android.view.KeyEvent;
-import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ImageButton;
-import android.widget.ImageView;
import android.widget.LinearLayout;
-import android.widget.TextView;
import com.android.systemui.R;
+import com.android.systemui.media.MediaControlPanel;
+import com.android.systemui.statusbar.NotificationMediaManager;
-import java.util.List;
+import java.util.concurrent.Executor;
/**
* QQS mini media player
*/
-public class QuickQSMediaPlayer {
+public class QuickQSMediaPlayer extends MediaControlPanel {
private static final String TAG = "QQSMediaPlayer";
- private Context mContext;
- private LinearLayout mMediaNotifView;
- private MediaSession.Token mToken;
- private MediaController mController;
- private int mForegroundColor;
- private ComponentName mRecvComponent;
-
- private MediaController.Callback mSessionCallback = new MediaController.Callback() {
- @Override
- public void onSessionDestroyed() {
- Log.d(TAG, "session destroyed");
- mController.unregisterCallback(mSessionCallback);
-
- // Hide all the old buttons
- final int[] actionIds = {R.id.action0, R.id.action1, R.id.action2};
- for (int i = 0; i < actionIds.length; i++) {
- ImageButton thisBtn = mMediaNotifView.findViewById(actionIds[i]);
- if (thisBtn != null) {
- thisBtn.setVisibility(View.GONE);
- }
- }
-
- // Add a restart button
- ImageButton btn = mMediaNotifView.findViewById(actionIds[0]);
- btn.setOnClickListener(v -> {
- Log.d(TAG, "Attempting to restart session");
- // Send a media button event to previously found receiver
- if (mRecvComponent != null) {
- Intent intent = new Intent(Intent.ACTION_MEDIA_BUTTON);
- intent.setComponent(mRecvComponent);
- int keyCode = KeyEvent.KEYCODE_MEDIA_PLAY;
- intent.putExtra(
- Intent.EXTRA_KEY_EVENT,
- new KeyEvent(KeyEvent.ACTION_DOWN, keyCode));
- mContext.sendBroadcast(intent);
- } else {
- Log.d(TAG, "No receiver to restart");
- // If we don't have a receiver, try relaunching the activity instead
- try {
- mController.getSessionActivity().send();
- } catch (PendingIntent.CanceledException e) {
- Log.e(TAG, "Pending intent was canceled");
- e.printStackTrace();
- }
- }
- });
- btn.setImageDrawable(mContext.getResources().getDrawable(R.drawable.lb_ic_play));
- btn.setImageTintList(ColorStateList.valueOf(mForegroundColor));
- btn.setVisibility(View.VISIBLE);
- }
- };
+ // Button IDs for QS controls
+ private static final int[] QQS_ACTION_IDS = {R.id.action0, R.id.action1, R.id.action2};
/**
- *
+ * Initialize mini media player for QQS
* @param context
* @param parent
+ * @param manager
+ * @param backgroundExecutor
*/
- public QuickQSMediaPlayer(Context context, ViewGroup parent) {
- mContext = context;
- LayoutInflater inflater = LayoutInflater.from(mContext);
- mMediaNotifView = (LinearLayout) inflater.inflate(R.layout.qqs_media_panel, parent, false);
- }
-
- public View getView() {
- return mMediaNotifView;
+ public QuickQSMediaPlayer(Context context, ViewGroup parent, NotificationMediaManager manager,
+ Executor backgroundExecutor) {
+ super(context, parent, manager, R.layout.qqs_media_panel, QQS_ACTION_IDS,
+ backgroundExecutor);
}
/**
- *
+ * Update media panel view for the given media session
* @param token token for this media session
* @param icon app notification icon
* @param iconColor foreground color (for text, icons)
@@ -130,84 +69,30 @@ public class QuickQSMediaPlayer {
*/
public void setMediaSession(MediaSession.Token token, Icon icon, int iconColor, int bgColor,
View actionsContainer, int[] actionsToShow, PendingIntent contentIntent) {
- mToken = token;
- mForegroundColor = iconColor;
-
+ // Only update if this is a different session and currently playing
String oldPackage = "";
- if (mController != null) {
- oldPackage = mController.getPackageName();
+ if (getController() != null) {
+ oldPackage = getController().getPackageName();
}
- MediaController controller = new MediaController(mContext, token);
- boolean samePlayer = mToken.equals(token) && oldPackage.equals(controller.getPackageName());
- if (mController != null && !samePlayer && !isPlaying(controller)) {
- // Only update if this is a different session and currently playing
+ MediaController controller = new MediaController(getContext(), token);
+ MediaSession.Token currentToken = getMediaSessionToken();
+ boolean samePlayer = currentToken != null
+ && currentToken.equals(token)
+ && oldPackage.equals(controller.getPackageName());
+ if (getController() != null && !samePlayer && !isPlaying(controller)) {
return;
}
- mController = controller;
- MediaMetadata mMediaMetadata = mController.getMetadata();
-
- // Try to find a receiver for the media button that matches this app
- PackageManager pm = mContext.getPackageManager();
- Intent it = new Intent(Intent.ACTION_MEDIA_BUTTON);
- List<ResolveInfo> info = pm.queryBroadcastReceiversAsUser(it, 0, mContext.getUser());
- if (info != null) {
- for (ResolveInfo inf : info) {
- if (inf.activityInfo.packageName.equals(mController.getPackageName())) {
- mRecvComponent = inf.getComponentInfo().getComponentName();
- }
- }
- }
- mController.registerCallback(mSessionCallback);
-
- if (mMediaMetadata == null) {
- Log.e(TAG, "Media metadata was null");
- return;
- }
-
- // Action
- mMediaNotifView.setOnClickListener(v -> {
- try {
- contentIntent.send();
- mContext.sendBroadcast(new Intent(Intent.ACTION_CLOSE_SYSTEM_DIALOGS));
- } catch (PendingIntent.CanceledException e) {
- Log.e(TAG, "Pending intent was canceled: " + e.getMessage());
- }
- });
-
- mMediaNotifView.setBackgroundTintList(ColorStateList.valueOf(bgColor));
-
- // App icon
- ImageView appIcon = mMediaNotifView.findViewById(R.id.icon);
- Drawable iconDrawable = icon.loadDrawable(mContext);
- iconDrawable.setTint(mForegroundColor);
- appIcon.setImageDrawable(iconDrawable);
- // Song name
- TextView titleText = mMediaNotifView.findViewById(R.id.header_title);
- String songName = mMediaMetadata.getString(MediaMetadata.METADATA_KEY_TITLE);
- titleText.setText(songName);
- titleText.setTextColor(mForegroundColor);
+ super.setMediaSession(token, icon, iconColor, bgColor, contentIntent, null, null);
- // Buttons we can display
- final int[] actionIds = {R.id.action0, R.id.action1, R.id.action2};
-
- // Existing buttons in the notification
LinearLayout parentActionsLayout = (LinearLayout) actionsContainer;
- final int[] notifActionIds = {
- com.android.internal.R.id.action0,
- com.android.internal.R.id.action1,
- com.android.internal.R.id.action2,
- com.android.internal.R.id.action3,
- com.android.internal.R.id.action4
- };
-
int i = 0;
if (actionsToShow != null) {
int maxButtons = Math.min(actionsToShow.length, parentActionsLayout.getChildCount());
- maxButtons = Math.min(maxButtons, actionIds.length);
+ maxButtons = Math.min(maxButtons, QQS_ACTION_IDS.length);
for (; i < maxButtons; i++) {
- ImageButton thisBtn = mMediaNotifView.findViewById(actionIds[i]);
- int thatId = notifActionIds[actionsToShow[i]];
+ ImageButton thisBtn = mMediaNotifView.findViewById(QQS_ACTION_IDS[i]);
+ int thatId = NOTIF_ACTION_IDS[actionsToShow[i]];
ImageButton thatBtn = parentActionsLayout.findViewById(thatId);
if (thatBtn == null || thatBtn.getDrawable() == null
|| thatBtn.getVisibility() != View.VISIBLE) {
@@ -225,38 +110,9 @@ public class QuickQSMediaPlayer {
}
// Hide any unused buttons
- for (; i < actionIds.length; i++) {
- ImageButton thisBtn = mMediaNotifView.findViewById(actionIds[i]);
+ for (; i < QQS_ACTION_IDS.length; i++) {
+ ImageButton thisBtn = mMediaNotifView.findViewById(QQS_ACTION_IDS[i]);
thisBtn.setVisibility(View.GONE);
}
}
-
- public MediaSession.Token getMediaSessionToken() {
- return mToken;
- }
-
- /**
- * Check whether the media controlled by this player is currently playing
- * @return whether it is playing, or false if no controller information
- */
- public boolean isPlaying(MediaController controller) {
- if (controller == null) {
- return false;
- }
-
- PlaybackState state = controller.getPlaybackState();
- if (state == null) {
- return false;
- }
-
- return (state.getState() == PlaybackState.STATE_PLAYING);
- }
-
- /**
- * Check whether this player has an attached media session.
- * @return whether there is a controller with a current media session.
- */
- public boolean hasMediaSession() {
- return mController != null && mController.getPlaybackState() != null;
- }
}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QuickQSPanel.java b/packages/SystemUI/src/com/android/systemui/qs/QuickQSPanel.java
index 20efbcb3cc42..3da767e51be0 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QuickQSPanel.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QuickQSPanel.java
@@ -29,18 +29,21 @@ import android.widget.LinearLayout;
import com.android.systemui.Dependency;
import com.android.systemui.R;
import com.android.systemui.broadcast.BroadcastDispatcher;
+import com.android.systemui.dagger.qualifiers.Background;
import com.android.systemui.dump.DumpManager;
import com.android.systemui.plugins.qs.QSTile;
import com.android.systemui.plugins.qs.QSTile.SignalState;
import com.android.systemui.plugins.qs.QSTile.State;
import com.android.systemui.qs.customize.QSCustomizer;
import com.android.systemui.qs.logging.QSLogger;
+import com.android.systemui.statusbar.NotificationMediaManager;
import com.android.systemui.tuner.TunerService;
import com.android.systemui.tuner.TunerService.Tunable;
import com.android.systemui.util.Utils;
import java.util.ArrayList;
import java.util.Collection;
+import java.util.concurrent.Executor;
import javax.inject.Inject;
import javax.inject.Named;
@@ -72,9 +75,12 @@ public class QuickQSPanel extends QSPanel {
AttributeSet attrs,
DumpManager dumpManager,
BroadcastDispatcher broadcastDispatcher,
- QSLogger qsLogger
+ QSLogger qsLogger,
+ NotificationMediaManager notificationMediaManager,
+ @Background Executor backgroundExecutor
) {
- super(context, attrs, dumpManager, broadcastDispatcher, qsLogger);
+ super(context, attrs, dumpManager, broadcastDispatcher, qsLogger, notificationMediaManager,
+ backgroundExecutor);
if (mFooter != null) {
removeView(mFooter.getView());
}
@@ -93,7 +99,8 @@ public class QuickQSPanel extends QSPanel {
mHorizontalLinearLayout.setClipToPadding(false);
int marginSize = (int) mContext.getResources().getDimension(R.dimen.qqs_media_spacing);
- mMediaPlayer = new QuickQSMediaPlayer(mContext, mHorizontalLinearLayout);
+ mMediaPlayer = new QuickQSMediaPlayer(mContext, mHorizontalLinearLayout,
+ notificationMediaManager, backgroundExecutor);
LayoutParams lp2 = new LayoutParams(0, LayoutParams.MATCH_PARENT, 1);
lp2.setMarginEnd(marginSize);
lp2.setMarginStart(0);
diff --git a/packages/SystemUI/src/com/android/systemui/screenshot/TakeScreenshotService.java b/packages/SystemUI/src/com/android/systemui/screenshot/TakeScreenshotService.java
index 37a8ca5c42c3..8b8b6f8071e1 100644
--- a/packages/SystemUI/src/com/android/systemui/screenshot/TakeScreenshotService.java
+++ b/packages/SystemUI/src/com/android/systemui/screenshot/TakeScreenshotService.java
@@ -16,10 +16,6 @@
package com.android.systemui.screenshot;
-import static android.provider.DeviceConfig.NAMESPACE_SYSTEMUI;
-
-import static com.android.internal.config.sysui.SystemUiDeviceConfigFlags.SCREENSHOT_CORNER_FLOW;
-
import android.app.Service;
import android.content.Intent;
import android.graphics.Bitmap;
@@ -33,7 +29,6 @@ import android.os.Message;
import android.os.Messenger;
import android.os.RemoteException;
import android.os.UserManager;
-import android.provider.DeviceConfig;
import android.util.Log;
import android.view.WindowManager;
@@ -70,8 +65,7 @@ public class TakeScreenshotService extends Service {
}
// TODO (mkephart): clean up once notifications flow is fully deprecated
- boolean useCornerFlow = DeviceConfig.getBoolean(
- NAMESPACE_SYSTEMUI, SCREENSHOT_CORNER_FLOW, true);
+ boolean useCornerFlow = true;
switch (msg.what) {
case WindowManager.TAKE_SCREENSHOT_FULLSCREEN:
if (useCornerFlow) {
diff --git a/packages/SystemUI/src/com/android/systemui/stackdivider/Divider.java b/packages/SystemUI/src/com/android/systemui/stackdivider/Divider.java
index 27b799bc02a3..fb6815336548 100644
--- a/packages/SystemUI/src/com/android/systemui/stackdivider/Divider.java
+++ b/packages/SystemUI/src/com/android/systemui/stackdivider/Divider.java
@@ -17,8 +17,13 @@
package com.android.systemui.stackdivider;
import static android.content.res.Configuration.ORIENTATION_LANDSCAPE;
+import static android.content.res.Configuration.SCREEN_HEIGHT_DP_UNDEFINED;
+import static android.content.res.Configuration.SCREEN_WIDTH_DP_UNDEFINED;
import static android.view.Display.DEFAULT_DISPLAY;
+import android.animation.Animator;
+import android.animation.AnimatorListenerAdapter;
+import android.animation.ValueAnimator;
import android.app.ActivityTaskManager;
import android.content.Context;
import android.content.res.Configuration;
@@ -35,6 +40,8 @@ import android.view.SurfaceSession;
import android.view.View;
import android.view.WindowContainerTransaction;
+import androidx.annotation.Nullable;
+
import com.android.internal.policy.DividerSnapAlgorithm;
import com.android.systemui.R;
import com.android.systemui.SystemUI;
@@ -69,6 +76,7 @@ public class Divider extends SystemUI implements DividerView.DividerCallbacks,
static final boolean DEBUG = true;
static final int DEFAULT_APP_TRANSITION_DURATION = 336;
+ static final float ADJUSTED_NONFOCUS_DIM = 0.3f;
private final Optional<Lazy<Recents>> mRecentsOptionalLazy;
@@ -121,81 +129,213 @@ public class Divider extends SystemUI implements DividerView.DividerCallbacks,
}
};
- private IWindowContainer mLastImeTarget = null;
- private boolean mShouldAdjustForIme = false;
+ private class DividerImeController implements DisplayImeController.ImePositionProcessor {
+ /**
+ * These are the y positions of the top of the IME surface when it is hidden and when it is
+ * shown respectively. These are NOT necessarily the top of the visible IME itself.
+ */
+ private int mHiddenTop = 0;
+ private int mShownTop = 0;
+
+ // The following are target states (what we are curretly animating towards).
+ /**
+ * {@code true} if, at the end of the animation, the split task positions should be
+ * adjusted by height of the IME. This happens when the secondary split is the IME target.
+ */
+ private boolean mTargetAdjusted = false;
+ /**
+ * {@code true} if, at the end of the animation, the IME should be shown/visible
+ * regardless of what has focus.
+ */
+ private boolean mTargetShown = false;
+
+ // The following are the current (most recent) states set during animation
+ /** {@code true} if the secondary split has IME focus. */
+ private boolean mSecondaryHasFocus = false;
+ /** The dimming currently applied to the primary/secondary splits. */
+ private float mLastPrimaryDim = 0.f;
+ private float mLastSecondaryDim = 0.f;
+ /** The most recent y position of the top of the IME surface */
+ private int mLastAdjustTop = -1;
+
+ // The following are states reached last time an animation fully completed.
+ /** {@code true} if the IME was shown/visible by the last-completed animation. */
+ private boolean mImeWasShown = false;
+ /** {@code true} if the split positions were adjusted by the last-completed animation. */
+ private boolean mAdjusted = false;
+
+ /**
+ * When some aspect of split-screen needs to animate independent from the IME,
+ * this will be non-null and control split animation.
+ */
+ @Nullable
+ private ValueAnimator mAnimation = null;
+
+ private boolean getSecondaryHasFocus(int displayId) {
+ try {
+ IWindowContainer imeSplit = ActivityTaskManager.getTaskOrganizerController()
+ .getImeTarget(displayId);
+ return imeSplit != null
+ && (imeSplit.asBinder() == mSplits.mSecondary.token.asBinder());
+ } catch (RemoteException e) {
+ Slog.w(TAG, "Failed to get IME target", e);
+ }
+ return false;
+ }
- private DisplayImeController.ImePositionProcessor mImePositionProcessor =
- new DisplayImeController.ImePositionProcessor() {
- private int mStartTop = 0;
- private int mFinalTop = 0;
- @Override
- public void onImeStartPositioning(int displayId, int imeTop, int finalImeTop,
- boolean showing, SurfaceControl.Transaction t) {
- mStartTop = imeTop;
- mFinalTop = finalImeTop;
- if (showing) {
- try {
- mLastImeTarget = ActivityTaskManager.getTaskOrganizerController()
- .getImeTarget(displayId);
- mShouldAdjustForIme = mLastImeTarget != null
- && !mSplitLayout.mDisplayLayout.isLandscape()
- && (mLastImeTarget.asBinder()
- == mSplits.mSecondary.token.asBinder());
- } catch (RemoteException e) {
- Slog.w(TAG, "Failed to get IME target", e);
- }
- }
- if (!mShouldAdjustForIme) {
- setAdjustedForIme(false);
- return;
- }
- mView.setAdjustedForIme(showing, showing
- ? DisplayImeController.ANIMATION_DURATION_SHOW_MS
- : DisplayImeController.ANIMATION_DURATION_HIDE_MS);
- // Reposition the server's secondary split position so that it evaluates
- // insets properly.
- WindowContainerTransaction wct = new WindowContainerTransaction();
- if (showing) {
- mSplitLayout.updateAdjustedBounds(finalImeTop, imeTop, finalImeTop);
- wct.setBounds(mSplits.mSecondary.token, mSplitLayout.mAdjustedSecondary);
- } else {
- wct.setBounds(mSplits.mSecondary.token, mSplitLayout.mSecondary);
- }
- try {
- ActivityTaskManager.getTaskOrganizerController()
- .applyContainerTransaction(wct, null /* organizer */);
- } catch (RemoteException e) {
- }
- setAdjustedForIme(showing);
- }
+ @Override
+ public void onImeStartPositioning(int displayId, int hiddenTop, int shownTop,
+ boolean imeShouldShow, SurfaceControl.Transaction t) {
+ mSecondaryHasFocus = getSecondaryHasFocus(displayId);
+ mTargetAdjusted = imeShouldShow && mSecondaryHasFocus
+ && !mSplitLayout.mDisplayLayout.isLandscape();
+ mHiddenTop = hiddenTop;
+ mShownTop = shownTop;
+ mTargetShown = imeShouldShow;
+ if (mLastAdjustTop < 0) {
+ mLastAdjustTop = imeShouldShow ? hiddenTop : shownTop;
+ }
+ if (mAnimation != null || (mImeWasShown && imeShouldShow
+ && mTargetAdjusted != mAdjusted)) {
+ // We need to animate adjustment independently of the IME position, so
+ // start our own animation to drive adjustment. This happens when a
+ // different split's editor has gained focus while the IME is still visible.
+ startAsyncAnimation();
+ }
+ updateImeAdjustState();
+ }
+
+ private void updateImeAdjustState() {
+ // Reposition the server's secondary split position so that it evaluates
+ // insets properly.
+ WindowContainerTransaction wct = new WindowContainerTransaction();
+ if (mTargetAdjusted) {
+ mSplitLayout.updateAdjustedBounds(mShownTop, mHiddenTop, mShownTop);
+ wct.setBounds(mSplits.mSecondary.token, mSplitLayout.mAdjustedSecondary);
+ // "Freeze" the configuration size so that the app doesn't get a config
+ // or relaunch. This is required because normally nav-bar contributes
+ // to configuration bounds (via nondecorframe).
+ Rect adjustAppBounds = new Rect(mSplits.mSecondary.configuration
+ .windowConfiguration.getAppBounds());
+ adjustAppBounds.offset(0, mSplitLayout.mAdjustedSecondary.top
+ - mSplitLayout.mSecondary.top);
+ wct.setAppBounds(mSplits.mSecondary.token, adjustAppBounds);
+ wct.setScreenSizeDp(mSplits.mSecondary.token,
+ mSplits.mSecondary.configuration.screenWidthDp,
+ mSplits.mSecondary.configuration.screenHeightDp);
+ } else {
+ wct.setBounds(mSplits.mSecondary.token, mSplitLayout.mSecondary);
+ wct.setAppBounds(mSplits.mSecondary.token, null);
+ wct.setScreenSizeDp(mSplits.mSecondary.token,
+ SCREEN_WIDTH_DP_UNDEFINED, SCREEN_HEIGHT_DP_UNDEFINED);
+ }
+ try {
+ ActivityTaskManager.getTaskOrganizerController()
+ .applyContainerTransaction(wct, null /* organizer */);
+ } catch (RemoteException e) {
+ }
+
+ // Update all the adjusted-for-ime states
+ mView.setAdjustedForIme(mTargetShown, mTargetShown
+ ? DisplayImeController.ANIMATION_DURATION_SHOW_MS
+ : DisplayImeController.ANIMATION_DURATION_HIDE_MS);
+ setAdjustedForIme(mTargetShown);
+ }
+
+ @Override
+ public void onImePositionChanged(int displayId, int imeTop,
+ SurfaceControl.Transaction t) {
+ if (mAnimation != null) {
+ // Not synchronized with IME anymore, so return.
+ return;
+ }
+ final float fraction = ((float) imeTop - mHiddenTop) / (mShownTop - mHiddenTop);
+ final float progress = mTargetShown ? fraction : 1.f - fraction;
+ onProgress(progress, t);
+ }
+
+ @Override
+ public void onImeEndPositioning(int displayId, boolean cancelled,
+ SurfaceControl.Transaction t) {
+ if (mAnimation != null) {
+ // Not synchronized with IME anymore, so return.
+ return;
+ }
+ onEnd(cancelled, t);
+ }
+
+ private void onProgress(float progress, SurfaceControl.Transaction t) {
+ if (mTargetAdjusted != mAdjusted) {
+ final float fraction = mTargetAdjusted ? progress : 1.f - progress;
+ mLastAdjustTop = (int) (fraction * mShownTop + (1.f - fraction) * mHiddenTop);
+ mSplitLayout.updateAdjustedBounds(mLastAdjustTop, mHiddenTop, mShownTop);
+ mView.resizeSplitSurfaces(t, mSplitLayout.mAdjustedPrimary,
+ mSplitLayout.mAdjustedSecondary);
+ }
+ final float invProg = 1.f - progress;
+ final float targetPrimaryDim =
+ (mSecondaryHasFocus && mTargetShown) ? ADJUSTED_NONFOCUS_DIM : 0.f;
+ final float targetSecondaryDim =
+ (!mSecondaryHasFocus && mTargetShown) ? ADJUSTED_NONFOCUS_DIM : 0.f;
+ mView.setResizeDimLayer(t, true /* primary */,
+ mLastPrimaryDim * invProg + progress * targetPrimaryDim);
+ mView.setResizeDimLayer(t, false /* primary */,
+ mLastSecondaryDim * invProg + progress * targetSecondaryDim);
+ }
+
+ private void onEnd(boolean cancelled, SurfaceControl.Transaction t) {
+ if (!cancelled) {
+ onProgress(1.f, t);
+ mAdjusted = mTargetAdjusted;
+ mImeWasShown = mTargetShown;
+ mLastAdjustTop = mAdjusted ? mShownTop : mHiddenTop;
+ mLastPrimaryDim =
+ (mSecondaryHasFocus && mTargetShown) ? ADJUSTED_NONFOCUS_DIM : 0.f;
+ mLastSecondaryDim =
+ (!mSecondaryHasFocus && mTargetShown) ? ADJUSTED_NONFOCUS_DIM : 0.f;
+ }
+ }
+
+ private void startAsyncAnimation() {
+ if (mAnimation != null) {
+ mAnimation.cancel();
+ }
+ mAnimation = ValueAnimator.ofFloat(0.f, 1.f);
+ mAnimation.setDuration(DisplayImeController.ANIMATION_DURATION_SHOW_MS);
+ if (mTargetAdjusted != mAdjusted) {
+ final float fraction =
+ ((float) mLastAdjustTop - mHiddenTop) / (mShownTop - mHiddenTop);
+ final float progress = mTargetAdjusted ? fraction : 1.f - fraction;
+ mAnimation.setCurrentFraction(progress);
+ }
+ mAnimation.addUpdateListener(animation -> {
+ SurfaceControl.Transaction t = mTransactionPool.acquire();
+ float value = (float) animation.getAnimatedValue();
+ onProgress(value, t);
+ t.apply();
+ mTransactionPool.release(t);
+ });
+ mAnimation.setInterpolator(DisplayImeController.INTERPOLATOR);
+ mAnimation.addListener(new AnimatorListenerAdapter() {
+ private boolean mCancel = false;
@Override
- public void onImePositionChanged(int displayId, int imeTop,
- SurfaceControl.Transaction t) {
- if (!mShouldAdjustForIme) {
- return;
- }
- mSplitLayout.updateAdjustedBounds(imeTop, mStartTop, mFinalTop);
- mView.resizeSplitSurfaces(t, mSplitLayout.mAdjustedPrimary,
- mSplitLayout.mAdjustedSecondary);
- final boolean showing = mFinalTop < mStartTop;
- final float progress = ((float) (imeTop - mStartTop)) / (mFinalTop - mStartTop);
- final float fraction = showing ? progress : 1.f - progress;
- mView.setResizeDimLayer(t, true /* primary */, fraction * 0.3f);
+ public void onAnimationCancel(Animator animation) {
+ mCancel = true;
}
-
@Override
- public void onImeEndPositioning(int displayId, int imeTop,
- boolean showing, SurfaceControl.Transaction t) {
- if (!mShouldAdjustForIme) {
- return;
- }
- mSplitLayout.updateAdjustedBounds(imeTop, mStartTop, mFinalTop);
- mView.resizeSplitSurfaces(t, mSplitLayout.mAdjustedPrimary,
- mSplitLayout.mAdjustedSecondary);
- mView.setResizeDimLayer(t, true /* primary */, showing ? 0.3f : 0.f);
+ public void onAnimationEnd(Animator animation) {
+ SurfaceControl.Transaction t = mTransactionPool.acquire();
+ onEnd(mCancel, t);
+ t.apply();
+ mTransactionPool.release(t);
+ mAnimation = null;
}
- };
+ });
+ mAnimation.start();
+ }
+ }
+ private final DividerImeController mImePositionProcessor = new DividerImeController();
public Divider(Context context, Optional<Lazy<Recents>> recentsOptionalLazy,
DisplayController displayController, SystemWindows systemWindows,
@@ -369,42 +509,37 @@ public class Divider extends SystemUI implements DividerView.DividerCallbacks,
}
}
- private void setHomeStackResizable(boolean resizable) {
- if (mHomeStackResizable == resizable) {
- return;
+ /** Switch to minimized state if appropriate */
+ public void setMinimized(final boolean minimized) {
+ mHandler.post(() -> {
+ setHomeMinimized(minimized, mHomeStackResizable);
+ });
+ }
+
+ private void setHomeMinimized(final boolean minimized, boolean homeStackResizable) {
+ WindowContainerTransaction wct = new WindowContainerTransaction();
+ // Update minimized state
+ if (mMinimized != minimized) {
+ mMinimized = minimized;
}
- mHomeStackResizable = resizable;
- if (!inSplitMode()) {
- return;
+ // Always set this because we could be entering split when mMinimized is already true
+ wct.setFocusable(mSplits.mPrimary.token, !mMinimized);
+
+ // Update home-stack resizability
+ if (mHomeStackResizable != homeStackResizable) {
+ mHomeStackResizable = homeStackResizable;
+ if (inSplitMode()) {
+ WindowManagerProxy.applyHomeTasksMinimized(
+ mSplitLayout, mSplits.mSecondary.token, wct);
+ }
}
- WindowManagerProxy.applyHomeTasksMinimized(mSplitLayout, mSplits.mSecondary.token);
- }
- private void updateMinimizedDockedStack(final boolean minimized, final long animDuration,
- final boolean isHomeStackResizable) {
- setHomeStackResizable(isHomeStackResizable);
- if (animDuration > 0) {
- mView.setMinimizedDockStack(minimized, animDuration, isHomeStackResizable);
- } else {
- mView.setMinimizedDockStack(minimized, isHomeStackResizable);
+ // Sync state to DividerView if it exists.
+ if (mView != null) {
+ mView.setMinimizedDockStack(minimized, getAnimDuration(), homeStackResizable);
}
updateTouchable();
- }
-
- /** Switch to minimized state if appropriate */
- public void setMinimized(final boolean minimized) {
- mHandler.post(() -> {
- if (!inSplitMode()) {
- return;
- }
- if (mMinimized == minimized) {
- return;
- }
- mMinimized = minimized;
- WindowManagerProxy.applyPrimaryFocusable(mSplits, !mMinimized);
- mView.setMinimizedDockStack(minimized, getAnimDuration(), mHomeStackResizable);
- updateTouchable();
- });
+ WindowManagerProxy.applyContainerTransaction(wct);
}
void setAdjustedForIme(boolean adjustedForIme) {
@@ -502,46 +637,24 @@ public class Divider extends SystemUI implements DividerView.DividerCallbacks,
}
void ensureMinimizedSplit() {
- final boolean wasMinimized = mMinimized;
- mMinimized = true;
- setHomeStackResizable(mSplits.mSecondary.isResizable());
- WindowManagerProxy.applyPrimaryFocusable(mSplits, false /* focusable */);
+ setHomeMinimized(true /* minimized */, mSplits.mSecondary.isResizable());
if (!inSplitMode()) {
// Wasn't in split-mode yet, so enter now.
if (DEBUG) {
Log.d(TAG, " entering split mode with minimized=true");
}
updateVisibility(true /* visible */);
- } else if (!wasMinimized) {
- if (DEBUG) {
- Log.d(TAG, " in split mode, but minimizing ");
- }
- // Was already in split-mode, update just minimized state.
- updateMinimizedDockedStack(mMinimized, getAnimDuration(),
- mHomeStackResizable);
}
}
void ensureNormalSplit() {
- if (mMinimized) {
- WindowManagerProxy.applyPrimaryFocusable(mSplits, true /* focusable */);
- }
+ setHomeMinimized(false /* minimized */, mHomeStackResizable);
if (!inSplitMode()) {
// Wasn't in split-mode, so enter now.
if (DEBUG) {
Log.d(TAG, " enter split mode unminimized ");
}
- mMinimized = false;
updateVisibility(true /* visible */);
}
- if (mMinimized) {
- // Was in minimized state, so leave that.
- if (DEBUG) {
- Log.d(TAG, " in split mode already, but unminimizing ");
- }
- mMinimized = false;
- updateMinimizedDockedStack(mMinimized, getAnimDuration(),
- mHomeStackResizable);
- }
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/stackdivider/DividerView.java b/packages/SystemUI/src/com/android/systemui/stackdivider/DividerView.java
index be9fcbf19f12..477cbb7c7ad0 100644
--- a/packages/SystemUI/src/com/android/systemui/stackdivider/DividerView.java
+++ b/packages/SystemUI/src/com/android/systemui/stackdivider/DividerView.java
@@ -935,6 +935,9 @@ public class DividerView extends FrameLayout implements OnTouchListener,
}
public void setAdjustedForIme(boolean adjustedForIme, long animDuration) {
+ if (mAdjustedForIme == adjustedForIme) {
+ return;
+ }
updateDockSide();
mHandle.animate()
.setInterpolator(IME_ADJUST_INTERPOLATOR)
diff --git a/packages/SystemUI/src/com/android/systemui/stackdivider/DividerWindowManager.java b/packages/SystemUI/src/com/android/systemui/stackdivider/DividerWindowManager.java
index 3020a25dfa47..729df3887915 100644
--- a/packages/SystemUI/src/com/android/systemui/stackdivider/DividerWindowManager.java
+++ b/packages/SystemUI/src/com/android/systemui/stackdivider/DividerWindowManager.java
@@ -88,6 +88,9 @@ public class DividerWindowManager {
}
public void setTouchable(boolean touchable) {
+ if (mView == null) {
+ return;
+ }
boolean changed = false;
if (!touchable && (mLp.flags & FLAG_NOT_TOUCHABLE) == 0) {
mLp.flags |= FLAG_NOT_TOUCHABLE;
diff --git a/packages/SystemUI/src/com/android/systemui/stackdivider/SplitDisplayLayout.java b/packages/SystemUI/src/com/android/systemui/stackdivider/SplitDisplayLayout.java
index b19f560f2f50..271faed54bca 100644
--- a/packages/SystemUI/src/com/android/systemui/stackdivider/SplitDisplayLayout.java
+++ b/packages/SystemUI/src/com/android/systemui/stackdivider/SplitDisplayLayout.java
@@ -171,22 +171,13 @@ public class SplitDisplayLayout {
/**
* Updates the adjustment depending on it's current state.
*/
- void updateAdjustedBounds(int currImeTop, int startTop, int finalTop) {
- updateAdjustedBounds(mDisplayLayout, currImeTop, startTop, finalTop, mDividerSize,
+ void updateAdjustedBounds(int currImeTop, int hiddenTop, int shownTop) {
+ adjustForIME(mDisplayLayout, currImeTop, hiddenTop, shownTop, mDividerSize,
mDividerSizeInactive, mPrimary, mSecondary);
}
- /**
- * Updates the adjustment depending on it's current state.
- */
- private void updateAdjustedBounds(DisplayLayout dl, int currImeTop, int startTop, int finalTop,
- int dividerWidth, int dividerWidthInactive, Rect primaryBounds, Rect secondaryBounds) {
- adjustForIME(dl, currImeTop, startTop, finalTop, dividerWidth, dividerWidthInactive,
- primaryBounds, secondaryBounds);
- }
-
/** Assumes top/bottom split. Splits are not adjusted for left/right splits. */
- private void adjustForIME(DisplayLayout dl, int currImeTop, int startTop, int finalTop,
+ private void adjustForIME(DisplayLayout dl, int currImeTop, int hiddenTop, int shownTop,
int dividerWidth, int dividerWidthInactive, Rect primaryBounds, Rect secondaryBounds) {
if (mAdjustedPrimary == null) {
mAdjustedPrimary = new Rect();
@@ -196,11 +187,9 @@ public class SplitDisplayLayout {
final Rect displayStableRect = new Rect();
dl.getStableBounds(displayStableRect);
- final boolean showing = finalTop < startTop;
- final float progress = ((float) (currImeTop - startTop)) / (finalTop - startTop);
- final float dividerSquish = showing ? progress : 1.f - progress;
+ final float shownFraction = ((float) (currImeTop - hiddenTop)) / (shownTop - hiddenTop);
final int currDividerWidth =
- (int) (dividerWidthInactive * dividerSquish + dividerWidth * (1.f - dividerSquish));
+ (int) (dividerWidthInactive * shownFraction + dividerWidth * (1.f - shownFraction));
final int minTopStackBottom = displayStableRect.top
+ (int) ((mPrimary.bottom - displayStableRect.top) * ADJUSTED_STACK_FRACTION_MIN);
diff --git a/packages/SystemUI/src/com/android/systemui/stackdivider/WindowManagerProxy.java b/packages/SystemUI/src/com/android/systemui/stackdivider/WindowManagerProxy.java
index 167c33abac6e..fea57a320d04 100644
--- a/packages/SystemUI/src/com/android/systemui/stackdivider/WindowManagerProxy.java
+++ b/packages/SystemUI/src/com/android/systemui/stackdivider/WindowManagerProxy.java
@@ -21,6 +21,7 @@ import static android.app.WindowConfiguration.ACTIVITY_TYPE_RECENTS;
import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN;
import static android.view.Display.DEFAULT_DISPLAY;
+import android.annotation.NonNull;
import android.app.ActivityManager;
import android.app.ActivityTaskManager;
import android.graphics.Rect;
@@ -137,17 +138,13 @@ public class WindowManagerProxy {
return resizable;
}
- static void applyHomeTasksMinimized(SplitDisplayLayout layout, IWindowContainer parent) {
- applyHomeTasksMinimized(layout, parent, null /* transaction */);
- }
-
/**
* Assign a fixed override-bounds to home tasks that reflect their geometry while the primary
* split is minimized. This actually "sticks out" of the secondary split area, but when in
* minimized mode, the secondary split gets a 'negative' crop to expose it.
*/
static boolean applyHomeTasksMinimized(SplitDisplayLayout layout, IWindowContainer parent,
- WindowContainerTransaction t) {
+ @NonNull WindowContainerTransaction wct) {
// Resize the home/recents stacks to the larger minimized-state size
final Rect homeBounds;
final ArrayList<IWindowContainer> homeStacks = new ArrayList<>();
@@ -158,19 +155,9 @@ public class WindowManagerProxy {
homeBounds = new Rect(0, 0, layout.mDisplayLayout.width(),
layout.mDisplayLayout.height());
}
- WindowContainerTransaction wct = t != null ? t : new WindowContainerTransaction();
for (int i = homeStacks.size() - 1; i >= 0; --i) {
wct.setBounds(homeStacks.get(i), homeBounds);
}
- if (t != null) {
- return isHomeResizable;
- }
- try {
- ActivityTaskManager.getTaskOrganizerController().applyContainerTransaction(wct,
- null /* organizer */);
- } catch (RemoteException e) {
- Log.e(TAG, "Failed to resize home stacks ", e);
- }
return isHomeResizable;
}
@@ -301,10 +288,8 @@ public class WindowManagerProxy {
}
}
- static void applyPrimaryFocusable(SplitScreenTaskOrganizer splits, boolean focusable) {
+ static void applyContainerTransaction(WindowContainerTransaction wct) {
try {
- WindowContainerTransaction wct = new WindowContainerTransaction();
- wct.setFocusable(splits.mPrimary.token, focusable);
ActivityTaskManager.getTaskOrganizerController().applyContainerTransaction(wct,
null /* organizer */);
} catch (RemoteException e) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/MediaArtworkProcessor.kt b/packages/SystemUI/src/com/android/systemui/statusbar/MediaArtworkProcessor.kt
index 711d6a6daeef..326757e9a4c1 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/MediaArtworkProcessor.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/MediaArtworkProcessor.kt
@@ -19,6 +19,7 @@ package com.android.systemui.statusbar
import android.content.Context
import android.graphics.Bitmap
import android.graphics.Canvas
+import android.graphics.Point
import android.graphics.Rect
import android.renderscript.Allocation
import android.renderscript.Element
@@ -26,11 +27,9 @@ import android.renderscript.RenderScript
import android.renderscript.ScriptIntrinsicBlur
import android.util.Log
import android.util.MathUtils
-import android.util.Size
-import android.view.WindowManager
-import com.android.internal.annotations.VisibleForTesting
import com.android.internal.graphics.ColorUtils
import com.android.systemui.statusbar.notification.MediaNotificationProcessor
+
import javax.inject.Inject
import javax.inject.Singleton
@@ -42,9 +41,10 @@ private const val DOWNSAMPLE = 6
@Singleton
class MediaArtworkProcessor @Inject constructor() {
+ private val mTmpSize = Point()
private var mArtworkCache: Bitmap? = null
- fun processArtwork(context: Context, artwork: Bitmap, windowType: Int): Bitmap? {
+ fun processArtwork(context: Context, artwork: Bitmap): Bitmap? {
if (mArtworkCache != null) {
return mArtworkCache
}
@@ -54,9 +54,10 @@ class MediaArtworkProcessor @Inject constructor() {
var output: Allocation? = null
var inBitmap: Bitmap? = null
try {
- val size = getWindowSize(context, windowType)
+ @Suppress("DEPRECATION")
+ context.display?.getSize(mTmpSize)
val rect = Rect(0, 0, artwork.width, artwork.height)
- MathUtils.fitRect(rect, Math.max(size.width / DOWNSAMPLE, size.height / DOWNSAMPLE))
+ MathUtils.fitRect(rect, Math.max(mTmpSize.x / DOWNSAMPLE, mTmpSize.y / DOWNSAMPLE))
inBitmap = Bitmap.createScaledBitmap(artwork, rect.width(), rect.height(),
true /* filter */)
// Render script blurs only support ARGB_8888, we need a conversion if we got a
@@ -98,15 +99,4 @@ class MediaArtworkProcessor @Inject constructor() {
mArtworkCache?.recycle()
mArtworkCache = null
}
-
- @VisibleForTesting
- internal fun getWindowSize(context: Context, windowType: Int): Size {
- val windowContext = context.display?.let {
- context.createDisplayContext(it)
- .createWindowContext(windowType, null)
- } ?: run { throw NullPointerException("Display is null") }
- val windowManager = windowContext.getSystemService(WindowManager::class.java)
- ?: run { throw NullPointerException("Null window manager") }
- return windowManager.currentWindowMetrics.size
- }
} \ No newline at end of file
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NavigationBarController.java b/packages/SystemUI/src/com/android/systemui/statusbar/NavigationBarController.java
index ebac4b293522..1b7524521d76 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/NavigationBarController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/NavigationBarController.java
@@ -165,6 +165,7 @@ public class NavigationBarController implements Callbacks {
private void removeNavigationBar(int displayId) {
NavigationBarFragment navBar = mNavigationBars.get(displayId);
if (navBar != null) {
+ navBar.setAutoHideController(/* autoHideController */ null);
View navigationWindow = navBar.getView().getRootView();
WindowManagerGlobal.getInstance()
.removeView(navigationWindow, true /* immediate */);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationMediaManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationMediaManager.java
index 3d7beea7cd6f..87be73998fcc 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationMediaManager.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationMediaManager.java
@@ -42,7 +42,6 @@ import android.provider.DeviceConfig.Properties;
import android.util.ArraySet;
import android.util.Log;
import android.view.View;
-import android.view.WindowManager;
import android.widget.ImageView;
import com.android.internal.config.sysui.SystemUiDeviceConfigFlags;
@@ -674,8 +673,7 @@ public class NotificationMediaManager implements Dumpable {
};
private Bitmap processArtwork(Bitmap artwork) {
- return mMediaArtworkProcessor.processArtwork(mContext, artwork,
- WindowManager.LayoutParams.TYPE_NOTIFICATION_SHADE);
+ return mMediaArtworkProcessor.processArtwork(mContext, artwork);
}
@MainThread
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationShadeWindowBlurController.kt b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationShadeWindowBlurController.kt
index aadc4510170f..6e905a30e590 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationShadeWindowBlurController.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationShadeWindowBlurController.kt
@@ -21,6 +21,9 @@ import android.animation.AnimatorListenerAdapter
import android.animation.ValueAnimator
import android.view.Choreographer
import android.view.View
+import androidx.dynamicanimation.animation.FloatPropertyCompat
+import androidx.dynamicanimation.animation.SpringAnimation
+import androidx.dynamicanimation.animation.SpringForce
import com.android.internal.util.IndentingPrintWriter
import com.android.systemui.Dumpable
import com.android.systemui.Interpolators
@@ -59,6 +62,16 @@ class NotificationShadeWindowBlurController @Inject constructor(
private var notificationAnimator: Animator? = null
private var updateScheduled: Boolean = false
private var shadeExpansion = 1.0f
+ private val shadeSpring = SpringAnimation(this, object :
+ FloatPropertyCompat<NotificationShadeWindowBlurController>("shadeBlurRadius") {
+ override fun setValue(rect: NotificationShadeWindowBlurController?, value: Float) {
+ shadeBlurRadius = value.toInt()
+ }
+
+ override fun getValue(rect: NotificationShadeWindowBlurController?): Float {
+ return shadeBlurRadius.toFloat()
+ }
+ })
private var shadeBlurRadius = 0
set(value) {
if (field == value) return
@@ -135,6 +148,9 @@ class NotificationShadeWindowBlurController @Inject constructor(
if (WAKE_UP_ANIMATION_ENABLED) {
keyguardStateController.addCallback(keyguardStateCallback)
}
+ shadeSpring.spring = SpringForce(0.0f)
+ shadeSpring.spring.dampingRatio = SpringForce.DAMPING_RATIO_NO_BOUNCY
+ shadeSpring.spring.stiffness = SpringForce.STIFFNESS_LOW
}
/**
@@ -153,8 +169,7 @@ class NotificationShadeWindowBlurController @Inject constructor(
if (shadeBlurRadius == newBlur) {
return
}
- shadeBlurRadius = newBlur
- scheduleUpdate()
+ shadeSpring.animateToFinalPosition(newBlur.toFloat())
}
private fun scheduleUpdate() {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/ScrimView.java b/packages/SystemUI/src/com/android/systemui/statusbar/ScrimView.java
index 04f1c3248a6f..7f30009cda6f 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/ScrimView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/ScrimView.java
@@ -16,6 +16,8 @@
package com.android.systemui.statusbar;
+import static java.lang.Float.isNaN;
+
import android.annotation.NonNull;
import android.content.Context;
import android.graphics.Canvas;
@@ -179,6 +181,9 @@ public class ScrimView extends View {
* @param alpha Gradient alpha from 0 to 1.
*/
public void setViewAlpha(float alpha) {
+ if (isNaN(alpha)) {
+ throw new IllegalArgumentException("alpha cannot be NaN: " + alpha);
+ }
if (alpha != mViewAlpha) {
mViewAlpha = alpha;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/ActivityLaunchAnimator.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/ActivityLaunchAnimator.java
index 53605e5a308a..7c061574f19c 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/ActivityLaunchAnimator.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/ActivityLaunchAnimator.java
@@ -282,7 +282,7 @@ public class ActivityLaunchAnimator {
.withCornerRadius(mCornerRadius)
.withVisibility(true)
.build();
- mSyncRtTransactionApplier.scheduleApply(params);
+ mSyncRtTransactionApplier.scheduleApply(true /* earlyWakeup */, params);
}
@Override
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/ForegroundServiceDismissalFeatureController.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/ForegroundServiceDismissalFeatureController.kt
index b1d6b40fcc1e..571a85440b89 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/ForegroundServiceDismissalFeatureController.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/ForegroundServiceDismissalFeatureController.kt
@@ -42,8 +42,8 @@ class ForegroundServiceDismissalFeatureController @Inject constructor(
private fun isEnabled(proxy: DeviceConfigProxy): Boolean {
if (sIsEnabled == null) {
sIsEnabled = proxy.getBoolean(
- DeviceConfig.NAMESPACE_SYSTEMUI, NOTIFICATIONS_ALLOW_FGS_DISMISSAL, false)
+ DeviceConfig.NAMESPACE_SYSTEMUI, NOTIFICATIONS_ALLOW_FGS_DISMISSAL, true)
}
return sIsEnabled!!
-} \ No newline at end of file
+}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotificationRankingManager.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotificationRankingManager.kt
index 9c942a52b966..8674047f4ab2 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotificationRankingManager.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotificationRankingManager.kt
@@ -27,6 +27,9 @@ import com.android.systemui.statusbar.notification.NotificationFilter
import com.android.systemui.statusbar.notification.NotificationSectionsFeatureManager
import com.android.systemui.statusbar.notification.collection.provider.HighPriorityProvider
import com.android.systemui.statusbar.notification.people.PeopleNotificationIdentifier
+import com.android.systemui.statusbar.notification.people.PeopleNotificationIdentifier.Companion.TYPE_IMPORTANT_PERSON
+import com.android.systemui.statusbar.notification.people.PeopleNotificationIdentifier.Companion.TYPE_NON_PERSON
+import com.android.systemui.statusbar.notification.people.PeopleNotificationIdentifier.Companion.TYPE_PERSON
import com.android.systemui.statusbar.notification.stack.NotificationSectionsManager.BUCKET_ALERTING
import com.android.systemui.statusbar.notification.stack.NotificationSectionsManager.BUCKET_HEADS_UP
import com.android.systemui.statusbar.notification.stack.NotificationSectionsManager.BUCKET_PEOPLE
@@ -72,11 +75,14 @@ open class NotificationRankingManager @Inject constructor(
val aRank = a.ranking.rank
val bRank = b.ranking.rank
- val aIsPeople = a.isPeopleNotification()
- val bIsPeople = b.isPeopleNotification()
+ val aPersonType = a.getPeopleNotificationType()
+ val bPersonType = b.getPeopleNotificationType()
- val aIsImportantPeople = a.isImportantPeopleNotification()
- val bIsImportantPeople = b.isImportantPeopleNotification()
+ val aIsPeople = aPersonType == TYPE_PERSON
+ val bIsPeople = bPersonType == TYPE_PERSON
+
+ val aIsImportantPeople = aPersonType == TYPE_IMPORTANT_PERSON
+ val bIsImportantPeople = bPersonType == TYPE_IMPORTANT_PERSON
val aMedia = isImportantMedia(a)
val bMedia = isImportantMedia(b)
@@ -165,7 +171,7 @@ open class NotificationRankingManager @Inject constructor(
) {
if (usePeopleFiltering && isHeadsUp) {
entry.bucket = BUCKET_HEADS_UP
- } else if (usePeopleFiltering && entry.isPeopleNotification()) {
+ } else if (usePeopleFiltering && entry.getPeopleNotificationType() != TYPE_NON_PERSON) {
entry.bucket = BUCKET_PEOPLE
} else if (isHeadsUp || isMedia || isSystemMax || entry.isHighPriority()) {
entry.bucket = BUCKET_ALERTING
@@ -198,11 +204,8 @@ open class NotificationRankingManager @Inject constructor(
}
}
- private fun NotificationEntry.isPeopleNotification() =
- peopleNotificationIdentifier.isPeopleNotification(sbn, ranking)
-
- private fun NotificationEntry.isImportantPeopleNotification() =
- peopleNotificationIdentifier.isImportantPeopleNotification(sbn, ranking)
+ private fun NotificationEntry.getPeopleNotificationType() =
+ peopleNotificationIdentifier.getPeopleNotificationType(sbn, ranking)
private fun NotificationEntry.isHighPriority() =
highPriorityProvider.isHighPriority(this)
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/provider/HighPriorityProvider.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/provider/HighPriorityProvider.java
index 0d9beaefbf8d..df3609bbc6b6 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/provider/HighPriorityProvider.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/provider/HighPriorityProvider.java
@@ -103,8 +103,8 @@ public class HighPriorityProvider {
}
private boolean isPeopleNotification(NotificationEntry entry) {
- return mPeopleNotificationIdentifier.isPeopleNotification(
- entry.getSbn(), entry.getRanking());
+ return mPeopleNotificationIdentifier.getPeopleNotificationType(
+ entry.getSbn(), entry.getRanking()) != PeopleNotificationIdentifier.TYPE_NON_PERSON;
}
private boolean hasUserSetImportance(NotificationEntry entry) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/dagger/NotificationsModule.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/dagger/NotificationsModule.java
index d0b553db2100..e425ee951ba9 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/dagger/NotificationsModule.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/dagger/NotificationsModule.java
@@ -21,6 +21,8 @@ import android.os.Handler;
import android.view.accessibility.AccessibilityManager;
import com.android.internal.logging.MetricsLogger;
+import com.android.internal.logging.UiEventLogger;
+import com.android.internal.logging.UiEventLoggerImpl;
import com.android.systemui.R;
import com.android.systemui.dagger.qualifiers.Main;
import com.android.systemui.dagger.qualifiers.UiBackground;
@@ -43,6 +45,8 @@ import com.android.systemui.statusbar.notification.init.NotificationsController;
import com.android.systemui.statusbar.notification.init.NotificationsControllerImpl;
import com.android.systemui.statusbar.notification.init.NotificationsControllerStub;
import com.android.systemui.statusbar.notification.logging.NotificationLogger;
+import com.android.systemui.statusbar.notification.logging.NotificationPanelLogger;
+import com.android.systemui.statusbar.notification.logging.NotificationPanelLoggerImpl;
import com.android.systemui.statusbar.notification.row.NotificationBlockingHelperManager;
import com.android.systemui.statusbar.notification.row.NotificationGutsManager;
import com.android.systemui.statusbar.phone.NotificationGroupManager;
@@ -144,13 +148,29 @@ public interface NotificationsModule {
@UiBackground Executor uiBgExecutor,
NotificationEntryManager entryManager,
StatusBarStateController statusBarStateController,
- NotificationLogger.ExpansionStateLogger expansionStateLogger) {
+ NotificationLogger.ExpansionStateLogger expansionStateLogger,
+ NotificationPanelLogger notificationPanelLogger) {
return new NotificationLogger(
notificationListener,
uiBgExecutor,
entryManager,
statusBarStateController,
- expansionStateLogger);
+ expansionStateLogger,
+ notificationPanelLogger);
+ }
+
+ /** Provides an instance of {@link NotificationPanelLogger} */
+ @Singleton
+ @Provides
+ static NotificationPanelLogger provideNotificationPanelLogger() {
+ return new NotificationPanelLoggerImpl();
+ }
+
+ /** Provides an instance of {@link com.android.internal.logging.UiEventLogger} */
+ @Singleton
+ @Provides
+ static UiEventLogger provideUiEventLogger() {
+ return new UiEventLoggerImpl();
}
/** Provides an instance of {@link NotificationBlockingHelperManager} */
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/logging/NotificationLogger.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/logging/NotificationLogger.java
index 6e161c9686dd..ad047889f29f 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/logging/NotificationLogger.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/logging/NotificationLogger.java
@@ -70,6 +70,7 @@ public class NotificationLogger implements StateListener {
private final NotificationListenerService mNotificationListener;
private final Executor mUiBgExecutor;
private final NotificationEntryManager mEntryManager;
+ private final NotificationPanelLogger mNotificationPanelLogger;
private HeadsUpManager mHeadsUpManager;
private final ExpansionStateLogger mExpansionStateLogger;
@@ -198,13 +199,15 @@ public class NotificationLogger implements StateListener {
@UiBackground Executor uiBgExecutor,
NotificationEntryManager entryManager,
StatusBarStateController statusBarStateController,
- ExpansionStateLogger expansionStateLogger) {
+ ExpansionStateLogger expansionStateLogger,
+ NotificationPanelLogger notificationPanelLogger) {
mNotificationListener = notificationListener;
mUiBgExecutor = uiBgExecutor;
mEntryManager = entryManager;
mBarService = IStatusBarService.Stub.asInterface(
ServiceManager.getService(Context.STATUS_BAR_SERVICE));
mExpansionStateLogger = expansionStateLogger;
+ mNotificationPanelLogger = notificationPanelLogger;
// Not expected to be destroyed, don't need to unsubscribe
statusBarStateController.addCallback(this);
@@ -264,6 +267,8 @@ public class NotificationLogger implements StateListener {
// (Note that in cases where the scroller does emit events, this
// additional event doesn't break anything.)
mNotificationLocationsChangedListener.onChildLocationsChanged();
+ mNotificationPanelLogger.logPanelShown(mListContainer.hasPulsingNotifications(),
+ mEntryManager.getVisibleNotifications());
}
private void setDozing(boolean dozing) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/logging/NotificationPanelLogger.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/logging/NotificationPanelLogger.java
new file mode 100644
index 000000000000..9a25c480dfe8
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/logging/NotificationPanelLogger.java
@@ -0,0 +1,95 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.statusbar.notification.logging;
+
+import android.annotation.Nullable;
+import android.service.notification.StatusBarNotification;
+
+import com.android.internal.logging.UiEvent;
+import com.android.internal.logging.UiEventLogger;
+import com.android.systemui.statusbar.notification.collection.NotificationEntry;
+import com.android.systemui.statusbar.notification.logging.nano.Notifications;
+
+import java.util.List;
+/**
+ * Statsd logging for notification panel.
+ */
+public interface NotificationPanelLogger {
+
+ /**
+ * Log a NOTIFICATION_PANEL_REPORTED statsd event.
+ * @param visibleNotifications as provided by NotificationEntryManager.getVisibleNotifications()
+ */
+ void logPanelShown(boolean isLockscreen,
+ @Nullable List<NotificationEntry> visibleNotifications);
+
+ enum NotificationPanelEvent implements UiEventLogger.UiEventEnum {
+ @UiEvent(doc = "Notification panel shown from status bar.")
+ NOTIFICATION_PANEL_OPEN_STATUS_BAR(200),
+ @UiEvent(doc = "Notification panel shown from lockscreen.")
+ NOTIFICATION_PANEL_OPEN_LOCKSCREEN(201);
+
+ private final int mId;
+ NotificationPanelEvent(int id) {
+ mId = id;
+ }
+ @Override public int getId() {
+ return mId;
+ }
+
+ public static NotificationPanelEvent fromLockscreen(boolean isLockscreen) {
+ return isLockscreen ? NOTIFICATION_PANEL_OPEN_LOCKSCREEN :
+ NOTIFICATION_PANEL_OPEN_STATUS_BAR;
+ }
+ }
+
+ /**
+ * Composes a NotificationsList proto from the list of visible notifications.
+ * @param visibleNotifications as provided by NotificationEntryManager.getVisibleNotifications()
+ * @return NotificationList proto suitable for SysUiStatsLog.write(NOTIFICATION_PANEL_REPORTED)
+ */
+ static Notifications.NotificationList toNotificationProto(
+ @Nullable List<NotificationEntry> visibleNotifications) {
+ Notifications.NotificationList notificationList = new Notifications.NotificationList();
+ if (visibleNotifications == null) {
+ return notificationList;
+ }
+ final Notifications.Notification[] proto_array =
+ new Notifications.Notification[visibleNotifications.size()];
+ int i = 0;
+ for (NotificationEntry ne : visibleNotifications) {
+ final StatusBarNotification n = ne.getSbn();
+ if (n != null) {
+ final Notifications.Notification proto = new Notifications.Notification();
+ proto.uid = n.getUid();
+ proto.packageName = n.getPackageName();
+ if (n.getInstanceId() != null) {
+ proto.instanceId = n.getInstanceId().getId();
+ }
+ // TODO set np.groupInstanceId
+ if (n.getNotification() != null) {
+ proto.isGroupSummary = n.getNotification().isGroupSummary();
+ }
+ proto.section = 1 + ne.getBucket(); // We want 0 to mean not set / unknown
+ proto_array[i] = proto;
+ }
+ ++i;
+ }
+ notificationList.notifications = proto_array;
+ return notificationList;
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/logging/NotificationPanelLoggerImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/logging/NotificationPanelLoggerImpl.java
new file mode 100644
index 000000000000..75a60194f2fa
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/logging/NotificationPanelLoggerImpl.java
@@ -0,0 +1,41 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.statusbar.notification.logging;
+
+import com.android.systemui.shared.system.SysUiStatsLog;
+import com.android.systemui.statusbar.notification.collection.NotificationEntry;
+import com.android.systemui.statusbar.notification.logging.nano.Notifications;
+
+import com.google.protobuf.nano.MessageNano;
+
+import java.util.List;
+
+/**
+ * Normal implementation of NotificationPanelLogger.
+ */
+public class NotificationPanelLoggerImpl implements NotificationPanelLogger {
+ @Override
+ public void logPanelShown(boolean isLockscreen,
+ List<NotificationEntry> visibleNotifications) {
+ final Notifications.NotificationList proto = NotificationPanelLogger.toNotificationProto(
+ visibleNotifications);
+ SysUiStatsLog.write(SysUiStatsLog.NOTIFICATION_PANEL_REPORTED,
+ /* int event_id */ NotificationPanelEvent.fromLockscreen(isLockscreen).getId(),
+ /* int num_notifications*/ proto.notifications.length,
+ /* byte[] notifications*/ MessageNano.toByteArray(proto));
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/logging/Notifications.proto b/packages/SystemUI/src/com/android/systemui/statusbar/notification/logging/Notifications.proto
new file mode 100644
index 000000000000..552a5fb40a1c
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/logging/Notifications.proto
@@ -0,0 +1,49 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.statusbar.notification.logging;
+
+/**
+ * NotificationList proto from atoms.proto, duplicated here so that it's accessible in the build.
+ * Must be kept in sync with the version in atoms.proto.
+ */
+
+message Notification {
+ // The notifying app's uid and package.
+ optional int32 uid = 1;
+ optional string package_name = 2;
+ // A small system-assigned identifier for the notification.
+ optional int32 instance_id = 3;
+
+ // Grouping information.
+ optional int32 group_instance_id = 4;
+ optional bool is_group_summary = 5;
+
+ // The section of the shade that the notification is in.
+ // See NotificationSectionsManager.PriorityBucket.
+ enum NotificationSection {
+ SECTION_UNKNOWN = 0;
+ SECTION_HEADS_UP = 1;
+ SECTION_PEOPLE = 2;
+ SECTION_ALERTING = 3;
+ SECTION_SILENT = 4;
+ }
+ optional NotificationSection section = 6;
+}
+
+message NotificationList {
+ repeated Notification notifications = 1; // An ordered sequence of notifications.
+} \ No newline at end of file
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/people/PeopleHub.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/people/PeopleHub.kt
index 3007198ff756..3af6ba8434a5 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/people/PeopleHub.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/people/PeopleHub.kt
@@ -16,7 +16,6 @@
package com.android.systemui.statusbar.notification.people
-import android.app.PendingIntent
import android.graphics.drawable.Drawable
/**
@@ -45,10 +44,11 @@ data class PeopleHubModel(val people: Collection<PersonModel>)
/** `Model` for a single "Person" in PeopleHub. */
data class PersonModel(
val key: PersonKey,
+ val userId: Int,
+ // TODO: these should live in the ViewModel
val name: CharSequence,
val avatar: Drawable,
- val clickRunnable: Runnable,
- val userId: Int
+ val clickRunnable: Runnable
)
/** Unique identifier for a Person in PeopleHub. */
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/people/PeopleHubNotificationListener.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/people/PeopleHubNotificationListener.kt
index 360bf96a3cce..2fbd3ee0094a 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/people/PeopleHubNotificationListener.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/people/PeopleHubNotificationListener.kt
@@ -20,9 +20,7 @@ import android.app.Notification
import android.content.Context
import android.content.pm.LauncherApps
import android.content.pm.PackageManager
-import android.content.pm.ShortcutInfo
import android.content.pm.UserInfo
-import android.graphics.drawable.BitmapDrawable
import android.graphics.drawable.Drawable
import android.os.UserManager
import android.service.notification.NotificationListenerService
@@ -45,6 +43,7 @@ import com.android.systemui.statusbar.NotificationLockscreenUserManager
import com.android.systemui.statusbar.notification.NotificationEntryListener
import com.android.systemui.statusbar.notification.NotificationEntryManager
import com.android.systemui.statusbar.notification.collection.NotificationEntry
+import com.android.systemui.statusbar.notification.people.PeopleNotificationIdentifier.Companion.TYPE_NON_PERSON
import com.android.systemui.statusbar.policy.ExtensionController
import java.util.ArrayDeque
import java.util.concurrent.Executor
@@ -79,7 +78,7 @@ class NotificationPersonExtractorPluginBoundary @Inject constructor(
override fun extractPerson(sbn: StatusBarNotification) =
plugin?.extractPerson(sbn)?.run {
- PersonModel(key, name, avatar, clickRunnable, sbn.user.identifier)
+ PersonModel(key, sbn.user.identifier, name, avatar, clickRunnable)
}
override fun extractPersonKey(sbn: StatusBarNotification) = plugin?.extractPersonKey(sbn)
@@ -90,26 +89,35 @@ class NotificationPersonExtractorPluginBoundary @Inject constructor(
@Singleton
class PeopleHubDataSourceImpl @Inject constructor(
- private val notificationEntryManager: NotificationEntryManager,
- private val extractor: NotificationPersonExtractor,
- private val userManager: UserManager,
- private val launcherApps: LauncherApps,
- private val packageManager: PackageManager,
- private val c: Context,
- private val notificationListener: NotificationListener,
- @Background private val bgExecutor: Executor,
- @Main private val mainExecutor: Executor,
- private val notifLockscreenUserMgr: NotificationLockscreenUserManager,
- private val peopleNotificationIdentifier: PeopleNotificationIdentifier
- ) : DataSource<PeopleHubModel> {
+ private val notificationEntryManager: NotificationEntryManager,
+ private val extractor: NotificationPersonExtractor,
+ private val userManager: UserManager,
+ launcherApps: LauncherApps,
+ packageManager: PackageManager,
+ context: Context,
+ private val notificationListener: NotificationListener,
+ @Background private val bgExecutor: Executor,
+ @Main private val mainExecutor: Executor,
+ private val notifLockscreenUserMgr: NotificationLockscreenUserManager,
+ private val peopleNotificationIdentifier: PeopleNotificationIdentifier
+) : DataSource<PeopleHubModel> {
private var userChangeSubscription: Subscription? = null
private val dataListeners = mutableListOf<DataListener<PeopleHubModel>>()
private val peopleHubManagerForUser = SparseArray<PeopleHubManager>()
- val context: Context = c.applicationContext
- val iconFactory = ConversationIconFactory(context, launcherApps, packageManager,
- IconDrawableFactory.newInstance(context), context.resources.getDimensionPixelSize(
- R.dimen.notification_guts_conversation_icon_size))
+
+ private val iconFactory = run {
+ val appContext = context.applicationContext
+ ConversationIconFactory(
+ appContext,
+ launcherApps,
+ packageManager,
+ IconDrawableFactory.newInstance(appContext),
+ appContext.resources.getDimensionPixelSize(
+ R.dimen.notification_guts_conversation_icon_size
+ )
+ )
+ }
private val notificationEntryListener = object : NotificationEntryListener {
override fun onEntryInflated(entry: NotificationEntry) = addVisibleEntry(entry)
@@ -206,7 +214,8 @@ class PeopleHubDataSourceImpl @Inject constructor(
}
private fun NotificationEntry.extractPerson(): PersonModel? {
- if (!peopleNotificationIdentifier.isPeopleNotification(sbn, ranking)) {
+ val type = peopleNotificationIdentifier.getPeopleNotificationType(sbn, ranking)
+ if (type == TYPE_NON_PERSON) {
return null
}
val clickRunnable = Runnable { notificationListener.unsnoozeNotification(key) }
@@ -215,23 +224,34 @@ class PeopleHubDataSourceImpl @Inject constructor(
?: extras.getString(Notification.EXTRA_CONVERSATION_TITLE)
?: extras.getString(Notification.EXTRA_TITLE)
?: return null
- val drawable = ranking.shortcutInfo?.getIcon(iconFactory, sbn, ranking)
- ?: iconFactory.getConversationDrawable(extractAvatarFromRow(this), sbn.packageName,
- sbn.uid, ranking.channel.isImportantConversation)
-
- return PersonModel(key, name, drawable, clickRunnable, sbn.user.identifier)
+ val drawable = ranking.getIcon(iconFactory, sbn)
+ ?: iconFactory.getConversationDrawable(
+ extractAvatarFromRow(this),
+ sbn.packageName,
+ sbn.uid,
+ ranking.channel.isImportantConversation
+ )
+ return PersonModel(key, sbn.user.identifier, name, drawable, clickRunnable)
}
- private fun ShortcutInfo.getIcon(iconFactory: ConversationIconFactory,
- sbn: StatusBarNotification,
- ranking: NotificationListenerService.Ranking): Drawable? {
- return iconFactory.getConversationDrawable(ranking.shortcutInfo, sbn.packageName, sbn.uid,
- ranking.channel.isImportantConversation)
- }
+ private fun NotificationListenerService.Ranking.getIcon(
+ iconFactory: ConversationIconFactory,
+ sbn: StatusBarNotification
+ ): Drawable? =
+ shortcutInfo?.let { shortcutInfo ->
+ iconFactory.getConversationDrawable(
+ shortcutInfo,
+ sbn.packageName,
+ sbn.uid,
+ channel.isImportantConversation
+ )
+ }
- private fun NotificationEntry.extractPersonKey(): PersonKey? =
- // TODO migrate to shortcut id when snoozing is conversation wide
- if (peopleNotificationIdentifier.isPeopleNotification(sbn, ranking)) key else null
+ private fun NotificationEntry.extractPersonKey(): PersonKey? {
+ // TODO migrate to shortcut id when snoozing is conversation wide
+ val type = peopleNotificationIdentifier.getPeopleNotificationType(sbn, ranking)
+ return if (type != TYPE_NON_PERSON) key else null
+ }
}
private fun NotificationLockscreenUserManager.registerListener(
@@ -303,4 +323,3 @@ fun extractAvatarFromRow(entry: NotificationEntry): Drawable? =
?.drawable
}
?.firstOrNull()
-
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/people/PeopleHubViewController.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/people/PeopleHubViewController.kt
index 62d3612a483b..7f42fe0473f3 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/people/PeopleHubViewController.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/people/PeopleHubViewController.kt
@@ -164,8 +164,8 @@ class PeopleHubSettingChangeDataSourceImpl @Inject constructor(
// Immediately report current value of setting
updateListener(listener)
val observer = object : ContentObserver(handler) {
- override fun onChange(selfChange: Boolean, uri: Uri?, userId: Int) {
- super.onChange(selfChange, uri, userId)
+ override fun onChange(selfChange: Boolean, uri: Uri?, flags: Int) {
+ super.onChange(selfChange, uri, flags)
updateListener(listener)
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/people/PeopleNotificationIdentifier.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/people/PeopleNotificationIdentifier.kt
index e15fa2eac4fd..597bdb9f2e74 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/people/PeopleNotificationIdentifier.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/people/PeopleNotificationIdentifier.kt
@@ -16,24 +16,97 @@
package com.android.systemui.statusbar.notification.people
+import android.annotation.IntDef
import android.service.notification.NotificationListenerService.Ranking
import android.service.notification.StatusBarNotification
+import com.android.systemui.statusbar.notification.people.PeopleNotificationIdentifier.Companion.PeopleNotificationType
+import com.android.systemui.statusbar.notification.people.PeopleNotificationIdentifier.Companion.TYPE_IMPORTANT_PERSON
+import com.android.systemui.statusbar.notification.people.PeopleNotificationIdentifier.Companion.TYPE_NON_PERSON
+import com.android.systemui.statusbar.notification.people.PeopleNotificationIdentifier.Companion.TYPE_PERSON
+import com.android.systemui.statusbar.phone.NotificationGroupManager
import javax.inject.Inject
import javax.inject.Singleton
+import kotlin.math.max
interface PeopleNotificationIdentifier {
- fun isPeopleNotification(sbn: StatusBarNotification, ranking: Ranking): Boolean
- fun isImportantPeopleNotification(sbn: StatusBarNotification, ranking: Ranking): Boolean
+
+ /**
+ * Identifies if the given notification can be classified as a "People" notification.
+ *
+ * @return [TYPE_NON_PERSON] if not a people notification, [TYPE_PERSON] if a standard people
+ * notification, and [TYPE_IMPORTANT_PERSON] if an "important" people notification.
+ */
+ @PeopleNotificationType
+ fun getPeopleNotificationType(sbn: StatusBarNotification, ranking: Ranking): Int
+
+ companion object {
+
+ @Retention(AnnotationRetention.SOURCE)
+ @IntDef(prefix = ["TYPE_"], value = [TYPE_NON_PERSON, TYPE_PERSON, TYPE_IMPORTANT_PERSON])
+ annotation class PeopleNotificationType
+
+ const val TYPE_NON_PERSON = 0
+ const val TYPE_PERSON = 1
+ const val TYPE_IMPORTANT_PERSON = 2
+ }
}
@Singleton
class PeopleNotificationIdentifierImpl @Inject constructor(
- private val personExtractor: NotificationPersonExtractor
+ private val personExtractor: NotificationPersonExtractor,
+ private val groupManager: NotificationGroupManager
) : PeopleNotificationIdentifier {
- override fun isPeopleNotification(sbn: StatusBarNotification, ranking: Ranking) =
- ranking.isConversation || personExtractor.isPersonNotification(sbn)
+ @PeopleNotificationType
+ override fun getPeopleNotificationType(sbn: StatusBarNotification, ranking: Ranking): Int =
+ when (val type = ranking.personTypeInfo) {
+ TYPE_IMPORTANT_PERSON -> TYPE_IMPORTANT_PERSON
+ else -> {
+ when (val type = upperBound(type, extractPersonTypeInfo(sbn))) {
+ TYPE_IMPORTANT_PERSON -> TYPE_IMPORTANT_PERSON
+ else -> upperBound(type, getPeopleTypeOfSummary(sbn))
+ }
+ }
+ }
+
+ /**
+ * Given two [PeopleNotificationType]s, determine the upper bound. Used to constrain a
+ * notification to a type given multiple signals, i.e. notification groups, where each child
+ * has a [PeopleNotificationType] that is used to constrain the summary.
+ */
+ @PeopleNotificationType
+ private fun upperBound(
+ @PeopleNotificationType type: Int,
+ @PeopleNotificationType other: Int
+ ): Int =
+ max(type, other)
- override fun isImportantPeopleNotification(sbn: StatusBarNotification, ranking: Ranking) =
- isPeopleNotification(sbn, ranking) && ranking.channel.isImportantConversation
-} \ No newline at end of file
+ private val Ranking.personTypeInfo
+ get() = when {
+ channel.isImportantConversation -> TYPE_IMPORTANT_PERSON
+ isConversation -> TYPE_PERSON
+ else -> TYPE_NON_PERSON
+ }
+
+ private fun extractPersonTypeInfo(sbn: StatusBarNotification) =
+ if (personExtractor.isPersonNotification(sbn)) TYPE_PERSON else TYPE_NON_PERSON
+
+ private fun getPeopleTypeOfSummary(statusBarNotification: StatusBarNotification): Int {
+ if (!groupManager.isSummaryOfGroup(statusBarNotification)) {
+ return TYPE_NON_PERSON
+ }
+
+ val childTypes = groupManager.getLogicalChildren(statusBarNotification)
+ ?.asSequence()
+ ?.map { getPeopleNotificationType(it.sbn, it.ranking) }
+ ?: return TYPE_NON_PERSON
+
+ var groupType = TYPE_NON_PERSON
+ for (childType in childTypes) {
+ groupType = upperBound(groupType, childType)
+ if (groupType == TYPE_IMPORTANT_PERSON)
+ break
+ }
+ return groupType
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationGutsManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationGutsManager.java
index d746822ddcff..bd4984e8d24e 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationGutsManager.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationGutsManager.java
@@ -315,7 +315,6 @@ public class NotificationGutsManager implements Dumpable, NotificationLifetimeEx
mNotificationActivityStarter.startNotificationGutsIntent(intent, sbn.getUid(),
row);
};
- boolean isForBlockingHelper = row.isBlockingHelperShowing();
if (!userHandle.equals(UserHandle.ALL)
|| mLockscreenUserManager.getCurrentUserId() == UserHandle.USER_SYSTEM) {
@@ -335,13 +334,10 @@ public class NotificationGutsManager implements Dumpable, NotificationLifetimeEx
row.getEntry().getChannel(),
row.getUniqueChannels(),
row.getEntry(),
- mCheckSaveListener,
onSettingsClick,
onAppSettingsClick,
mDeviceProvisionedController.isDeviceProvisioned(),
row.getIsNonblockable(),
- isForBlockingHelper,
- row.getEntry().getImportance(),
mHighPriorityProvider.isHighPriority(row.getEntry()));
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationInfo.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationInfo.java
index 6b4511d31669..12aa4dfaf6fa 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationInfo.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationInfo.java
@@ -24,10 +24,6 @@ import static com.android.systemui.Interpolators.FAST_OUT_SLOW_IN;
import static java.lang.annotation.RetentionPolicy.SOURCE;
-import android.animation.Animator;
-import android.animation.AnimatorListenerAdapter;
-import android.animation.AnimatorSet;
-import android.animation.ObjectAnimator;
import android.annotation.IntDef;
import android.annotation.Nullable;
import android.app.INotificationManager;
@@ -53,7 +49,6 @@ import android.transition.TransitionSet;
import android.util.AttributeSet;
import android.util.Log;
import android.view.View;
-import android.view.ViewGroup;
import android.view.accessibility.AccessibilityEvent;
import android.widget.ImageView;
import android.widget.LinearLayout;
@@ -63,42 +58,33 @@ import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.logging.MetricsLogger;
import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
import com.android.systemui.Dependency;
-import com.android.systemui.Interpolators;
import com.android.systemui.R;
import com.android.systemui.statusbar.notification.VisualStabilityManager;
import com.android.systemui.statusbar.notification.collection.NotificationEntry;
-import com.android.systemui.statusbar.notification.logging.NotificationCounters;
import java.lang.annotation.Retention;
import java.util.List;
import java.util.Set;
/**
- * The guts of a notification revealed when performing a long press. This also houses the blocking
- * helper affordance that allows a user to keep/stop notifications after swiping one away.
+ * The guts of a notification revealed when performing a long press.
*/
public class NotificationInfo extends LinearLayout implements NotificationGuts.GutsContent {
private static final String TAG = "InfoGuts";
@IntDef(prefix = { "ACTION_" }, value = {
ACTION_NONE,
- ACTION_UNDO,
+ ACTION_TOGGLE_ALERT,
ACTION_TOGGLE_SILENT,
- ACTION_BLOCK,
})
public @interface NotificationInfoAction {
}
public static final int ACTION_NONE = 0;
- static final int ACTION_UNDO = 1;
// standard controls
static final int ACTION_TOGGLE_SILENT = 2;
- // unused
- static final int ACTION_BLOCK = 3;
- // blocking helper
- static final int ACTION_DELIVER_SILENTLY = 4;
// standard controls
- private static final int ACTION_ALERT = 5;
+ private static final int ACTION_TOGGLE_ALERT = 5;
private TextView mPriorityDescriptionView;
private TextView mSilentDescriptionView;
@@ -128,101 +114,35 @@ public class NotificationInfo extends LinearLayout implements NotificationGuts.G
@Nullable private Integer mChosenImportance;
private boolean mIsSingleDefaultChannel;
private boolean mIsNonblockable;
- private NotificationEntry mEntry;
private StatusBarNotification mSbn;
- private AnimatorSet mExpandAnimation;
private boolean mIsDeviceProvisioned;
- private CheckSaveListener mCheckSaveListener;
private OnSettingsClickListener mOnSettingsClickListener;
private OnAppSettingsClickListener mAppSettingsClickListener;
private NotificationGuts mGutsContainer;
private Drawable mPkgIcon;
- /** Whether this view is being shown as part of the blocking helper. */
- private boolean mIsForBlockingHelper;
-
@VisibleForTesting
boolean mSkipPost = false;
- /**
- * String that describes how the user exit or quit out of this view, also used as a counter tag.
- */
- private String mExitReason = NotificationCounters.BLOCKING_HELPER_DISMISSED;
-
-
// used by standard ui
private OnClickListener mOnAlert = v -> {
- mExitReason = NotificationCounters.BLOCKING_HELPER_KEEP_SHOWING;
mChosenImportance = IMPORTANCE_DEFAULT;
applyAlertingBehavior(BEHAVIOR_ALERTING, true /* userTriggered */);
};
// used by standard ui
private OnClickListener mOnSilent = v -> {
- mExitReason = NotificationCounters.BLOCKING_HELPER_DELIVER_SILENTLY;
mChosenImportance = IMPORTANCE_LOW;
applyAlertingBehavior(BEHAVIOR_SILENT, true /* userTriggered */);
};
-
// used by standard ui
private OnClickListener mOnDismissSettings = v -> {
mPressedApply = true;
closeControls(v, true);
};
- // used by blocking helper
- private OnClickListener mOnKeepShowing = v -> {
- mExitReason = NotificationCounters.BLOCKING_HELPER_KEEP_SHOWING;
- closeControls(v, true);
- mMetricsLogger.write(getLogMaker().setCategory(
- MetricsEvent.NOTIFICATION_BLOCKING_HELPER)
- .setType(MetricsEvent.TYPE_ACTION)
- .setSubtype(MetricsEvent.BLOCKING_HELPER_CLICK_STAY_SILENT));
- };
-
- // used by blocking helper
- private OnClickListener mOnDeliverSilently = v -> {
- handleSaveImportance(
- ACTION_DELIVER_SILENTLY, MetricsEvent.BLOCKING_HELPER_CLICK_STAY_SILENT);
- };
-
- private void handleSaveImportance(int action, int metricsSubtype) {
- Runnable saveImportance = () -> {
- saveImportanceAndExitReason(action);
- if (mIsForBlockingHelper) {
- swapContent(action, true /* animate */);
- mMetricsLogger.write(getLogMaker()
- .setCategory(MetricsEvent.NOTIFICATION_BLOCKING_HELPER)
- .setType(MetricsEvent.TYPE_ACTION)
- .setSubtype(metricsSubtype));
- }
- };
- if (mCheckSaveListener != null) {
- mCheckSaveListener.checkSave(saveImportance, mSbn);
- } else {
- saveImportance.run();
- }
- }
-
- private OnClickListener mOnUndo = v -> {
- // Reset exit counter that we'll log and record an undo event separately (not an exit event)
- mExitReason = NotificationCounters.BLOCKING_HELPER_DISMISSED;
- if (mIsForBlockingHelper) {
- logBlockingHelperCounter(NotificationCounters.BLOCKING_HELPER_UNDO);
- mMetricsLogger.write(getLogMaker().setCategory(
- MetricsEvent.NOTIFICATION_BLOCKING_HELPER)
- .setType(MetricsEvent.TYPE_DISMISS)
- .setSubtype(MetricsEvent.BLOCKING_HELPER_CLICK_UNDO));
- } else {
- // TODO: this can't happen?
- mMetricsLogger.write(importanceChangeLogMaker().setType(MetricsEvent.TYPE_DISMISS));
- }
- saveImportanceAndExitReason(ACTION_UNDO);
- swapContent(ACTION_UNDO, true /* animate */);
- };
-
public NotificationInfo(Context context, AttributeSet attrs) {
super(context, attrs);
}
@@ -250,30 +170,6 @@ public class NotificationInfo extends LinearLayout implements NotificationGuts.G
void onClick(View v, Intent intent);
}
- @VisibleForTesting
- void bindNotification(
- final PackageManager pm,
- final INotificationManager iNotificationManager,
- final VisualStabilityManager visualStabilityManager,
- final String pkg,
- final NotificationChannel notificationChannel,
- final Set<NotificationChannel> uniqueChannelsInRow,
- final NotificationEntry entry,
- final CheckSaveListener checkSaveListener,
- final OnSettingsClickListener onSettingsClick,
- final OnAppSettingsClickListener onAppSettingsClick,
- boolean isDeviceProvisioned,
- boolean isNonblockable,
- int importance,
- boolean wasShownHighPriority)
- throws RemoteException {
- bindNotification(pm, iNotificationManager, visualStabilityManager, pkg, notificationChannel,
- uniqueChannelsInRow, entry, checkSaveListener, onSettingsClick,
- onAppSettingsClick, isDeviceProvisioned, isNonblockable,
- false /* isBlockingHelper */,
- importance, wasShownHighPriority);
- }
-
public void bindNotification(
PackageManager pm,
INotificationManager iNotificationManager,
@@ -282,13 +178,10 @@ public class NotificationInfo extends LinearLayout implements NotificationGuts.G
NotificationChannel notificationChannel,
Set<NotificationChannel> uniqueChannelsInRow,
NotificationEntry entry,
- CheckSaveListener checkSaveListener,
OnSettingsClickListener onSettingsClick,
OnAppSettingsClickListener onAppSettingsClick,
boolean isDeviceProvisioned,
boolean isNonblockable,
- boolean isForBlockingHelper,
- int importance,
boolean wasShownHighPriority)
throws RemoteException {
mINotificationManager = iNotificationManager;
@@ -298,18 +191,15 @@ public class NotificationInfo extends LinearLayout implements NotificationGuts.G
mPackageName = pkg;
mUniqueChannelsInRow = uniqueChannelsInRow;
mNumUniqueChannelsInRow = uniqueChannelsInRow.size();
- mEntry = entry;
mSbn = entry.getSbn();
mPm = pm;
mAppSettingsClickListener = onAppSettingsClick;
mAppName = mPackageName;
- mCheckSaveListener = checkSaveListener;
mOnSettingsClickListener = onSettingsClick;
mSingleNotificationChannel = notificationChannel;
mStartingChannelImportance = mSingleNotificationChannel.getImportance();
mWasShownHighPriority = wasShownHighPriority;
mIsNonblockable = isNonblockable;
- mIsForBlockingHelper = isForBlockingHelper;
mAppUid = mSbn.getUid();
mDelegatePkg = mSbn.getOpPkg();
mIsDeviceProvisioned = isDeviceProvisioned;
@@ -329,36 +219,12 @@ public class NotificationInfo extends LinearLayout implements NotificationGuts.G
bindHeader();
bindChannelDetails();
- if (mIsForBlockingHelper) {
- bindBlockingHelper();
- } else {
- bindInlineControls();
- }
+ bindInlineControls();
mMetricsLogger.write(notificationControlsLogMaker());
}
- private void bindBlockingHelper() {
- findViewById(R.id.inline_controls).setVisibility(GONE);
- findViewById(R.id.blocking_helper).setVisibility(VISIBLE);
-
- findViewById(R.id.undo).setOnClickListener(mOnUndo);
-
- View turnOffButton = findViewById(R.id.blocking_helper_turn_off_notifications);
- turnOffButton.setOnClickListener(getSettingsOnClickListener());
- turnOffButton.setVisibility(turnOffButton.hasOnClickListeners() ? VISIBLE : GONE);
-
- TextView keepShowing = findViewById(R.id.keep_showing);
- keepShowing.setOnClickListener(mOnKeepShowing);
-
- View deliverSilently = findViewById(R.id.deliver_silently);
- deliverSilently.setOnClickListener(mOnDeliverSilently);
- }
-
private void bindInlineControls() {
- findViewById(R.id.inline_controls).setVisibility(VISIBLE);
- findViewById(R.id.blocking_helper).setVisibility(GONE);
-
if (mIsNonblockable) {
findViewById(R.id.non_configurable_text).setVisibility(VISIBLE);
findViewById(R.id.non_configurable_multichannel_text).setVisibility(GONE);
@@ -414,8 +280,8 @@ public class NotificationInfo extends LinearLayout implements NotificationGuts.G
// app is gone, just show package name and generic icon
mPkgIcon = mPm.getDefaultActivityIcon();
}
- ((ImageView) findViewById(R.id.pkgicon)).setImageDrawable(mPkgIcon);
- ((TextView) findViewById(R.id.pkgname)).setText(mAppName);
+ ((ImageView) findViewById(R.id.pkg_icon)).setImageDrawable(mPkgIcon);
+ ((TextView) findViewById(R.id.pkg_name)).setText(mAppName);
// Delegate
bindDelegate();
@@ -445,8 +311,6 @@ public class NotificationInfo extends LinearLayout implements NotificationGuts.G
if (mAppUid >= 0 && mOnSettingsClickListener != null && mIsDeviceProvisioned) {
final int appUidF = mAppUid;
return ((View view) -> {
- logBlockingHelperCounter(
- NotificationCounters.BLOCKING_HELPER_NOTIF_SETTINGS);
mOnSettingsClickListener.onClick(view,
mNumUniqueChannelsInRow > 1 ? null : mSingleNotificationChannel,
appUidF);
@@ -487,16 +351,13 @@ public class NotificationInfo extends LinearLayout implements NotificationGuts.G
private void bindDelegate() {
TextView delegateView = findViewById(R.id.delegate_name);
- TextView dividerView = findViewById(R.id.pkg_divider);
CharSequence delegatePkg = null;
if (!TextUtils.equals(mPackageName, mDelegatePkg)) {
// this notification was posted by a delegate!
delegateView.setVisibility(View.VISIBLE);
- dividerView.setVisibility(View.VISIBLE);
} else {
delegateView.setVisibility(View.GONE);
- dividerView.setVisibility(View.GONE);
}
}
@@ -512,25 +373,19 @@ public class NotificationInfo extends LinearLayout implements NotificationGuts.G
}
}
TextView groupNameView = findViewById(R.id.group_name);
+ View divider = findViewById(R.id.group_divider);
if (groupName != null) {
groupNameView.setText(groupName);
- groupNameView.setVisibility(View.VISIBLE);
+ groupNameView.setVisibility(VISIBLE);
+ divider.setVisibility(VISIBLE);
} else {
- groupNameView.setVisibility(View.GONE);
- }
- }
-
-
- @VisibleForTesting
- void logBlockingHelperCounter(String counterTag) {
- if (mIsForBlockingHelper) {
- mMetricsLogger.count(counterTag, 1);
+ groupNameView.setVisibility(GONE);
+ divider.setVisibility(GONE);
}
}
private void saveImportance() {
- if (!mIsNonblockable
- || mExitReason != NotificationCounters.BLOCKING_HELPER_STOP_NOTIFICATIONS) {
+ if (!mIsNonblockable) {
if (mChosenImportance == null) {
mChosenImportance = mStartingChannelImportance;
}
@@ -621,99 +476,13 @@ public class NotificationInfo extends LinearLayout implements NotificationGuts.G
: R.string.inline_done_button);
}
- private void saveImportanceAndExitReason(@NotificationInfoAction int action) {
- switch (action) {
- case ACTION_UNDO:
- mChosenImportance = mStartingChannelImportance;
- break;
- case ACTION_DELIVER_SILENTLY:
- mExitReason = NotificationCounters.BLOCKING_HELPER_DELIVER_SILENTLY;
- mChosenImportance = mWasShownHighPriority
- ? IMPORTANCE_LOW : mStartingChannelImportance;
- break;
- default:
- throw new IllegalArgumentException();
- }
- }
-
- // only used for blocking helper
- private void swapContent(@NotificationInfoAction int action, boolean animate) {
- if (mExpandAnimation != null) {
- mExpandAnimation.cancel();
- }
-
- View blockingHelper = findViewById(R.id.blocking_helper);
- ViewGroup confirmation = findViewById(R.id.confirmation);
- TextView confirmationText = findViewById(R.id.confirmation_text);
-
- saveImportanceAndExitReason(action);
-
- switch (action) {
- case ACTION_UNDO:
- break;
- case ACTION_DELIVER_SILENTLY:
- confirmationText.setText(R.string.notification_channel_silenced);
- break;
- default:
- throw new IllegalArgumentException();
- }
-
- boolean isUndo = action == ACTION_UNDO;
-
- blockingHelper.setVisibility(isUndo ? VISIBLE : GONE);
- findViewById(R.id.channel_info).setVisibility(isUndo ? VISIBLE : GONE);
- findViewById(R.id.header).setVisibility(isUndo ? VISIBLE : GONE);
- confirmation.setVisibility(isUndo ? GONE : VISIBLE);
-
- if (animate) {
- ObjectAnimator promptAnim = ObjectAnimator.ofFloat(blockingHelper, View.ALPHA,
- blockingHelper.getAlpha(), isUndo ? 1f : 0f);
- promptAnim.setInterpolator(isUndo ? Interpolators.ALPHA_IN : Interpolators.ALPHA_OUT);
- ObjectAnimator confirmAnim = ObjectAnimator.ofFloat(confirmation, View.ALPHA,
- confirmation.getAlpha(), isUndo ? 0f : 1f);
- confirmAnim.setInterpolator(isUndo ? Interpolators.ALPHA_OUT : Interpolators.ALPHA_IN);
-
- mExpandAnimation = new AnimatorSet();
- mExpandAnimation.playTogether(promptAnim, confirmAnim);
- mExpandAnimation.setDuration(150);
- mExpandAnimation.addListener(new AnimatorListenerAdapter() {
- boolean mCancelled = false;
-
- @Override
- public void onAnimationCancel(Animator animation) {
- mCancelled = true;
- }
-
- @Override
- public void onAnimationEnd(Animator animation) {
- if (!mCancelled) {
- blockingHelper.setVisibility(isUndo ? VISIBLE : GONE);
- confirmation.setVisibility(isUndo ? GONE : VISIBLE);
- }
- }
- });
- mExpandAnimation.start();
- }
-
- // Since we're swapping/update the content, reset the timeout so the UI can't close
- // immediately after the update.
- if (mGutsContainer != null) {
- mGutsContainer.resetFalsingCheck();
- }
- }
-
@Override
public void onFinishedClosing() {
if (mChosenImportance != null) {
mStartingChannelImportance = mChosenImportance;
}
- mExitReason = NotificationCounters.BLOCKING_HELPER_DISMISSED;
- if (mIsForBlockingHelper) {
- bindBlockingHelper();
- } else {
- bindInlineControls();
- }
+ bindInlineControls();
mMetricsLogger.write(notificationControlsLogMaker().setType(MetricsEvent.TYPE_CLOSE));
}
@@ -756,13 +525,10 @@ public class NotificationInfo extends LinearLayout implements NotificationGuts.G
}
/**
- * Closes the controls and commits the updated importance values (indirectly). If this view is
- * being used to show the blocking helper, this will immediately dismiss the blocking helper and
- * commit the updated importance.
+ * Closes the controls and commits the updated importance values (indirectly).
*
* <p><b>Note,</b> this will only get called once the view is dismissing. This means that the
- * user does not have the ability to undo the action anymore. See
- * {@link #swapContent(boolean, boolean)} for where undo is handled.
+ * user does not have the ability to undo the action anymore.
*/
@VisibleForTesting
void closeControls(View v, boolean save) {
@@ -811,7 +577,6 @@ public class NotificationInfo extends LinearLayout implements NotificationGuts.G
if (save) {
saveImportance();
}
- logBlockingHelperCounter(mExitReason);
return false;
}
@@ -822,7 +587,7 @@ public class NotificationInfo extends LinearLayout implements NotificationGuts.G
@VisibleForTesting
public boolean isAnimating() {
- return mExpandAnimation != null && mExpandAnimation.isRunning();
+ return false;
}
/**
@@ -901,8 +666,7 @@ public class NotificationInfo extends LinearLayout implements NotificationGuts.G
private LogMaker notificationControlsLogMaker() {
return getLogMaker().setCategory(MetricsEvent.ACTION_NOTE_CONTROLS)
.setType(MetricsEvent.TYPE_OPEN)
- .setSubtype(mIsForBlockingHelper ? MetricsEvent.BLOCKING_HELPER_DISPLAY
- : MetricsEvent.BLOCKING_HELPER_UNKNOWN);
+ .setSubtype(MetricsEvent.BLOCKING_HELPER_UNKNOWN);
}
@Retention(SOURCE)
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationUndoLayout.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationUndoLayout.java
deleted file mode 100644
index 3ea8195ff917..000000000000
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationUndoLayout.java
+++ /dev/null
@@ -1,139 +0,0 @@
-/*
- * Copyright (C) 2018 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License
- */
-
-package com.android.systemui.statusbar.notification.row;
-
-import android.content.Context;
-import android.util.AttributeSet;
-import android.view.View;
-import android.widget.FrameLayout;
-
-import com.android.systemui.R;
-
-/**
- * Custom view for the NotificationInfo confirmation views so that the confirmation text can
- * occupy the full width of the notification and push the undo button down to the next line if
- * necessary.
- *
- * @see NotificationInfo
- */
-public class NotificationUndoLayout extends FrameLayout {
- /**
- * View for the prompt/confirmation text to tell the user the previous action was successful.
- */
- private View mConfirmationTextView;
- /** Undo button (actionable text) view. */
- private View mUndoView;
-
- /**
- * Whether {@link #mConfirmationTextView} is multiline and will require the full width of the
- * parent (which causes the {@link #mUndoView} to push down).
- */
- private boolean mIsMultiline = false;
- private int mMultilineTopMargin;
-
- public NotificationUndoLayout(Context context) {
- this(context, null);
- }
-
- public NotificationUndoLayout(Context context, AttributeSet attrs) {
- this(context, attrs, 0);
- }
-
- public NotificationUndoLayout(Context context, AttributeSet attrs, int defStyleAttr) {
- super(context, attrs, defStyleAttr);
- }
- @Override
- protected void onFinishInflate() {
- super.onFinishInflate();
-
- mConfirmationTextView = findViewById(R.id.confirmation_text);
- mUndoView = findViewById(R.id.undo);
-
- mMultilineTopMargin = getResources().getDimensionPixelOffset(
- com.android.internal.R.dimen.notification_content_margin_start);
- }
-
- @Override
- protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
- super.onMeasure(widthMeasureSpec, heightMeasureSpec);
-
- LayoutParams confirmationLayoutParams =
- (LayoutParams) mConfirmationTextView.getLayoutParams();
- LayoutParams undoLayoutParams =(LayoutParams) mUndoView.getLayoutParams();
-
- int measuredWidth = getMeasuredWidth();
- // Ignore the left margin on the undo button - no need for additional extra space between
- // the text and the button.
- int requiredWidth = mConfirmationTextView.getMeasuredWidth()
- + confirmationLayoutParams.rightMargin
- + confirmationLayoutParams.leftMargin
- + mUndoView.getMeasuredWidth()
- + undoLayoutParams.rightMargin;
- // If the measured width isn't enough to accommodate both the undo button and the text in
- // the same line, we'll need to adjust the view to be multi-line. Otherwise, we're done.
- if (requiredWidth > measuredWidth) {
- mIsMultiline = true;
-
- // Update height requirement to the text height and the button's height (along with
- // additional spacing for the top of the text).
- int updatedHeight = mMultilineTopMargin
- + mConfirmationTextView.getMeasuredHeight()
- + mUndoView.getMeasuredHeight()
- + undoLayoutParams.topMargin
- + undoLayoutParams.bottomMargin;
-
- setMeasuredDimension(measuredWidth, updatedHeight);
- } else {
- mIsMultiline = false;
- }
- }
-
- @Override
- protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
- // If the text view and undo view don't fit on the same line, we'll need to manually lay
- // out the content.
- if (mIsMultiline) {
- // Re-align parent right/bottom values. Left and top are considered to be 0.
- int parentBottom = getMeasuredHeight();
- int parentRight = getMeasuredWidth();
-
- LayoutParams confirmationLayoutParams =
- (LayoutParams) mConfirmationTextView.getLayoutParams();
- LayoutParams undoLayoutParams = (LayoutParams) mUndoView.getLayoutParams();
-
- // The confirmation text occupies the full width as computed earlier. Both side margins
- // are equivalent, so we only need to grab the left one here.
- mConfirmationTextView.layout(
- confirmationLayoutParams.leftMargin,
- mMultilineTopMargin,
- confirmationLayoutParams.leftMargin + mConfirmationTextView.getMeasuredWidth(),
- mMultilineTopMargin + mConfirmationTextView.getMeasuredHeight());
-
- // The undo button is aligned bottom|end with the parent in the case of multiline text.
- int undoViewLeft = getLayoutDirection() == View.LAYOUT_DIRECTION_RTL
- ? undoLayoutParams.rightMargin
- : parentRight - mUndoView.getMeasuredWidth() - undoLayoutParams.rightMargin;
- mUndoView.layout(
- undoViewLeft,
- parentBottom - mUndoView.getMeasuredHeight() - undoLayoutParams.bottomMargin,
- undoViewLeft + mUndoView.getMeasuredWidth(),
- parentBottom - undoLayoutParams.bottomMargin);
- } else {
- super.onLayout(changed, left, top, right, bottom);
- }
- }
-}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationSectionsManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationSectionsManager.java
index 8ee2f5002f0d..42a7c6a07e0f 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationSectionsManager.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationSectionsManager.java
@@ -332,6 +332,10 @@ public class NotificationSectionsManager implements StackScrollAlgorithm.Section
// Put it at the end of the list.
peopleHeaderTarget = lastNotifIndex;
}
+ // Offset the target to account for the current position of the people header.
+ if (currentPeopleHeaderIdx != -1 && currentPeopleHeaderIdx < peopleHeaderTarget) {
+ peopleHeaderTarget--;
+ }
}
// Add headers in reverse order to preserve indices
@@ -459,6 +463,11 @@ public class NotificationSectionsManager implements StackScrollAlgorithm.Section
return mPeopleHubView;
}
+ @VisibleForTesting
+ void setPeopleHubVisible(boolean visible) {
+ mPeopleHubVisible = visible;
+ }
+
private final ConfigurationListener mConfigurationListener = new ConfigurationListener() {
@Override
public void onLocaleListChanged() {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayout.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayout.java
index 1bd9bbecc26e..cfcbd885754d 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayout.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayout.java
@@ -81,6 +81,8 @@ import android.widget.ScrollView;
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.graphics.ColorUtils;
import com.android.internal.logging.MetricsLogger;
+import com.android.internal.logging.UiEvent;
+import com.android.internal.logging.UiEventLogger;
import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
import com.android.internal.statusbar.IStatusBarService;
import com.android.internal.statusbar.NotificationVisibility;
@@ -502,6 +504,7 @@ public class NotificationStackScrollLayout extends ViewGroup implements ScrollAd
ServiceManager.getService(Context.STATUS_BAR_SERVICE));
@VisibleForTesting
protected final MetricsLogger mMetricsLogger = Dependency.get(MetricsLogger.class);
+ protected final UiEventLogger mUiEventLogger;
private final NotificationRemoteInputManager mRemoteInputManager =
Dependency.get(NotificationRemoteInputManager.class);
private final SysuiColorExtractor mColorExtractor = Dependency.get(SysuiColorExtractor.class);
@@ -547,7 +550,8 @@ public class NotificationStackScrollLayout extends ViewGroup implements ScrollAd
FeatureFlags featureFlags,
NotifPipeline notifPipeline,
NotificationEntryManager entryManager,
- NotifCollection notifCollection
+ NotifCollection notifCollection,
+ UiEventLogger uiEventLogger
) {
super(context, attrs, 0, 0);
Resources res = getResources();
@@ -649,6 +653,7 @@ public class NotificationStackScrollLayout extends ViewGroup implements ScrollAd
mDynamicPrivacyController = dynamicPrivacyController;
mStatusbarStateController = statusBarStateController;
initializeForegroundServiceSection(fgsFeatureController);
+ mUiEventLogger = uiEventLogger;
}
private void initializeForegroundServiceSection(
@@ -5524,7 +5529,8 @@ public class NotificationStackScrollLayout extends ViewGroup implements ScrollAd
}
@ShadeViewRefactor(RefactorComponent.SHADE_VIEW)
- private void clearNotifications(
+ @VisibleForTesting
+ void clearNotifications(
@SelectedRows int selection,
boolean closeShade) {
// animate-swipe all dismissable notifications, then animate the shade closed
@@ -5567,6 +5573,9 @@ public class NotificationStackScrollLayout extends ViewGroup implements ScrollAd
}
}
+ // Log dismiss event even if there's nothing to dismiss
+ mUiEventLogger.log(NotificationPanelEvent.fromSelection(selection));
+
if (viewsToRemove.isEmpty()) {
if (closeShade) {
Dependency.get(ShadeController.class).animateCollapsePanels(
@@ -6737,4 +6746,35 @@ public class NotificationStackScrollLayout extends ViewGroup implements ScrollAd
public static final int ROWS_HIGH_PRIORITY = 1;
/** Only rows where entry.isHighPriority() is false. */
public static final int ROWS_GENTLE = 2;
+
+ /**
+ * Enum for UiEvent logged from this class
+ */
+ enum NotificationPanelEvent implements UiEventLogger.UiEventEnum {
+ INVALID(0),
+ @UiEvent(doc = "User dismissed all notifications from notification panel.")
+ DISMISS_ALL_NOTIFICATIONS_PANEL(312),
+ @UiEvent(doc = "User dismissed all silent notifications from notification panel.")
+ DISMISS_SILENT_NOTIFICATIONS_PANEL(314);
+ private final int mId;
+ NotificationPanelEvent(int id) {
+ mId = id;
+ }
+ @Override public int getId() {
+ return mId;
+ }
+
+ public static UiEventLogger.UiEventEnum fromSelection(@SelectedRows int selection) {
+ if (selection == ROWS_ALL) {
+ return DISMISS_ALL_NOTIFICATIONS_PANEL;
+ }
+ if (selection == ROWS_GENTLE) {
+ return DISMISS_SILENT_NOTIFICATIONS_PANEL;
+ }
+ if (NotificationStackScrollLayout.DEBUG) {
+ throw new IllegalArgumentException("Unexpected selection" + selection);
+ }
+ return INVALID;
+ }
+ }
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/LockIcon.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/LockIcon.java
index c29ec9eeaf56..cf9d43eeff73 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/LockIcon.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/LockIcon.java
@@ -26,7 +26,6 @@ import android.graphics.Color;
import android.graphics.drawable.Animatable2;
import android.graphics.drawable.AnimatedVectorDrawable;
import android.graphics.drawable.Drawable;
-import android.hardware.biometrics.BiometricSourceType;
import android.os.Trace;
import android.provider.Settings;
import android.text.TextUtils;
@@ -34,22 +33,17 @@ import android.util.AttributeSet;
import android.view.ViewTreeObserver;
import android.view.accessibility.AccessibilityNodeInfo;
-import androidx.annotation.Nullable;
-
import com.android.internal.graphics.ColorUtils;
import com.android.keyguard.KeyguardUpdateMonitor;
-import com.android.keyguard.KeyguardUpdateMonitorCallback;
import com.android.systemui.Dependency;
import com.android.systemui.Interpolators;
import com.android.systemui.R;
-import com.android.systemui.dock.DockManager;
import com.android.systemui.statusbar.KeyguardAffordanceView;
import com.android.systemui.statusbar.StatusBarState;
import com.android.systemui.statusbar.notification.NotificationWakeUpCoordinator;
import com.android.systemui.statusbar.phone.ScrimController.ScrimVisibility;
import com.android.systemui.statusbar.policy.AccessibilityController;
import com.android.systemui.statusbar.policy.KeyguardStateController;
-import com.android.systemui.statusbar.policy.OnHeadsUpChangedListener;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
@@ -61,8 +55,7 @@ import javax.inject.Named;
* Manages the different states and animations of the unlock icon.
*/
public class LockIcon extends KeyguardAffordanceView implements
- KeyguardStateController.Callback, NotificationWakeUpCoordinator.WakeUpListener,
- ViewTreeObserver.OnPreDrawListener, OnHeadsUpChangedListener {
+ ViewTreeObserver.OnPreDrawListener {
private static final int STATE_LOCKED = 0;
private static final int STATE_LOCK_OPEN = 1;
@@ -70,7 +63,6 @@ public class LockIcon extends KeyguardAffordanceView implements
private static final int STATE_BIOMETRICS_ERROR = 3;
private final KeyguardUpdateMonitor mKeyguardUpdateMonitor;
private final AccessibilityController mAccessibilityController;
- private final DockManager mDockManager;
private final KeyguardStateController mKeyguardStateController;
private final KeyguardBypassController mBypassController;
private final NotificationWakeUpCoordinator mWakeUpCoordinator;
@@ -130,43 +122,6 @@ public class LockIcon extends KeyguardAffordanceView implements
update();
}
};
- private final DockManager.DockEventListener mDockEventListener =
- new DockManager.DockEventListener() {
- @Override
- public void onEvent(int event) {
- boolean docked = event == DockManager.STATE_DOCKED
- || event == DockManager.STATE_DOCKED_HIDE;
- if (docked != mDocked) {
- mDocked = docked;
- update();
- }
- }
- };
-
- private final KeyguardUpdateMonitorCallback mUpdateMonitorCallback =
- new KeyguardUpdateMonitorCallback() {
- @Override
- public void onSimStateChanged(int subId, int slotId, int simState) {
- mSimLocked = mKeyguardUpdateMonitor.isSimPinSecure();
- update();
- }
-
- @Override
- public void onKeyguardVisibilityChanged(boolean showing) {
- update();
- }
-
- @Override
- public void onBiometricRunningStateChanged(boolean running,
- BiometricSourceType biometricSourceType) {
- update();
- }
-
- @Override
- public void onStrongAuthStateChanged(int userId) {
- update();
- }
- };
@Inject
public LockIcon(@Named(VIEW_CONTEXT) Context context, AttributeSet attrs,
@@ -174,7 +129,6 @@ public class LockIcon extends KeyguardAffordanceView implements
KeyguardBypassController bypassController,
NotificationWakeUpCoordinator wakeUpCoordinator,
KeyguardStateController keyguardStateController,
- @Nullable DockManager dockManager,
HeadsUpManagerPhone headsUpManager) {
super(context, attrs);
mContext = context;
@@ -183,7 +137,6 @@ public class LockIcon extends KeyguardAffordanceView implements
mBypassController = bypassController;
mWakeUpCoordinator = wakeUpCoordinator;
mKeyguardStateController = keyguardStateController;
- mDockManager = dockManager;
mHeadsUpManager = headsUpManager;
}
@@ -191,24 +144,14 @@ public class LockIcon extends KeyguardAffordanceView implements
protected void onAttachedToWindow() {
super.onAttachedToWindow();
mKeyguardStateController.addCallback(mKeyguardMonitorCallback);
- mKeyguardUpdateMonitor.registerCallback(mUpdateMonitorCallback);
- mWakeUpCoordinator.addListener(this);
mSimLocked = mKeyguardUpdateMonitor.isSimPinSecure();
- if (mDockManager != null) {
- mDockManager.addListener(mDockEventListener);
- }
update();
}
@Override
protected void onDetachedFromWindow() {
super.onDetachedFromWindow();
- mKeyguardUpdateMonitor.removeCallback(mUpdateMonitorCallback);
mKeyguardStateController.removeCallback(mKeyguardMonitorCallback);
- mWakeUpCoordinator.removeListener(this);
- if (mDockManager != null) {
- mDockManager.removeListener(mDockEventListener);
- }
}
/**
@@ -306,7 +249,7 @@ public class LockIcon extends KeyguardAffordanceView implements
* Update the icon visibility
* @return true if the visibility changed
*/
- private boolean updateIconVisibility() {
+ boolean updateIconVisibility() {
boolean onAodNotPulsingOrDocked = mDozing && (!mPulsing || mDocked);
boolean invisible = onAodNotPulsingOrDocked || mWakeAndUnlockRunning
|| mShowingLaunchAffordance;
@@ -424,16 +367,6 @@ public class LockIcon extends KeyguardAffordanceView implements
return -1;
}
- @Override
- public void onFullyHiddenChanged(boolean isFullyHidden) {
- if (mBypassController.getBypassEnabled()) {
- boolean changed = updateIconVisibility();
- if (changed) {
- update();
- }
- }
- }
-
public void setBouncerShowingScrimmed(boolean bouncerShowing) {
mBouncerShowingScrimmed = bouncerShowing;
if (mBypassController.getBypassEnabled()) {
@@ -454,6 +387,18 @@ public class LockIcon extends KeyguardAffordanceView implements
updateDarkTint();
}
+ void setSimLocked(boolean simLocked) {
+ mSimLocked = simLocked;
+ }
+
+ /** Set if the device is docked. */
+ public void setDocked(boolean docked) {
+ if (mDocked != docked) {
+ mDocked = docked;
+ update();
+ }
+ }
+
@Retention(RetentionPolicy.SOURCE)
@IntDef({ERROR, UNLOCK, LOCK, SCANNING})
@interface LockAnimIndex {}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/LockscreenLockIconController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/LockscreenLockIconController.java
index 698a430c389e..2b1a8a472d9e 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/LockscreenLockIconController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/LockscreenLockIconController.java
@@ -18,20 +18,29 @@ package com.android.systemui.statusbar.phone;
import android.content.res.TypedArray;
import android.graphics.Color;
+import android.hardware.biometrics.BiometricSourceType;
import android.view.View;
import android.view.ViewGroup;
+import androidx.annotation.Nullable;
+
import com.android.internal.logging.nano.MetricsProto;
import com.android.internal.widget.LockPatternUtils;
import com.android.keyguard.KeyguardUpdateMonitor;
+import com.android.keyguard.KeyguardUpdateMonitorCallback;
import com.android.systemui.R;
+import com.android.systemui.dock.DockManager;
import com.android.systemui.plugins.statusbar.StatusBarStateController;
import com.android.systemui.statusbar.CommandQueue;
import com.android.systemui.statusbar.KeyguardIndicationController;
+import com.android.systemui.statusbar.notification.NotificationWakeUpCoordinator;
+import com.android.systemui.statusbar.notification.NotificationWakeUpCoordinator.WakeUpListener;
import com.android.systemui.statusbar.policy.AccessibilityController;
import com.android.systemui.statusbar.policy.ConfigurationController;
import com.android.systemui.statusbar.policy.ConfigurationController.ConfigurationListener;
+import java.util.Optional;
+
import javax.inject.Inject;
import javax.inject.Singleton;
@@ -47,6 +56,9 @@ public class LockscreenLockIconController {
private final KeyguardIndicationController mKeyguardIndicationController;
private final StatusBarStateController mStatusBarStateController;
private final ConfigurationController mConfigurationController;
+ private final NotificationWakeUpCoordinator mNotificationWakeUpCoordinator;
+ private final KeyguardBypassController mKeyguardBypassController;
+ private final Optional<DockManager> mDockManager;
private LockIcon mLockIcon;
private View.OnAttachStateChangeListener mOnAttachStateChangeListener =
@@ -55,6 +67,10 @@ public class LockscreenLockIconController {
public void onViewAttachedToWindow(View v) {
mStatusBarStateController.addCallback(mSBStateListener);
mConfigurationController.addCallback(mConfigurationListener);
+ mNotificationWakeUpCoordinator.addListener(mWakeUpListener);
+ mKeyguardUpdateMonitor.registerCallback(mUpdateMonitorCallback);
+
+ mDockManager.ifPresent(dockManager -> dockManager.addListener(mDockEventListener));
mConfigurationListener.onThemeChanged();
}
@@ -63,6 +79,11 @@ public class LockscreenLockIconController {
public void onViewDetachedFromWindow(View v) {
mStatusBarStateController.removeCallback(mSBStateListener);
mConfigurationController.removeCallback(mConfigurationListener);
+ mNotificationWakeUpCoordinator.removeListener(mWakeUpListener);
+ mKeyguardUpdateMonitor.removeCallback(mUpdateMonitorCallback);
+
+
+ mDockManager.ifPresent(dockManager -> dockManager.removeListener(mDockEventListener));
}
};
@@ -115,6 +136,47 @@ public class LockscreenLockIconController {
}
};
+ private final WakeUpListener mWakeUpListener = new WakeUpListener() {
+ @Override
+ public void onFullyHiddenChanged(boolean isFullyHidden) {
+ if (mKeyguardBypassController.getBypassEnabled()) {
+ boolean changed = mLockIcon.updateIconVisibility();
+ if (changed) {
+ mLockIcon.update();
+ }
+ }
+ }
+ };
+
+ private final KeyguardUpdateMonitorCallback mUpdateMonitorCallback =
+ new KeyguardUpdateMonitorCallback() {
+ @Override
+ public void onSimStateChanged(int subId, int slotId, int simState) {
+ mLockIcon.setSimLocked(mKeyguardUpdateMonitor.isSimPinSecure());
+ mLockIcon.update();
+ }
+
+ @Override
+ public void onKeyguardVisibilityChanged(boolean showing) {
+ mLockIcon.update();
+ }
+
+ @Override
+ public void onBiometricRunningStateChanged(boolean running,
+ BiometricSourceType biometricSourceType) {
+ mLockIcon.update();
+ }
+
+ @Override
+ public void onStrongAuthStateChanged(int userId) {
+ mLockIcon.update();
+ }
+ };
+
+ private final DockManager.DockEventListener mDockEventListener =
+ event -> mLockIcon.setDocked(event == DockManager.STATE_DOCKED
+ || event == DockManager.STATE_DOCKED_HIDE);
+
@Inject
public LockscreenLockIconController(LockscreenGestureLogger lockscreenGestureLogger,
KeyguardUpdateMonitor keyguardUpdateMonitor,
@@ -123,7 +185,10 @@ public class LockscreenLockIconController {
AccessibilityController accessibilityController,
KeyguardIndicationController keyguardIndicationController,
StatusBarStateController statusBarStateController,
- ConfigurationController configurationController) {
+ ConfigurationController configurationController,
+ NotificationWakeUpCoordinator notificationWakeUpCoordinator,
+ KeyguardBypassController keyguardBypassController,
+ @Nullable DockManager dockManager) {
mLockscreenGestureLogger = lockscreenGestureLogger;
mKeyguardUpdateMonitor = keyguardUpdateMonitor;
mLockPatternUtils = lockPatternUtils;
@@ -132,6 +197,9 @@ public class LockscreenLockIconController {
mKeyguardIndicationController = keyguardIndicationController;
mStatusBarStateController = statusBarStateController;
mConfigurationController = configurationController;
+ mNotificationWakeUpCoordinator = notificationWakeUpCoordinator;
+ mKeyguardBypassController = keyguardBypassController;
+ mDockManager = dockManager == null ? Optional.empty() : Optional.of(dockManager);
mKeyguardIndicationController.setLockIconController(this);
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarFragment.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarFragment.java
index 02cf8ccbef8b..b119f0b1f1e2 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarFragment.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarFragment.java
@@ -205,6 +205,28 @@ public class NavigationBarFragment extends LifecycleFragment implements Callback
private final Handler mHandler;
+ private final AutoHideUiElement mAutoHideUiElement = new AutoHideUiElement() {
+ @Override
+ public void synchronizeState() {
+ checkNavBarModes();
+ }
+
+ @Override
+ public boolean shouldHideOnTouch() {
+ return !mNotificationRemoteInputManager.getController().isRemoteInputActive();
+ }
+
+ @Override
+ public boolean isVisible() {
+ return isTransientShown();
+ }
+
+ @Override
+ public void hide() {
+ clearTransient();
+ }
+ };
+
private final OverviewProxyListener mOverviewProxyListener = new OverviewProxyListener() {
@Override
public void onConnectionChanged(boolean isConnected) {
@@ -1052,28 +1074,13 @@ public class NavigationBarFragment extends LifecycleFragment implements Callback
/** Sets {@link AutoHideController} to the navigation bar. */
public void setAutoHideController(AutoHideController autoHideController) {
+ if (mAutoHideController != null) {
+ mAutoHideController.removeAutoHideUiElement(mAutoHideUiElement);
+ }
mAutoHideController = autoHideController;
- mAutoHideController.addAutoHideUiElement(new AutoHideUiElement() {
- @Override
- public void synchronizeState() {
- checkNavBarModes();
- }
-
- @Override
- public boolean shouldHideOnTouch() {
- return !mNotificationRemoteInputManager.getController().isRemoteInputActive();
- }
-
- @Override
- public boolean isVisible() {
- return isTransientShown();
- }
-
- @Override
- public void hide() {
- clearTransient();
- }
- });
+ if (mAutoHideController != null) {
+ mAutoHideController.addAutoHideUiElement(mAutoHideUiElement);
+ }
}
private boolean isTransientShown() {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationModeController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationModeController.java
index 67e7f2302f44..43ac4cf732aa 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationModeController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationModeController.java
@@ -16,26 +16,14 @@
package com.android.systemui.statusbar.phone;
-import static android.app.Activity.RESULT_CANCELED;
-import static android.app.Activity.RESULT_OK;
-import static android.app.admin.DevicePolicyManager.STATE_USER_UNMANAGED;
import static android.content.Intent.ACTION_OVERLAY_CHANGED;
import static android.content.Intent.ACTION_PREFERRED_ACTIVITY_CHANGED;
-import static android.content.pm.PackageManager.FEATURE_DEVICE_ADMIN;
import static android.os.UserHandle.USER_CURRENT;
-import static android.view.WindowManagerPolicyConstants.NAV_BAR_MODE_3BUTTON;
import static android.view.WindowManagerPolicyConstants.NAV_BAR_MODE_3BUTTON_OVERLAY;
import static android.view.WindowManagerPolicyConstants.NAV_BAR_MODE_GESTURAL;
import static android.view.WindowManagerPolicyConstants.NAV_BAR_MODE_GESTURAL_OVERLAY;
-import static com.android.systemui.shared.system.QuickStepContract.ACTION_ENABLE_GESTURE_NAV;
-import static com.android.systemui.shared.system.QuickStepContract.ACTION_ENABLE_GESTURE_NAV_RESULT;
-import static com.android.systemui.shared.system.QuickStepContract.EXTRA_RESULT_INTENT;
-
-import android.app.PendingIntent;
-import android.app.admin.DevicePolicyManager;
import android.content.BroadcastReceiver;
-import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
@@ -46,7 +34,6 @@ import android.os.PatternMatcher;
import android.os.RemoteException;
import android.os.ServiceManager;
import android.os.UserHandle;
-import android.os.UserManager;
import android.provider.Settings;
import android.provider.Settings.Secure;
import android.util.Log;
@@ -87,7 +74,6 @@ public class NavigationModeController implements Dumpable {
private SparseBooleanArray mRestoreGesturalNavBarMode = new SparseBooleanArray();
- private int mMode = NAV_BAR_MODE_3BUTTON;
private ArrayList<ModeChangedListener> mListeners = new ArrayList<>();
private BroadcastReceiver mReceiver = new BroadcastReceiver() {
@@ -142,8 +128,6 @@ public class NavigationModeController implements Dumpable {
}
};
- private BroadcastReceiver mEnableGestureNavReceiver;
-
@Inject
public NavigationModeController(Context context,
DeviceProvisionedController deviceProvisionedController,
@@ -171,18 +155,7 @@ public class NavigationModeController implements Dumpable {
deferGesturalNavOverlayIfNecessary();
}
- private void removeEnableGestureNavListener() {
- if (mEnableGestureNavReceiver != null) {
- if (DEBUG) {
- Log.d(TAG, "mEnableGestureNavReceiver unregistered");
- }
- mContext.unregisterReceiver(mEnableGestureNavReceiver);
- mEnableGestureNavReceiver = null;
- }
- }
-
private boolean setGestureModeOverlayForMainLauncher() {
- removeEnableGestureNavListener();
if (getCurrentInteractionMode(mCurrentUserContext) == NAV_BAR_MODE_GESTURAL) {
// Already in gesture mode
return true;
@@ -196,59 +169,15 @@ public class NavigationModeController implements Dumpable {
return true;
}
- private boolean enableGestureNav(Intent intent) {
- if (!(intent.getParcelableExtra(EXTRA_RESULT_INTENT) instanceof PendingIntent)) {
- Log.e(TAG, "No callback pending intent was attached");
- return false;
- }
-
- PendingIntent callback = intent.getParcelableExtra(EXTRA_RESULT_INTENT);
- Intent callbackIntent = callback.getIntent();
- if (callbackIntent == null
- || !ACTION_ENABLE_GESTURE_NAV_RESULT.equals(callbackIntent.getAction())) {
- Log.e(TAG, "Invalid callback intent");
- return false;
- }
- String callerPackage = callback.getCreatorPackage();
- UserHandle callerUser = callback.getCreatorUserHandle();
-
- DevicePolicyManager dpm = mCurrentUserContext.getSystemService(DevicePolicyManager.class);
- ComponentName ownerComponent = dpm.getDeviceOwnerComponentOnCallingUser();
-
- if (ownerComponent != null) {
- // Verify that the caller is the owner component
- if (!ownerComponent.getPackageName().equals(callerPackage)
- || !mCurrentUserContext.getUser().equals(callerUser)) {
- Log.e(TAG, "Callback must be from the device owner");
- return false;
- }
- } else {
- UserHandle callerParent = mCurrentUserContext.getSystemService(UserManager.class)
- .getProfileParent(callerUser);
- if (callerParent == null || !callerParent.equals(mCurrentUserContext.getUser())) {
- Log.e(TAG, "Callback must be from a managed user");
- return false;
- }
- ComponentName profileOwner = dpm.getProfileOwnerAsUser(callerUser);
- if (profileOwner == null || !profileOwner.getPackageName().equals(callerPackage)) {
- Log.e(TAG, "Callback must be from the profile owner");
- return false;
- }
- }
-
- return setGestureModeOverlayForMainLauncher();
- }
-
public void updateCurrentInteractionMode(boolean notify) {
mCurrentUserContext = getCurrentUserContext();
int mode = getCurrentInteractionMode(mCurrentUserContext);
- mMode = mode;
mUiBgExecutor.execute(() -> {
Settings.Secure.putString(mCurrentUserContext.getContentResolver(),
Secure.NAVIGATION_MODE, String.valueOf(mode));
});
if (DEBUG) {
- Log.e(TAG, "updateCurrentInteractionMode: mode=" + mMode);
+ Log.e(TAG, "updateCurrentInteractionMode: mode=" + mode);
dumpAssetPaths(mCurrentUserContext);
}
@@ -272,7 +201,7 @@ public class NavigationModeController implements Dumpable {
int mode = context.getResources().getInteger(
com.android.internal.R.integer.config_navBarInteractionMode);
if (DEBUG) {
- Log.d(TAG, "getCurrentInteractionMode: mode=" + mMode
+ Log.d(TAG, "getCurrentInteractionMode: mode=" + mode
+ " contextUser=" + context.getUserId());
}
return mode;
@@ -297,10 +226,6 @@ public class NavigationModeController implements Dumpable {
}
}
- private boolean supportsDeviceAdmin() {
- return mContext.getPackageManager().hasSystemFeature(FEATURE_DEVICE_ADMIN);
- }
-
private void deferGesturalNavOverlayIfNecessary() {
final int userId = mDeviceProvisionedController.getCurrentUser();
mRestoreGesturalNavBarMode.put(userId, false);
@@ -311,7 +236,6 @@ public class NavigationModeController implements Dumpable {
Log.d(TAG, "deferGesturalNavOverlayIfNecessary: device is provisioned and user is "
+ "setup");
}
- removeEnableGestureNavListener();
return;
}
@@ -327,7 +251,6 @@ public class NavigationModeController implements Dumpable {
Log.d(TAG, "deferGesturalNavOverlayIfNecessary: no default gestural overlay, "
+ "default=" + defaultOverlays);
}
- removeEnableGestureNavListener();
return;
}
@@ -336,23 +259,6 @@ public class NavigationModeController implements Dumpable {
setModeOverlay(NAV_BAR_MODE_3BUTTON_OVERLAY, USER_CURRENT);
mRestoreGesturalNavBarMode.put(userId, true);
- if (supportsDeviceAdmin() && mEnableGestureNavReceiver == null) {
- mEnableGestureNavReceiver = new BroadcastReceiver() {
- @Override
- public void onReceive(Context context, Intent intent) {
- if (DEBUG) {
- Log.d(TAG, "ACTION_ENABLE_GESTURE_NAV");
- }
- setResultCode(enableGestureNav(intent) ? RESULT_OK : RESULT_CANCELED);
- }
- };
- // Register for all users so that we can get managed users as well
- mContext.registerReceiverAsUser(mEnableGestureNavReceiver, UserHandle.ALL,
- new IntentFilter(ACTION_ENABLE_GESTURE_NAV), null, null);
- if (DEBUG) {
- Log.d(TAG, "mEnableGestureNavReceiver registered");
- }
- }
if (DEBUG) {
Log.d(TAG, "deferGesturalNavOverlayIfNecessary: setting to 3 button mode");
}
@@ -366,15 +272,7 @@ public class NavigationModeController implements Dumpable {
final int userId = mDeviceProvisionedController.getCurrentUser();
if (mRestoreGesturalNavBarMode.get(userId)) {
// Restore the gestural state if necessary
- if (!supportsDeviceAdmin()
- || mCurrentUserContext.getSystemService(DevicePolicyManager.class)
- .getUserProvisioningState() == STATE_USER_UNMANAGED) {
- setGestureModeOverlayForMainLauncher();
- } else {
- if (DEBUG) {
- Log.d(TAG, "Not restoring to gesture nav for managed user");
- }
- }
+ setGestureModeOverlayForMainLauncher();
mRestoreGesturalNavBarMode.put(userId, false);
}
}
@@ -396,7 +294,7 @@ public class NavigationModeController implements Dumpable {
@Override
public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
pw.println("NavigationModeController:");
- pw.println(" mode=" + mMode);
+ pw.println(" mode=" + getCurrentInteractionMode(mCurrentUserContext));
String defaultOverlays = "";
try {
defaultOverlays = String.join(", ", mOverlayManager.getDefaultOverlayPackages());
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 945a9db7c836..d1ff32d9304e 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimController.java
@@ -16,6 +16,8 @@
package com.android.systemui.statusbar.phone;
+import static java.lang.Float.isNaN;
+
import android.animation.Animator;
import android.animation.AnimatorListenerAdapter;
import android.animation.ValueAnimator;
@@ -289,6 +291,10 @@ public class ScrimController implements ViewTreeObserver.OnPreDrawListener, OnCo
mInFrontAlpha = state.getFrontAlpha();
mBehindAlpha = state.getBehindAlpha();
mBubbleAlpha = state.getBubbleAlpha();
+ if (isNaN(mBehindAlpha) || isNaN(mInFrontAlpha)) {
+ throw new IllegalStateException("Scrim opacity is NaN for state: " + state + ", front: "
+ + mInFrontAlpha + ", back: " + mBehindAlpha);
+ }
applyExpansionToAlpha();
// Scrim might acquire focus when user is navigating with a D-pad or a keyboard.
@@ -416,6 +422,9 @@ public class ScrimController implements ViewTreeObserver.OnPreDrawListener, OnCo
* @param fraction From 0 to 1 where 0 means collapsed and 1 expanded.
*/
public void setPanelExpansion(float fraction) {
+ if (isNaN(fraction)) {
+ throw new IllegalArgumentException("Fraction should not be NaN");
+ }
if (mExpansionFraction != fraction) {
mExpansionFraction = fraction;
@@ -493,6 +502,10 @@ public class ScrimController implements ViewTreeObserver.OnPreDrawListener, OnCo
mBehindTint = ColorUtils.blendARGB(ScrimState.BOUNCER.getBehindTint(),
mState.getBehindTint(), interpolatedFract);
}
+ if (isNaN(mBehindAlpha) || isNaN(mInFrontAlpha)) {
+ throw new IllegalStateException("Scrim opacity is NaN for state: " + mState
+ + ", front: " + mInFrontAlpha + ", back: " + mBehindAlpha);
+ }
}
/**
@@ -548,6 +561,10 @@ public class ScrimController implements ViewTreeObserver.OnPreDrawListener, OnCo
float newBehindAlpha = mState.getBehindAlpha();
if (mBehindAlpha != newBehindAlpha) {
mBehindAlpha = newBehindAlpha;
+ if (isNaN(mBehindAlpha)) {
+ throw new IllegalStateException("Scrim opacity is NaN for state: " + mState
+ + ", back: " + mBehindAlpha);
+ }
updateScrims();
}
}
@@ -948,8 +965,11 @@ public class ScrimController implements ViewTreeObserver.OnPreDrawListener, OnCo
pw.print(" tint=0x");
pw.println(Integer.toHexString(mScrimForBubble.getTint()));
- pw.print(" mTracking=");
+ pw.print(" mTracking=");
pw.println(mTracking);
+
+ pw.print(" mExpansionFraction=");
+ pw.println(mExpansionFraction);
}
public void setWallpaperSupportsAmbientMode(boolean wallpaperSupportsAmbientMode) {
@@ -996,6 +1016,10 @@ public class ScrimController implements ViewTreeObserver.OnPreDrawListener, OnCo
// in this case, back-scrim needs to be re-evaluated
if (mState == ScrimState.AOD || mState == ScrimState.PULSING) {
float newBehindAlpha = mState.getBehindAlpha();
+ if (isNaN(newBehindAlpha)) {
+ throw new IllegalStateException("Scrim opacity is NaN for state: " + mState
+ + ", back: " + mBehindAlpha);
+ }
if (mBehindAlpha != newBehindAlpha) {
mBehindAlpha = newBehindAlpha;
updateScrims();
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 3e6e027d6c59..b3a62d8a4753 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java
@@ -2332,7 +2332,7 @@ public class StatusBar extends SystemUI implements DemoMode,
void checkBarModes() {
if (mDemoMode) return;
- if (mNotificationShadeWindowViewController != null) {
+ if (mNotificationShadeWindowViewController != null && getStatusBarTransitions() != null) {
checkBarMode(mStatusBarMode, mStatusBarWindowState, getStatusBarTransitions());
}
mNavigationBarController.checkNavBarModes(mDisplayId);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java
index 0644a42202d5..31db8eb404a9 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java
@@ -42,6 +42,7 @@ import com.android.internal.util.LatencyTracker;
import com.android.internal.widget.LockPatternUtils;
import com.android.keyguard.KeyguardUpdateMonitor;
import com.android.keyguard.KeyguardUpdateMonitorCallback;
+import com.android.keyguard.KeyguardViewController;
import com.android.keyguard.ViewMediatorCallback;
import com.android.settingslib.animation.AppearAnimationUtils;
import com.android.systemui.DejankUtils;
@@ -77,7 +78,8 @@ import javax.inject.Singleton;
@Singleton
public class StatusBarKeyguardViewManager implements RemoteInputController.Callback,
StatusBarStateController.StateListener, ConfigurationController.ConfigurationListener,
- PanelExpansionListener, NavigationModeController.ModeChangedListener {
+ PanelExpansionListener, NavigationModeController.ModeChangedListener,
+ KeyguardViewController {
// When hiding the Keyguard with timing supplied from WindowManager, better be early than late.
private static final long HIDE_TIMING_CORRECTION_MS = - 16 * 3;
@@ -221,6 +223,7 @@ public class StatusBarKeyguardViewManager implements RemoteInputController.Callb
mDockManager = dockManager;
}
+ @Override
public void registerStatusBar(StatusBar statusBar,
ViewGroup container,
NotificationPanelViewController notificationPanelViewController,
@@ -326,6 +329,7 @@ public class StatusBarKeyguardViewManager implements RemoteInputController.Callb
* Show the keyguard. Will handle creating and attaching to the view manager
* lazily.
*/
+ @Override
public void show(Bundle options) {
mShowing = true;
mNotificationShadeWindowController.setKeyguardShowing(true);
@@ -430,9 +434,7 @@ public class StatusBarKeyguardViewManager implements RemoteInputController.Callb
mAfterKeyguardGoneRunnables.add(runnable);
}
- /**
- * Reset the state of the view.
- */
+ @Override
public void reset(boolean hideBouncerWhenShowing) {
if (mShowing) {
if (mOccluded && !mDozing) {
@@ -452,23 +454,28 @@ public class StatusBarKeyguardViewManager implements RemoteInputController.Callb
return mGoingToSleepVisibleNotOccluded;
}
+ @Override
public void onStartedGoingToSleep() {
mGoingToSleepVisibleNotOccluded = isShowing() && !isOccluded();
}
+ @Override
public void onFinishedGoingToSleep() {
mGoingToSleepVisibleNotOccluded = false;
mBouncer.onScreenTurnedOff();
}
+ @Override
public void onStartedWakingUp() {
// TODO: remove
}
+ @Override
public void onScreenTurningOn() {
// TODO: remove
}
+ @Override
public void onScreenTurnedOn() {
// TODO: remove
}
@@ -503,14 +510,17 @@ public class StatusBarKeyguardViewManager implements RemoteInputController.Callb
}
}
+ @Override
public void setNeedsInput(boolean needsInput) {
mNotificationShadeWindowController.setKeyguardNeedsInput(needsInput);
}
+ @Override
public boolean isUnlockWithWallpaper() {
return mNotificationShadeWindowController.isShowingWallpaper();
}
+ @Override
public void setOccluded(boolean occluded, boolean animate) {
mStatusBar.setOccluded(occluded);
if (occluded && !mOccluded && mShowing) {
@@ -554,13 +564,7 @@ public class StatusBarKeyguardViewManager implements RemoteInputController.Callb
return mOccluded;
}
- /**
- * Starts the animation before we dismiss Keyguard, i.e. an disappearing animation on the
- * security view of the bouncer.
- *
- * @param finishRunnable the runnable to be run after the animation finished, or {@code null} if
- * no action should be run
- */
+ @Override
public void startPreHideAnimation(Runnable finishRunnable) {
if (mBouncer.isShowing()) {
mBouncer.startPreHideAnimation(finishRunnable);
@@ -572,9 +576,7 @@ public class StatusBarKeyguardViewManager implements RemoteInputController.Callb
updateLockIcon();
}
- /**
- * Hides the keyguard view
- */
+ @Override
public void hide(long startTime, long fadeoutDuration) {
mShowing = false;
mKeyguardStateController.notifyKeyguardState(mShowing,
@@ -728,9 +730,7 @@ public class StatusBarKeyguardViewManager implements RemoteInputController.Callb
mAfterKeyguardGoneRunnables.clear();
}
- /**
- * Dismisses the keyguard by going to the next screen or making it gone.
- */
+ @Override
public void dismissAndCollapse() {
mStatusBar.executeRunnableDismissingKeyguard(null, null, true, false, true);
}
@@ -742,9 +742,7 @@ public class StatusBarKeyguardViewManager implements RemoteInputController.Callb
return mBouncer.isSecure();
}
- /**
- * @return Whether the keyguard is showing
- */
+ @Override
public boolean isShowing() {
return mShowing;
}
@@ -921,18 +919,17 @@ public class StatusBarKeyguardViewManager implements RemoteInputController.Callb
mViewMediatorCallback.readyForKeyguardDone();
}
+ @Override
public boolean shouldDisableWindowAnimationsForUnlock() {
return mStatusBar.isInLaunchTransition();
}
-
- /**
- * @return Whether subtle animation should be used for unlocking the device.
- */
+ @Override
public boolean shouldSubtleWindowAnimationsForUnlock() {
return needsBypassFading();
}
+ @Override
public boolean isGoingToNotificationShade() {
return mStatusBarStateController.leaveOpenOnKeyguardHide();
}
@@ -941,13 +938,12 @@ public class StatusBarKeyguardViewManager implements RemoteInputController.Callb
return mBouncer.isSecure() || mLockPatternUtils.isSecure(userId);
}
+ @Override
public void keyguardGoingAway() {
mStatusBar.keyguardGoingAway();
}
- /**
- * Called when cancel button in bouncer is pressed.
- */
+ @Override
public void onCancelClicked() {
// No-op
}
@@ -964,6 +960,7 @@ public class StatusBarKeyguardViewManager implements RemoteInputController.Callb
mBouncer.showMessage(message, colorState);
}
+ @Override
public ViewRootImpl getViewRootImpl() {
return mStatusBar.getStatusBarView().getViewRootImpl();
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/BatteryController.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/BatteryController.java
index cf9d8e1d85ec..24b96855377f 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/BatteryController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/BatteryController.java
@@ -53,6 +53,12 @@ public interface BatteryController extends DemoMode, Dumpable,
boolean isAodPowerSave();
/**
+ * Set reverse state.
+ * @param isReverse true if turn on reverse, false otherwise
+ */
+ default void setReverseState(boolean isReverse) {}
+
+ /**
* A listener that will be notified whenever a change in battery level or power save mode has
* occurred.
*/
@@ -63,6 +69,9 @@ public interface BatteryController extends DemoMode, Dumpable,
default void onPowerSaveChanged(boolean isPowerSave) {
}
+
+ default void onReverseChanged(boolean isReverse, int level, String name) {
+ }
}
/**
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/BatteryControllerImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/BatteryControllerImpl.java
index d3e6f5309875..35954d88391a 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/BatteryControllerImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/BatteryControllerImpl.java
@@ -59,13 +59,13 @@ public class BatteryControllerImpl extends BroadcastReceiver implements BatteryC
private final EnhancedEstimates mEstimates;
private final BroadcastDispatcher mBroadcastDispatcher;
- private final ArrayList<BatteryController.BatteryStateChangeCallback>
+ protected final ArrayList<BatteryController.BatteryStateChangeCallback>
mChangeCallbacks = new ArrayList<>();
private final ArrayList<EstimateFetchCompletion> mFetchCallbacks = new ArrayList<>();
private final PowerManager mPowerManager;
private final Handler mMainHandler;
private final Handler mBgHandler;
- private final Context mContext;
+ protected final Context mContext;
private int mLevel;
private boolean mPluggedIn;
@@ -80,7 +80,7 @@ public class BatteryControllerImpl extends BroadcastReceiver implements BatteryC
@VisibleForTesting
@Inject
- BatteryControllerImpl(Context context, EnhancedEstimates enhancedEstimates,
+ protected BatteryControllerImpl(Context context, EnhancedEstimates enhancedEstimates,
PowerManager powerManager, BroadcastDispatcher broadcastDispatcher,
@Main Handler mainHandler, @Background Handler bgHandler) {
mContext = context;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/DeviceProvisionedControllerImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/DeviceProvisionedControllerImpl.java
index a3e2e7619bac..7280a881655c 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/DeviceProvisionedControllerImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/DeviceProvisionedControllerImpl.java
@@ -59,7 +59,7 @@ public class DeviceProvisionedControllerImpl extends CurrentUserTracker implemen
mUserSetupUri = Secure.getUriFor(Secure.USER_SETUP_COMPLETE);
mSettingsObserver = new ContentObserver(mainHandler) {
@Override
- public void onChange(boolean selfChange, Uri uri, int userId) {
+ public void onChange(boolean selfChange, Uri uri, int flags) {
Log.d(TAG, "Setting change: " + uri);
if (mUserSetupUri.equals(uri)) {
notifySetupChanged();
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkControllerImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkControllerImpl.java
index d2d76c7e853c..b84208c9ac35 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkControllerImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkControllerImpl.java
@@ -23,7 +23,6 @@ import static android.net.wifi.WifiManager.TrafficStateCallback.DATA_ACTIVITY_IN
import static android.net.wifi.WifiManager.TrafficStateCallback.DATA_ACTIVITY_NONE;
import static android.net.wifi.WifiManager.TrafficStateCallback.DATA_ACTIVITY_OUT;
import static android.telephony.PhoneStateListener.LISTEN_ACTIVE_DATA_SUBSCRIPTION_ID_CHANGE;
-import static android.telephony.TelephonyManager.MODEM_COUNT_DUAL_MODEM;
import android.content.BroadcastReceiver;
import android.content.Context;
@@ -606,7 +605,7 @@ public class NetworkControllerImpl extends BroadcastReceiver
}
private void filterMobileSubscriptionInSameGroup(List<SubscriptionInfo> subscriptions) {
- if (subscriptions.size() == MODEM_COUNT_DUAL_MODEM) {
+ if (subscriptions.size() == 2) {
SubscriptionInfo info1 = subscriptions.get(0);
SubscriptionInfo info2 = subscriptions.get(1);
if (info1.getGroupUuid() != null && info1.getGroupUuid().equals(info2.getGroupUuid())) {
diff --git a/packages/SystemUI/src/com/android/systemui/theme/ThemeOverlayController.java b/packages/SystemUI/src/com/android/systemui/theme/ThemeOverlayController.java
index 31b9952afe94..30db37c4f128 100644
--- a/packages/SystemUI/src/com/android/systemui/theme/ThemeOverlayController.java
+++ b/packages/SystemUI/src/com/android/systemui/theme/ThemeOverlayController.java
@@ -99,8 +99,10 @@ public class ThemeOverlayController extends SystemUI {
Settings.Secure.getUriFor(Settings.Secure.THEME_CUSTOMIZATION_OVERLAY_PACKAGES),
false,
new ContentObserver(mBgHandler) {
+
@Override
- public void onChange(boolean selfChange, Uri uri, int userId) {
+ public void onChange(boolean selfChange, Iterable<Uri> uris, int flags,
+ int userId) {
if (DEBUG) Log.d(TAG, "Overlay changed for user: " + userId);
if (ActivityManager.getCurrentUser() == userId) {
updateThemeOverlays();
diff --git a/packages/SystemUI/src/com/android/systemui/tuner/TunerServiceImpl.java b/packages/SystemUI/src/com/android/systemui/tuner/TunerServiceImpl.java
index 142fdc21aff1..b2a5f5bee543 100644
--- a/packages/SystemUI/src/com/android/systemui/tuner/TunerServiceImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/tuner/TunerServiceImpl.java
@@ -262,10 +262,13 @@ public class TunerServiceImpl extends TunerService {
}
@Override
- public void onChange(boolean selfChange, Uri uri, int userId) {
+ public void onChange(boolean selfChange, Iterable<Uri> uris, int flags, int userId) {
if (userId == ActivityManager.getCurrentUser()) {
- reloadSetting(uri);
+ for (Uri u : uris) {
+ reloadSetting(u);
+ }
}
}
+
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/util/DismissCircleView.java b/packages/SystemUI/src/com/android/systemui/util/DismissCircleView.java
new file mode 100644
index 000000000000..6c3538cb6142
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/util/DismissCircleView.java
@@ -0,0 +1,62 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.util;
+
+import android.content.Context;
+import android.content.res.Configuration;
+import android.content.res.Resources;
+import android.view.Gravity;
+import android.widget.FrameLayout;
+import android.widget.ImageView;
+
+import com.android.systemui.R;
+
+/**
+ * Circular view with a semitransparent, circular background with an 'X' inside it.
+ *
+ * This is used by both Bubbles and PIP as the dismiss target.
+ */
+public class DismissCircleView extends FrameLayout {
+
+ private final ImageView mIconView = new ImageView(getContext());
+
+ public DismissCircleView(Context context) {
+ super(context);
+ final Resources res = getResources();
+
+ setBackground(res.getDrawable(R.drawable.dismiss_circle_background));
+
+ mIconView.setImageDrawable(res.getDrawable(R.drawable.dismiss_target_x));
+ addView(mIconView);
+
+ setViewSizes();
+ }
+
+ @Override
+ protected void onConfigurationChanged(Configuration newConfig) {
+ super.onConfigurationChanged(newConfig);
+ setViewSizes();
+ }
+
+ /** Retrieves the current dimensions for the icon and circle and applies them. */
+ private void setViewSizes() {
+ final Resources res = getResources();
+ final int iconSize = res.getDimensionPixelSize(R.dimen.dismiss_target_x_size);
+ mIconView.setLayoutParams(
+ new FrameLayout.LayoutParams(iconSize, iconSize, Gravity.CENTER));
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/util/magnetictarget/MagnetizedObject.kt b/packages/SystemUI/src/com/android/systemui/util/magnetictarget/MagnetizedObject.kt
index 2276ba19e432..812a1e4bc121 100644
--- a/packages/SystemUI/src/com/android/systemui/util/magnetictarget/MagnetizedObject.kt
+++ b/packages/SystemUI/src/com/android/systemui/util/magnetictarget/MagnetizedObject.kt
@@ -358,7 +358,7 @@ abstract class MagnetizedObject<T : Any>(
targetObjectIsStuckTo = targetObjectIsInMagneticFieldOf
cancelAnimations()
magnetListener.onStuckToTarget(targetObjectIsInMagneticFieldOf!!)
- animateStuckToTarget(targetObjectIsInMagneticFieldOf!!, velX, velY, false)
+ animateStuckToTarget(targetObjectIsInMagneticFieldOf, velX, velY, false)
vibrateIfEnabled(VibrationEffect.EFFECT_HEAVY_CLICK)
} else if (targetObjectIsInMagneticFieldOf == null && objectStuckToTarget) {
diff --git a/packages/SystemUI/src/com/android/systemui/util/sensors/ProximitySensor.java b/packages/SystemUI/src/com/android/systemui/util/sensors/ProximitySensor.java
index 13ba1a3cbf31..378dde284747 100644
--- a/packages/SystemUI/src/com/android/systemui/util/sensors/ProximitySensor.java
+++ b/packages/SystemUI/src/com/android/systemui/util/sensors/ProximitySensor.java
@@ -170,7 +170,11 @@ public class ProximitySensor {
return false;
}
- mListeners.add(listener);
+ if (mListeners.contains(listener)) {
+ Log.d(TAG, "ProxListener registered multiple times: " + listener);
+ } else {
+ mListeners.add(listener);
+ }
registerInternal();
return true;
diff --git a/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogImpl.java b/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogImpl.java
index af218c499d62..ce032e2ceaec 100644
--- a/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogImpl.java
@@ -65,7 +65,6 @@ import android.util.Log;
import android.util.Slog;
import android.util.SparseBooleanArray;
import android.view.ContextThemeWrapper;
-import android.view.Gravity;
import android.view.MotionEvent;
import android.view.View;
import android.view.View.AccessibilityDelegate;
@@ -224,7 +223,7 @@ public class VolumeDialogImpl implements VolumeDialog,
lp.format = PixelFormat.TRANSLUCENT;
lp.setTitle(VolumeDialogImpl.class.getSimpleName());
lp.windowAnimations = -1;
- lp.gravity = Gravity.RIGHT | Gravity.CENTER_VERTICAL;
+ lp.gravity = mContext.getResources().getInteger(R.integer.volume_dialog_gravity);
mWindow.setAttributes(lp);
mWindow.setLayout(WRAP_CONTENT, WRAP_CONTENT);
@@ -825,7 +824,7 @@ public class VolumeDialogImpl implements VolumeDialog,
}
protected void updateRingerH() {
- if (mState != null) {
+ if (mRinger != null && mState != null) {
final StreamState ss = mState.states.get(AudioManager.STREAM_RING);
if (ss == null) {
return;
diff --git a/packages/SystemUI/src/com/android/systemui/wm/DisplayImeController.java b/packages/SystemUI/src/com/android/systemui/wm/DisplayImeController.java
index 1b62cbfabe39..2f1b160ffd4b 100644
--- a/packages/SystemUI/src/com/android/systemui/wm/DisplayImeController.java
+++ b/packages/SystemUI/src/com/android/systemui/wm/DisplayImeController.java
@@ -51,7 +51,7 @@ public class DisplayImeController implements DisplayController.OnDisplaysChanged
public static final int ANIMATION_DURATION_SHOW_MS = 275;
public static final int ANIMATION_DURATION_HIDE_MS = 340;
- static final Interpolator INTERPOLATOR = new PathInterpolator(0.4f, 0f, 0.2f, 1f);
+ public static final Interpolator INTERPOLATOR = new PathInterpolator(0.4f, 0f, 0.2f, 1f);
private static final int DIRECTION_NONE = 0;
private static final int DIRECTION_SHOW = 1;
private static final int DIRECTION_HIDE = 2;
@@ -127,20 +127,20 @@ public class DisplayImeController implements DisplayController.OnDisplaysChanged
}
}
- private void dispatchStartPositioning(int displayId, int imeTop, int finalImeTop,
+ private void dispatchStartPositioning(int displayId, int hiddenTop, int shownTop,
boolean show, SurfaceControl.Transaction t) {
synchronized (mPositionProcessors) {
for (ImePositionProcessor pp : mPositionProcessors) {
- pp.onImeStartPositioning(displayId, imeTop, finalImeTop, show, t);
+ pp.onImeStartPositioning(displayId, hiddenTop, shownTop, show, t);
}
}
}
- private void dispatchEndPositioning(int displayId, int imeTop, boolean show,
+ private void dispatchEndPositioning(int displayId, boolean cancel,
SurfaceControl.Transaction t) {
synchronized (mPositionProcessors) {
for (ImePositionProcessor pp : mPositionProcessors) {
- pp.onImeEndPositioning(displayId, imeTop, show, t);
+ pp.onImeEndPositioning(displayId, cancel, t);
}
}
}
@@ -173,6 +173,7 @@ public class DisplayImeController implements DisplayController.OnDisplaysChanged
int mAnimationDirection = DIRECTION_NONE;
ValueAnimator mAnimation = null;
int mRotation = Surface.ROTATION_0;
+ boolean mImeShowing = false;
PerDisplay(int displayId, int initialRotation) {
mDisplayId = displayId;
@@ -239,23 +240,39 @@ public class DisplayImeController implements DisplayController.OnDisplaysChanged
if (imeSource == null || mImeSourceControl == null) {
return;
}
- if ((mAnimationDirection == DIRECTION_SHOW && show)
- || (mAnimationDirection == DIRECTION_HIDE && !show)) {
- return;
- }
- if (mAnimationDirection != DIRECTION_NONE) {
- mAnimation.end();
- mAnimationDirection = DIRECTION_NONE;
- }
- mAnimationDirection = show ? DIRECTION_SHOW : DIRECTION_HIDE;
mHandler.post(() -> {
+ if ((mAnimationDirection == DIRECTION_SHOW && show)
+ || (mAnimationDirection == DIRECTION_HIDE && !show)) {
+ return;
+ }
+ boolean seek = false;
+ float seekValue = 0;
+ if (mAnimation != null) {
+ if (mAnimation.isRunning()) {
+ seekValue = (float) mAnimation.getAnimatedValue();
+ seek = true;
+ }
+ mAnimation.cancel();
+ }
+ mAnimationDirection = show ? DIRECTION_SHOW : DIRECTION_HIDE;
final float defaultY = mImeSourceControl.getSurfacePosition().y;
final float x = mImeSourceControl.getSurfacePosition().x;
- final float startY = show ? defaultY + imeSource.getFrame().height() : defaultY;
- final float endY = show ? defaultY : defaultY + imeSource.getFrame().height();
+ final float hiddenY = defaultY + imeSource.getFrame().height();
+ final float shownY = defaultY;
+ final float startY = show ? hiddenY : shownY;
+ final float endY = show ? shownY : hiddenY;
+ if (mImeShowing && show) {
+ // IME is already showing, so set seek to end
+ seekValue = shownY;
+ seek = true;
+ }
+ mImeShowing = show;
mAnimation = ValueAnimator.ofFloat(startY, endY);
mAnimation.setDuration(
show ? ANIMATION_DURATION_SHOW_MS : ANIMATION_DURATION_HIDE_MS);
+ if (seek) {
+ mAnimation.setCurrentFraction((seekValue - startY) / (endY - startY));
+ }
mAnimation.addUpdateListener(animation -> {
SurfaceControl.Transaction t = mTransactionPool.acquire();
@@ -267,12 +284,13 @@ public class DisplayImeController implements DisplayController.OnDisplaysChanged
});
mAnimation.setInterpolator(INTERPOLATOR);
mAnimation.addListener(new AnimatorListenerAdapter() {
+ private boolean mCancelled = false;
@Override
public void onAnimationStart(Animator animation) {
SurfaceControl.Transaction t = mTransactionPool.acquire();
t.setPosition(mImeSourceControl.getLeash(), x, startY);
- dispatchStartPositioning(mDisplayId, imeTop(imeSource, startY),
- imeTop(imeSource, endY), mAnimationDirection == DIRECTION_SHOW,
+ dispatchStartPositioning(mDisplayId, imeTop(imeSource, hiddenY),
+ imeTop(imeSource, shownY), mAnimationDirection == DIRECTION_SHOW,
t);
if (mAnimationDirection == DIRECTION_SHOW) {
t.show(mImeSourceControl.getLeash());
@@ -281,12 +299,17 @@ public class DisplayImeController implements DisplayController.OnDisplaysChanged
mTransactionPool.release(t);
}
@Override
+ public void onAnimationCancel(Animator animation) {
+ mCancelled = true;
+ }
+ @Override
public void onAnimationEnd(Animator animation) {
SurfaceControl.Transaction t = mTransactionPool.acquire();
- t.setPosition(mImeSourceControl.getLeash(), x, endY);
- dispatchEndPositioning(mDisplayId, imeTop(imeSource, endY),
- mAnimationDirection == DIRECTION_SHOW, t);
- if (mAnimationDirection == DIRECTION_HIDE) {
+ if (!mCancelled) {
+ t.setPosition(mImeSourceControl.getLeash(), x, endY);
+ }
+ dispatchEndPositioning(mDisplayId, mCancelled, t);
+ if (mAnimationDirection == DIRECTION_HIDE && !mCancelled) {
t.hide(mImeSourceControl.getLeash());
}
t.apply();
@@ -317,21 +340,30 @@ public class DisplayImeController implements DisplayController.OnDisplaysChanged
public interface ImePositionProcessor {
/**
* Called when the IME position is starting to animate.
+ *
+ * @param hiddenTop The y position of the top of the IME surface when it is hidden.
+ * @param shownTop The y position of the top of the IME surface when it is shown.
+ * @param showing {@code true} when we are animating from hidden to shown, {@code false}
+ * when animating from shown to hidden.
*/
- default void onImeStartPositioning(int displayId, int imeTop, int finalImeTop,
+ default void onImeStartPositioning(int displayId, int hiddenTop, int shownTop,
boolean showing, SurfaceControl.Transaction t) {}
/**
* Called when the ime position changed. This is expected to be a synchronous call on the
* animation thread. Operations can be added to the transaction to be applied in sync.
+ *
+ * @param imeTop The current y position of the top of the IME surface.
*/
default void onImePositionChanged(int displayId, int imeTop,
SurfaceControl.Transaction t) {}
/**
* Called when the IME position is done animating.
+ *
+ * @param cancel {@code true} if this was cancelled. This implies another start is coming.
*/
- default void onImeEndPositioning(int displayId, int imeTop, boolean showing,
+ default void onImeEndPositioning(int displayId, boolean cancel,
SurfaceControl.Transaction t) {}
}
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/bubbles/BubbleControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/bubbles/BubbleControllerTest.java
index 742e652a7189..78160c406964 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/bubbles/BubbleControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/bubbles/BubbleControllerTest.java
@@ -399,7 +399,8 @@ public class BubbleControllerTest extends SysuiTestCase {
// Switch which bubble is expanded
mBubbleController.selectBubble(mRow.getEntry().getKey());
mBubbleData.setExpanded(true);
- assertEquals(mRow.getEntry(), stackView.getExpandedBubble().getEntry());
+ assertEquals(mRow.getEntry(),
+ mBubbleData.getBubbleWithKey(stackView.getExpandedBubble().getKey()).getEntry());
assertTrue(mBubbleController.isBubbleNotificationSuppressedFromShade(
mRow.getEntry()));
@@ -492,21 +493,25 @@ public class BubbleControllerTest extends SysuiTestCase {
verify(mBubbleExpandListener).onBubbleExpandChanged(true, mRow2.getEntry().getKey());
// Last added is the one that is expanded
- assertEquals(mRow2.getEntry(), stackView.getExpandedBubble().getEntry());
+ assertEquals(mRow2.getEntry(),
+ mBubbleData.getBubbleWithKey(stackView.getExpandedBubble().getKey()).getEntry());
assertTrue(mBubbleController.isBubbleNotificationSuppressedFromShade(
mRow2.getEntry()));
// Dismiss currently expanded
- mBubbleController.removeBubble(stackView.getExpandedBubble().getEntry(),
+ mBubbleController.removeBubble(
+ mBubbleData.getBubbleWithKey(stackView.getExpandedBubble().getKey()).getEntry(),
BubbleController.DISMISS_USER_GESTURE);
verify(mBubbleExpandListener).onBubbleExpandChanged(false, mRow2.getEntry().getKey());
// Make sure first bubble is selected
- assertEquals(mRow.getEntry(), stackView.getExpandedBubble().getEntry());
+ assertEquals(mRow.getEntry(),
+ mBubbleData.getBubbleWithKey(stackView.getExpandedBubble().getKey()).getEntry());
verify(mBubbleExpandListener).onBubbleExpandChanged(true, mRow.getEntry().getKey());
// Dismiss that one
- mBubbleController.removeBubble(stackView.getExpandedBubble().getEntry(),
+ mBubbleController.removeBubble(
+ mBubbleData.getBubbleWithKey(stackView.getExpandedBubble().getKey()).getEntry(),
BubbleController.DISMISS_USER_GESTURE);
// Make sure state changes and collapse happens
diff --git a/packages/SystemUI/tests/src/com/android/systemui/bubbles/NewNotifPipelineBubbleControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/bubbles/NewNotifPipelineBubbleControllerTest.java
index 22ef3f34cb4d..5ef4cd251f11 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/bubbles/NewNotifPipelineBubbleControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/bubbles/NewNotifPipelineBubbleControllerTest.java
@@ -130,19 +130,15 @@ public class NewNotifPipelineBubbleControllerTest extends SysuiTestCase {
private KeyguardBypassController mKeyguardBypassController;
@Mock
private FloatingContentCoordinator mFloatingContentCoordinator;
-
@Captor
private ArgumentCaptor<NotifCollectionListener> mNotifListenerCaptor;
-
private TestableBubbleController mBubbleController;
private NotificationShadeWindowController mNotificationShadeWindowController;
private NotifCollectionListener mEntryListener;
-
private NotificationTestHelper mNotificationTestHelper;
private ExpandableNotificationRow mRow;
private ExpandableNotificationRow mRow2;
private ExpandableNotificationRow mNonBubbleNotifRow;
-
@Mock
private BubbleController.BubbleStateChangeListener mBubbleStateChangeListener;
@Mock
@@ -309,7 +305,7 @@ public class NewNotifPipelineBubbleControllerTest extends SysuiTestCase {
verify(mNotifCallback, times(1)).invalidateNotifications(anyString());
assertNotNull(mBubbleData.getBubbleWithKey(mRow.getEntry().getKey()));
mBubbleController.updateBubble(mRow2.getEntry());
- verify(mNotifCallback, times(2)).invalidateNotifications(anyString());
+ verify(mNotifCallback, times(2)).invalidateNotifications(anyString());
assertNotNull(mBubbleData.getBubbleWithKey(mRow2.getEntry().getKey()));
assertTrue(mBubbleController.hasBubbles());
@@ -379,7 +375,8 @@ public class NewNotifPipelineBubbleControllerTest extends SysuiTestCase {
// Switch which bubble is expanded
mBubbleController.selectBubble(mRow.getEntry().getKey());
mBubbleData.setExpanded(true);
- assertEquals(mRow.getEntry(), stackView.getExpandedBubble().getEntry());
+ assertEquals(mRow.getEntry(),
+ mBubbleData.getBubbleWithKey(stackView.getExpandedBubble().getKey()).getEntry());
assertTrue(mBubbleController.isBubbleNotificationSuppressedFromShade(
mRow.getEntry()));
@@ -471,21 +468,25 @@ public class NewNotifPipelineBubbleControllerTest extends SysuiTestCase {
verify(mBubbleExpandListener).onBubbleExpandChanged(true, mRow2.getEntry().getKey());
// Last added is the one that is expanded
- assertEquals(mRow2.getEntry(), stackView.getExpandedBubble().getEntry());
+ assertEquals(mRow2.getEntry(),
+ mBubbleData.getBubbleWithKey(stackView.getExpandedBubble().getKey()).getEntry());
assertTrue(mBubbleController.isBubbleNotificationSuppressedFromShade(
mRow2.getEntry()));
// Dismiss currently expanded
- mBubbleController.removeBubble(stackView.getExpandedBubble().getEntry(),
+ mBubbleController.removeBubble(
+ mBubbleData.getBubbleWithKey(stackView.getExpandedBubble().getKey()).getEntry(),
BubbleController.DISMISS_USER_GESTURE);
verify(mBubbleExpandListener).onBubbleExpandChanged(false, mRow2.getEntry().getKey());
// Make sure first bubble is selected
- assertEquals(mRow.getEntry(), stackView.getExpandedBubble().getEntry());
+ assertEquals(mRow.getEntry(),
+ mBubbleData.getBubbleWithKey(stackView.getExpandedBubble().getKey()).getEntry());
verify(mBubbleExpandListener).onBubbleExpandChanged(true, mRow.getEntry().getKey());
// Dismiss that one
- mBubbleController.removeBubble(stackView.getExpandedBubble().getEntry(),
+ mBubbleController.removeBubble(
+ mBubbleData.getBubbleWithKey(stackView.getExpandedBubble().getKey()).getEntry(),
BubbleController.DISMISS_USER_GESTURE);
// Make sure state changes and collapse happens
@@ -645,7 +646,7 @@ public class NewNotifPipelineBubbleControllerTest extends SysuiTestCase {
}
@Test
- public void removeBubble_intercepted() {
+ public void removeBubble_intercepted() {
mEntryListener.onEntryAdded(mRow.getEntry());
mBubbleController.updateBubble(mRow.getEntry());
diff --git a/packages/SystemUI/tests/src/com/android/systemui/bubbles/animation/ExpandedAnimationControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/bubbles/animation/ExpandedAnimationControllerTest.java
index ae4581a80503..ec6d3e9d0dff 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/bubbles/animation/ExpandedAnimationControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/bubbles/animation/ExpandedAnimationControllerTest.java
@@ -17,7 +17,6 @@
package com.android.systemui.bubbles.animation;
import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertNotEquals;
import static org.mockito.Mockito.verify;
import android.content.res.Configuration;
@@ -118,118 +117,6 @@ public class ExpandedAnimationControllerTest extends PhysicsAnimationLayoutTestC
testBubblesInCorrectExpandedPositions();
}
- @Test
- @Ignore
- public void testBubbleDraggedNotDismissedSnapsBack() throws InterruptedException {
- expand();
-
- final View draggedBubble = mViews.get(0);
- mExpandedController.prepareForBubbleDrag(draggedBubble);
- mExpandedController.dragBubbleOut(draggedBubble, 500f, 500f);
-
- assertEquals(500f, draggedBubble.getTranslationX(), 1f);
- assertEquals(500f, draggedBubble.getTranslationY(), 1f);
-
- // Snap it back and make sure it made it back correctly.
- mExpandedController.snapBubbleBack(draggedBubble, 0f, 0f);
- waitForPropertyAnimations(DynamicAnimation.TRANSLATION_X, DynamicAnimation.TRANSLATION_Y);
- testBubblesInCorrectExpandedPositions();
- }
-
- @Test
- @Ignore
- public void testBubbleDismissed() throws InterruptedException {
- expand();
-
- final View draggedBubble = mViews.get(0);
- mExpandedController.prepareForBubbleDrag(draggedBubble);
- mExpandedController.dragBubbleOut(draggedBubble, 500f, 500f);
-
- assertEquals(500f, draggedBubble.getTranslationX(), 1f);
- assertEquals(500f, draggedBubble.getTranslationY(), 1f);
-
- mLayout.removeView(draggedBubble);
- waitForLayoutMessageQueue();
- waitForPropertyAnimations(DynamicAnimation.TRANSLATION_X, DynamicAnimation.TRANSLATION_Y);
-
- assertEquals(-1, mLayout.indexOfChild(draggedBubble));
- testBubblesInCorrectExpandedPositions();
- }
-
- @Test
- @Ignore("Flaky")
- public void testMagnetToDismiss_dismiss() throws InterruptedException {
- expand();
-
- final View draggedOutView = mViews.get(0);
- final Runnable after = Mockito.mock(Runnable.class);
-
- mExpandedController.prepareForBubbleDrag(draggedOutView);
- mExpandedController.dragBubbleOut(draggedOutView, 25, 25);
-
- // Magnet to dismiss, verify the bubble is at the dismiss target and the callback was
- // called.
- mExpandedController.magnetBubbleToDismiss(
- mViews.get(0), 100 /* velX */, 100 /* velY */, 1000 /* destY */, after);
- waitForPropertyAnimations(DynamicAnimation.TRANSLATION_X, DynamicAnimation.TRANSLATION_Y);
- verify(after).run();
- assertEquals(1000, mViews.get(0).getTranslationY(), .1f);
-
- // Dismiss the now-magneted bubble, verify that the callback was called.
- final Runnable afterDismiss = Mockito.mock(Runnable.class);
- mExpandedController.dismissDraggedOutBubble(draggedOutView, afterDismiss);
- waitForPropertyAnimations(DynamicAnimation.ALPHA);
- verify(after).run();
-
- waitForPropertyAnimations(DynamicAnimation.TRANSLATION_X, DynamicAnimation.TRANSLATION_Y);
-
- assertEquals(mBubblePaddingTop, mViews.get(1).getTranslationX(), 1f);
- }
-
- @Test
- @Ignore("Flaky")
- public void testMagnetToDismiss_demagnetizeThenDrag() throws InterruptedException {
- expand();
-
- final View draggedOutView = mViews.get(0);
- final Runnable after = Mockito.mock(Runnable.class);
-
- mExpandedController.prepareForBubbleDrag(draggedOutView);
- mExpandedController.dragBubbleOut(draggedOutView, 25, 25);
-
- // Magnet to dismiss, verify the bubble is at the dismiss target and the callback was
- // called.
- mExpandedController.magnetBubbleToDismiss(
- draggedOutView, 100 /* velX */, 100 /* velY */, 1000 /* destY */, after);
- waitForPropertyAnimations(DynamicAnimation.TRANSLATION_X, DynamicAnimation.TRANSLATION_Y);
- verify(after).run();
- assertEquals(1000, mViews.get(0).getTranslationY(), .1f);
-
- // Demagnetize the bubble towards (25, 25).
- mExpandedController.demagnetizeBubbleTo(25 /* x */, 25 /* y */, 100, 100);
-
- // Start dragging towards (20, 20).
- mExpandedController.dragBubbleOut(draggedOutView, 20, 20);
-
- // Since we just demagnetized, the bubble shouldn't be at (20, 20), it should be animating
- // towards it.
- assertNotEquals(20, draggedOutView.getTranslationX());
- assertNotEquals(20, draggedOutView.getTranslationY());
- waitForPropertyAnimations(DynamicAnimation.TRANSLATION_X, DynamicAnimation.TRANSLATION_Y);
-
- // Waiting for the animations should result in the bubble ending at (20, 20) since the
- // animation end value was updated.
- assertEquals(20, draggedOutView.getTranslationX(), 1f);
- assertEquals(20, draggedOutView.getTranslationY(), 1f);
-
- // Drag to (30, 30).
- mExpandedController.dragBubbleOut(draggedOutView, 30, 30);
-
- // It should go there instantly since the animations finished.
- assertEquals(30, draggedOutView.getTranslationX(), 1f);
- assertEquals(30, draggedOutView.getTranslationY(), 1f);
- }
-
/** Expand the stack and wait for animations to finish. */
private void expand() throws InterruptedException {
mExpandedController.expandFromStack(Mockito.mock(Runnable.class));
diff --git a/packages/SystemUI/tests/src/com/android/systemui/bubbles/animation/StackAnimationControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/bubbles/animation/StackAnimationControllerTest.java
index 9cc034996687..e3187cb9a6c5 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/bubbles/animation/StackAnimationControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/bubbles/animation/StackAnimationControllerTest.java
@@ -17,7 +17,6 @@
package com.android.systemui.bubbles.animation;
import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertNotEquals;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.Mockito.never;
import static org.mockito.Mockito.spy;
@@ -41,7 +40,6 @@ import org.junit.Ignore;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mock;
-import org.mockito.Mockito;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit;
@@ -242,61 +240,6 @@ public class StackAnimationControllerTest extends PhysicsAnimationLayoutTestCase
}
@Test
- @Ignore("Flaky")
- public void testMagnetToDismiss_dismiss() throws InterruptedException {
- final Runnable after = Mockito.mock(Runnable.class);
-
- // Magnet to dismiss, verify the stack is at the dismiss target and the callback was
- // called.
- mStackController.magnetToDismiss(100 /* velX */, 100 /* velY */, 1000 /* destY */, after);
- waitForPropertyAnimations(DynamicAnimation.TRANSLATION_X, DynamicAnimation.TRANSLATION_Y);
- verify(after).run();
- assertEquals(1000, mViews.get(0).getTranslationY(), .1f);
-
- // Dismiss the stack, verify that the callback was called.
- final Runnable afterImplode = Mockito.mock(Runnable.class);
- mStackController.implodeStack(afterImplode);
- waitForPropertyAnimations(
- DynamicAnimation.ALPHA, DynamicAnimation.SCALE_X, DynamicAnimation.SCALE_Y);
- verify(after).run();
- }
-
- @Test
- @Ignore("Flaking")
- public void testMagnetToDismiss_demagnetizeThenDrag() throws InterruptedException {
- final Runnable after = Mockito.mock(Runnable.class);
-
- // Magnet to dismiss, verify the stack is at the dismiss target and the callback was
- // called.
- mStackController.magnetToDismiss(100 /* velX */, 100 /* velY */, 1000 /* destY */, after);
- waitForPropertyAnimations(DynamicAnimation.TRANSLATION_X, DynamicAnimation.TRANSLATION_Y);
- verify(after).run();
-
- assertEquals(1000, mViews.get(0).getTranslationY(), .1f);
-
- // Demagnetize towards (25, 25) and then send a touch event.
- mStackController.demagnetizeFromDismissToPoint(25, 25, 0, 0);
- waitForLayoutMessageQueue();
- mStackController.moveStackFromTouch(20, 20);
-
- // Since the stack is demagnetizing, it shouldn't be at the stack position yet.
- assertNotEquals(20, mStackController.getStackPosition().x, 1f);
- assertNotEquals(20, mStackController.getStackPosition().y, 1f);
-
- waitForPropertyAnimations(DynamicAnimation.TRANSLATION_X, DynamicAnimation.TRANSLATION_Y);
-
- // Once the animation is done it should end at the touch position coordinates.
- assertEquals(20, mStackController.getStackPosition().x, 1f);
- assertEquals(20, mStackController.getStackPosition().y, 1f);
-
- mStackController.moveStackFromTouch(30, 30);
-
- // Touches after the animation are done should change the stack position instantly.
- assertEquals(30, mStackController.getStackPosition().x, 1f);
- assertEquals(30, mStackController.getStackPosition().y, 1f);
- }
-
- @Test
public void testFloatingCoordinator() {
// We should have called onContentAdded only once while adding all of the bubbles in
// setup().
diff --git a/packages/SystemUI/tests/src/com/android/systemui/controls/controller/ControlsControllerImplTest.kt b/packages/SystemUI/tests/src/com/android/systemui/controls/controller/ControlsControllerImplTest.kt
index 45ea3c96b819..c70c56a8660b 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/controls/controller/ControlsControllerImplTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/controls/controller/ControlsControllerImplTest.kt
@@ -234,7 +234,7 @@ class ControlsControllerImplTest : SysuiTestCase() {
loaded = true
assertEquals(1, controls.size)
val controlStatus = controls[0]
- assertEquals(ControlStatus(control, false), controlStatus)
+ assertEquals(ControlStatus(control, TEST_COMPONENT, false), controlStatus)
assertTrue(favorites.isEmpty())
assertFalse(data.errorOnLoad)
@@ -265,10 +265,10 @@ class ControlsControllerImplTest : SysuiTestCase() {
loaded = true
assertEquals(2, controls.size)
val controlStatus = controls.first { it.control.controlId == TEST_CONTROL_ID }
- assertEquals(ControlStatus(control, true), controlStatus)
+ assertEquals(ControlStatus(control, TEST_COMPONENT, true), controlStatus)
val controlStatus2 = controls.first { it.control.controlId == TEST_CONTROL_ID_2 }
- assertEquals(ControlStatus(control2, false), controlStatus2)
+ assertEquals(ControlStatus(control2, TEST_COMPONENT, false), controlStatus2)
assertEquals(1, favorites.size)
assertEquals(TEST_CONTROL_ID, favorites[0])
@@ -340,6 +340,8 @@ class ControlsControllerImplTest : SysuiTestCase() {
controlLoadCallbackCaptor.value.error("")
+ delayableExecutor.runAllReady()
+
assertTrue(loaded)
}
@@ -408,7 +410,7 @@ class ControlsControllerImplTest : SysuiTestCase() {
fun testDisableFeature_notAvailable() {
Settings.Secure.putIntForUser(mContext.contentResolver,
ControlsControllerImpl.CONTROLS_AVAILABLE, 0, user)
- controller.settingObserver.onChange(false, ControlsControllerImpl.URI, 0)
+ controller.settingObserver.onChange(false, listOf(ControlsControllerImpl.URI), 0, 0)
assertFalse(controller.available)
}
@@ -421,7 +423,7 @@ class ControlsControllerImplTest : SysuiTestCase() {
Settings.Secure.putIntForUser(mContext.contentResolver,
ControlsControllerImpl.CONTROLS_AVAILABLE, 0, user)
- controller.settingObserver.onChange(false, ControlsControllerImpl.URI, user)
+ controller.settingObserver.onChange(false, listOf(ControlsControllerImpl.URI), 0, user)
assertTrue(controller.getFavorites().isEmpty())
}
@@ -432,7 +434,7 @@ class ControlsControllerImplTest : SysuiTestCase() {
Settings.Secure.putIntForUser(mContext.contentResolver,
ControlsControllerImpl.CONTROLS_AVAILABLE, 0, otherUser)
- controller.settingObserver.onChange(false, ControlsControllerImpl.URI, otherUser)
+ controller.settingObserver.onChange(false, listOf(ControlsControllerImpl.URI), 0, otherUser)
assertTrue(controller.available)
assertFalse(controller.getFavorites().isEmpty())
@@ -519,7 +521,7 @@ class ControlsControllerImplTest : SysuiTestCase() {
}
@Test
- fun testReplaceFavoritesForStructure_noFavorites() {
+ fun testReplaceFavoritesForStructure_noExistingFavorites() {
controller.replaceFavoritesForStructure(TEST_STRUCTURE_INFO)
delayableExecutor.runAllReady()
@@ -529,6 +531,16 @@ class ControlsControllerImplTest : SysuiTestCase() {
}
@Test
+ fun testReplaceFavoritesForStructure_doNotStoreEmptyStructure() {
+ controller.replaceFavoritesForStructure(
+ StructureInfo(TEST_COMPONENT, "Home", emptyList<ControlInfo>()))
+ delayableExecutor.runAllReady()
+
+ assertEquals(0, controller.countFavoritesForComponent(TEST_COMPONENT))
+ assertEquals(emptyList<ControlInfo>(), controller.getFavoritesForComponent(TEST_COMPONENT))
+ }
+
+ @Test
fun testReplaceFavoritesForStructure_differentComponentsAreFilteredOut() {
controller.replaceFavoritesForStructure(TEST_STRUCTURE_INFO)
controller.replaceFavoritesForStructure(TEST_STRUCTURE_INFO_2)
diff --git a/packages/SystemUI/tests/src/com/android/systemui/controls/management/AllModelTest.kt b/packages/SystemUI/tests/src/com/android/systemui/controls/management/AllModelTest.kt
index 68e1ec1d9f1d..133df2aa203f 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/controls/management/AllModelTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/controls/management/AllModelTest.kt
@@ -17,6 +17,7 @@
package com.android.systemui.controls.management
import android.app.PendingIntent
+import android.content.ComponentName
import android.service.controls.Control
import android.testing.AndroidTestingRunner
import androidx.test.filters.SmallTest
@@ -78,6 +79,7 @@ class AllModelTest : SysuiTestCase() {
Control.StatelessBuilder("$idPrefix$it", pendingIntent)
.setZone(zoneMap(it))
.build(),
+ ComponentName("", ""),
it in favoritesIndices
)
}
@@ -189,4 +191,4 @@ class AllModelTest : SysuiTestCase() {
assertTrue(sameControl(it.first, it.second))
}
}
-} \ No newline at end of file
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/controls/management/ControlsListingControllerImplTest.kt b/packages/SystemUI/tests/src/com/android/systemui/controls/management/ControlsListingControllerImplTest.kt
index 85e937e40acd..13a77083255c 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/controls/management/ControlsListingControllerImplTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/controls/management/ControlsListingControllerImplTest.kt
@@ -30,7 +30,6 @@ import com.android.systemui.util.concurrency.FakeExecutor
import com.android.systemui.util.time.FakeSystemClock
import org.junit.After
import org.junit.Assert.assertEquals
-import org.junit.Assert.assertTrue
import org.junit.Before
import org.junit.Test
import org.junit.runner.RunWith
@@ -38,6 +37,7 @@ import org.mockito.ArgumentCaptor
import org.mockito.Mock
import org.mockito.Mockito
import org.mockito.Mockito.`when`
+import org.mockito.Mockito.inOrder
import org.mockito.Mockito.never
import org.mockito.Mockito.reset
import org.mockito.Mockito.verify
@@ -98,74 +98,18 @@ class ControlsListingControllerImplTest : SysuiTestCase() {
}
@Test
- fun testStartsOnUser() {
- assertEquals(user, controller.currentUserId)
- }
-
- @Test
- fun testNoServices_notListening() {
- assertTrue(controller.getCurrentServices().isEmpty())
- }
-
- @Test
- fun testStartListening_onFirstCallback() {
- controller.addCallback(mockCallback)
- executor.runAllReady()
-
- verify(mockSL).setListening(true)
- }
-
- @Test
- fun testStartListening_onlyOnce() {
- controller.addCallback(mockCallback)
- controller.addCallback(mockCallbackOther)
-
- executor.runAllReady()
-
+ fun testInitialStateListening() {
verify(mockSL).setListening(true)
+ verify(mockSL).reload()
}
@Test
- fun testStopListening_callbackRemoved() {
- controller.addCallback(mockCallback)
-
- executor.runAllReady()
-
- controller.removeCallback(mockCallback)
-
- executor.runAllReady()
-
- verify(mockSL).setListening(false)
- }
-
- @Test
- fun testStopListening_notWhileRemainingCallbacks() {
- controller.addCallback(mockCallback)
- controller.addCallback(mockCallbackOther)
-
- executor.runAllReady()
-
- controller.removeCallback(mockCallback)
-
- executor.runAllReady()
-
- verify(mockSL, never()).setListening(false)
- }
-
- @Test
- fun testReloadOnFirstCallbackAdded() {
- controller.addCallback(mockCallback)
- executor.runAllReady()
-
- verify(mockSL).reload()
+ fun testStartsOnUser() {
+ assertEquals(user, controller.currentUserId)
}
@Test
fun testCallbackCalledWhenAdded() {
- `when`(mockSL.reload()).then {
- serviceListingCallbackCaptor.value.onServicesReloaded(emptyList())
- }
-
controller.addCallback(mockCallback)
executor.runAllReady()
verify(mockCallback).onServicesUpdated(any())
@@ -209,5 +153,11 @@ class ControlsListingControllerImplTest : SysuiTestCase() {
controller.changeUser(UserHandle.of(otherUser))
executor.runAllReady()
assertEquals(otherUser, controller.currentUserId)
+
+ val inOrder = inOrder(mockSL)
+ inOrder.verify(mockSL).setListening(false)
+ inOrder.verify(mockSL).addCallback(any()) // We add a callback because we replaced the SL
+ inOrder.verify(mockSL).setListening(true)
+ inOrder.verify(mockSL).reload()
}
} \ No newline at end of file
diff --git a/packages/SystemUI/tests/src/com/android/systemui/controls/management/ControlsRequestReceiverTest.kt b/packages/SystemUI/tests/src/com/android/systemui/controls/management/ControlsRequestReceiverTest.kt
new file mode 100644
index 000000000000..663f011183ab
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/controls/management/ControlsRequestReceiverTest.kt
@@ -0,0 +1,161 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.controls.management
+
+import android.app.ActivityManager
+import android.app.ActivityManager.RunningAppProcessInfo.IMPORTANCE_FOREGROUND
+import android.app.ActivityManager.RunningAppProcessInfo.IMPORTANCE_GONE
+import android.content.ComponentName
+import android.content.Context
+import android.content.ContextWrapper
+import android.content.Intent
+import android.content.pm.PackageManager
+import android.os.UserHandle
+import android.service.controls.Control
+import android.service.controls.ControlsProviderService
+import android.testing.AndroidTestingRunner
+import androidx.test.filters.SmallTest
+import com.android.systemui.SysuiTestCase
+import org.junit.Assert.assertEquals
+import org.junit.Assert.assertFalse
+import org.junit.Assert.assertNull
+import org.junit.Assert.assertTrue
+import org.junit.Assert.fail
+import org.junit.Before
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.mockito.ArgumentMatchers.anyInt
+import org.mockito.ArgumentMatchers.anyString
+import org.mockito.ArgumentMatchers.eq
+import org.mockito.Mock
+import org.mockito.Mockito.`when`
+import org.mockito.MockitoAnnotations
+
+@SmallTest
+@RunWith(AndroidTestingRunner::class)
+class ControlsRequestReceiverTest : SysuiTestCase() {
+
+ @Mock
+ private lateinit var packageManager: PackageManager
+ @Mock
+ private lateinit var activityManager: ActivityManager
+ @Mock
+ private lateinit var control: Control
+
+ private val componentName = ComponentName("test_pkg", "test_cls")
+ private lateinit var receiver: ControlsRequestReceiver
+ private lateinit var wrapper: MyWrapper
+ private lateinit var intent: Intent
+
+ @Before
+ fun setUp() {
+ MockitoAnnotations.initMocks(this)
+
+ mContext.setMockPackageManager(packageManager)
+ mContext.addMockSystemService(ActivityManager::class.java, activityManager)
+
+ receiver = ControlsRequestReceiver()
+
+ wrapper = MyWrapper(context)
+
+ intent = Intent(ControlsProviderService.ACTION_ADD_CONTROL).apply {
+ putExtra(Intent.EXTRA_COMPONENT_NAME, componentName)
+ putExtra(ControlsProviderService.EXTRA_CONTROL, control)
+ }
+ }
+
+ @Test
+ fun testPackageVerification_nonExistentPackage() {
+ `when`(packageManager.getPackageUid(anyString(), anyInt()))
+ .thenThrow(PackageManager.NameNotFoundException::class.java)
+
+ assertFalse(ControlsRequestReceiver.isPackageInForeground(mContext, "TEST"))
+ }
+
+ @Test
+ fun testPackageVerification_uidNotInForeground() {
+ `when`(packageManager.getPackageUid(anyString(), anyInt())).thenReturn(12345)
+
+ `when`(activityManager.getUidImportance(anyInt())).thenReturn(IMPORTANCE_GONE)
+
+ assertFalse(ControlsRequestReceiver.isPackageInForeground(mContext, "TEST"))
+ }
+
+ @Test
+ fun testPackageVerification_OK() {
+ `when`(packageManager.getPackageUid(anyString(), anyInt())).thenReturn(12345)
+
+ `when`(activityManager.getUidImportance(anyInt())).thenReturn(IMPORTANCE_GONE)
+ `when`(activityManager.getUidImportance(12345)).thenReturn(IMPORTANCE_FOREGROUND)
+
+ assertTrue(ControlsRequestReceiver.isPackageInForeground(mContext, "TEST"))
+ }
+
+ @Test
+ fun testOnReceive_packageNotVerified_nameNotFound() {
+ `when`(packageManager.getPackageUid(eq(componentName.packageName), anyInt()))
+ .thenThrow(PackageManager.NameNotFoundException::class.java)
+
+ receiver.onReceive(wrapper, intent)
+
+ assertNull(wrapper.intent)
+ }
+
+ @Test
+ fun testOnReceive_packageNotVerified_notForeground() {
+ `when`(packageManager.getPackageUid(eq(componentName.packageName), anyInt()))
+ .thenReturn(12345)
+
+ `when`(activityManager.getUidImportance(anyInt())).thenReturn(IMPORTANCE_GONE)
+
+ receiver.onReceive(wrapper, intent)
+
+ assertNull(wrapper.intent)
+ }
+
+ @Test
+ fun testOnReceive_OK() {
+ `when`(packageManager.getPackageUid(eq(componentName.packageName), anyInt()))
+ .thenReturn(12345)
+
+ `when`(activityManager.getUidImportance(eq(12345))).thenReturn(IMPORTANCE_FOREGROUND)
+
+ receiver.onReceive(wrapper, intent)
+
+ wrapper.intent?.let {
+ assertEquals(ComponentName(wrapper, ControlsRequestDialog::class.java), it.component)
+
+ assertEquals(control, it.getParcelableExtra(ControlsProviderService.EXTRA_CONTROL))
+
+ assertEquals(componentName, it.getParcelableExtra(Intent.EXTRA_COMPONENT_NAME))
+ } ?: run { fail("Null start intent") }
+ }
+
+ class MyWrapper(context: Context) : ContextWrapper(context) {
+ var intent: Intent? = null
+
+ override fun startActivityAsUser(intent: Intent, user: UserHandle) {
+ // Always launch activity as system
+ assertTrue(user == UserHandle.SYSTEM)
+ this.intent = intent
+ }
+
+ override fun startActivity(intent: Intent) {
+ this.intent = intent
+ }
+ }
+} \ No newline at end of file
diff --git a/packages/SystemUI/tests/src/com/android/systemui/controls/management/FavoriteModelTest.kt b/packages/SystemUI/tests/src/com/android/systemui/controls/management/FavoriteModelTest.kt
index 9ffc29e0eb7e..c330b38fed42 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/controls/management/FavoriteModelTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/controls/management/FavoriteModelTest.kt
@@ -17,6 +17,7 @@
package com.android.systemui.controls.management
import android.app.PendingIntent
+import android.content.ComponentName
import android.service.controls.Control
import android.testing.AndroidTestingRunner
import androidx.test.filters.SmallTest
@@ -70,6 +71,7 @@ open class FavoriteModelTest : SysuiTestCase() {
Control.StatelessBuilder("$idPrefix$it", pendingIntent)
.setZone((it % 3).toString())
.build(),
+ ComponentName("", ""),
it in favoritesIndices
)
}
@@ -195,4 +197,4 @@ class FavoriteModelParameterizedTest(val from: Int, val to: Int) : FavoriteModel
verifyNoMoreInteractions(allAdapter, favoritesAdapter)
}
-} \ No newline at end of file
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/pip/PipAnimationControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/pip/PipAnimationControllerTest.java
index 6c09a46833a2..a2ab78483b68 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/pip/PipAnimationControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/pip/PipAnimationControllerTest.java
@@ -16,9 +16,10 @@
package com.android.systemui.pip;
+import static com.android.systemui.pip.PipAnimationController.TRANSITION_DIRECTION_TO_FULLSCREEN;
+import static com.android.systemui.pip.PipAnimationController.TRANSITION_DIRECTION_TO_PIP;
+
import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertFalse;
-import static org.junit.Assert.assertTrue;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.verify;
@@ -26,7 +27,6 @@ import static org.mockito.Mockito.verify;
import android.graphics.Rect;
import android.testing.AndroidTestingRunner;
import android.testing.TestableLooper;
-import android.view.IWindowContainer;
import android.view.SurfaceControl;
import androidx.test.filters.SmallTest;
@@ -51,7 +51,7 @@ public class PipAnimationControllerTest extends SysuiTestCase {
private PipAnimationController mPipAnimationController;
@Mock
- private IWindowContainer mWindowContainer;
+ private SurfaceControl mLeash;
@Mock
private PipAnimationController.PipAnimationCallback mPipAnimationCallback;
@@ -65,8 +65,7 @@ public class PipAnimationControllerTest extends SysuiTestCase {
@Test
public void getAnimator_withAlpha_returnFloatAnimator() {
final PipAnimationController.PipTransitionAnimator animator = mPipAnimationController
- .getAnimator(mWindowContainer, true /* scheduleFinishPip */,
- new Rect(), 0f, 1f);
+ .getAnimator(mLeash, new Rect(), 0f, 1f);
assertEquals("Expect ANIM_TYPE_ALPHA animation",
animator.getAnimationType(), PipAnimationController.ANIM_TYPE_ALPHA);
@@ -75,8 +74,7 @@ public class PipAnimationControllerTest extends SysuiTestCase {
@Test
public void getAnimator_withBounds_returnBoundsAnimator() {
final PipAnimationController.PipTransitionAnimator animator = mPipAnimationController
- .getAnimator(mWindowContainer, true /* scheduleFinishPip */,
- new Rect(), new Rect());
+ .getAnimator(mLeash, new Rect(), new Rect());
assertEquals("Expect ANIM_TYPE_BOUNDS animation",
animator.getAnimationType(), PipAnimationController.ANIM_TYPE_BOUNDS);
@@ -88,14 +86,12 @@ public class PipAnimationControllerTest extends SysuiTestCase {
final Rect endValue1 = new Rect(100, 100, 200, 200);
final Rect endValue2 = new Rect(200, 200, 300, 300);
final PipAnimationController.PipTransitionAnimator oldAnimator = mPipAnimationController
- .getAnimator(mWindowContainer, true /* scheduleFinishPip */,
- startValue, endValue1);
+ .getAnimator(mLeash, startValue, endValue1);
oldAnimator.setSurfaceControlTransactionFactory(DummySurfaceControlTx::new);
oldAnimator.start();
final PipAnimationController.PipTransitionAnimator newAnimator = mPipAnimationController
- .getAnimator(mWindowContainer, true /* scheduleFinishPip */,
- startValue, endValue2);
+ .getAnimator(mLeash, startValue, endValue2);
assertEquals("getAnimator with same type returns same animator",
oldAnimator, newAnimator);
@@ -104,26 +100,28 @@ public class PipAnimationControllerTest extends SysuiTestCase {
}
@Test
- public void getAnimator_scheduleFinishPip() {
+ public void getAnimator_setTransitionDirection() {
PipAnimationController.PipTransitionAnimator animator = mPipAnimationController
- .getAnimator(mWindowContainer, true /* scheduleFinishPip */,
- new Rect(), 0f, 1f);
- assertTrue("scheduleFinishPip is true", animator.shouldScheduleFinishPip());
+ .getAnimator(mLeash, new Rect(), 0f, 1f)
+ .setTransitionDirection(TRANSITION_DIRECTION_TO_PIP);
+ assertEquals("Transition to PiP mode",
+ animator.getTransitionDirection(), TRANSITION_DIRECTION_TO_PIP);
animator = mPipAnimationController
- .getAnimator(mWindowContainer, false /* scheduleFinishPip */,
- new Rect(), 0f, 1f);
- assertFalse("scheduleFinishPip is false", animator.shouldScheduleFinishPip());
+ .getAnimator(mLeash, new Rect(), 0f, 1f)
+ .setTransitionDirection(TRANSITION_DIRECTION_TO_FULLSCREEN);
+ assertEquals("Transition to fullscreen mode",
+ animator.getTransitionDirection(), TRANSITION_DIRECTION_TO_FULLSCREEN);
}
@Test
+ @SuppressWarnings("unchecked")
public void pipTransitionAnimator_updateEndValue() {
final Rect startValue = new Rect(0, 0, 100, 100);
final Rect endValue1 = new Rect(100, 100, 200, 200);
final Rect endValue2 = new Rect(200, 200, 300, 300);
final PipAnimationController.PipTransitionAnimator animator = mPipAnimationController
- .getAnimator(mWindowContainer, true /* scheduleFinishPip */,
- startValue, endValue1);
+ .getAnimator(mLeash, startValue, endValue1);
animator.updateEndValue(endValue2);
@@ -135,24 +133,23 @@ public class PipAnimationControllerTest extends SysuiTestCase {
final Rect startValue = new Rect(0, 0, 100, 100);
final Rect endValue = new Rect(100, 100, 200, 200);
final PipAnimationController.PipTransitionAnimator animator = mPipAnimationController
- .getAnimator(mWindowContainer, true /* scheduleFinishPip */,
- startValue, endValue);
+ .getAnimator(mLeash, startValue, endValue);
animator.setSurfaceControlTransactionFactory(DummySurfaceControlTx::new);
animator.setPipAnimationCallback(mPipAnimationCallback);
// onAnimationStart triggers onPipAnimationStart
animator.onAnimationStart(animator);
- verify(mPipAnimationCallback).onPipAnimationStart(mWindowContainer, animator);
+ verify(mPipAnimationCallback).onPipAnimationStart(animator);
// onAnimationCancel triggers onPipAnimationCancel
animator.onAnimationCancel(animator);
- verify(mPipAnimationCallback).onPipAnimationCancel(mWindowContainer, animator);
+ verify(mPipAnimationCallback).onPipAnimationCancel(animator);
// onAnimationEnd triggers onPipAnimationEnd
animator.onAnimationEnd(animator);
- verify(mPipAnimationCallback).onPipAnimationEnd(eq(mWindowContainer),
- any(SurfaceControl.Transaction.class), eq(animator));
+ verify(mPipAnimationCallback).onPipAnimationEnd(any(SurfaceControl.Transaction.class),
+ eq(animator));
}
/**
@@ -176,6 +173,11 @@ public class PipAnimationControllerTest extends SysuiTestCase {
}
@Override
+ public SurfaceControl.Transaction setCornerRadius(SurfaceControl leash, float radius) {
+ return this;
+ }
+
+ @Override
public void apply() {}
}
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/pip/PipBoundsHandlerTest.java b/packages/SystemUI/tests/src/com/android/systemui/pip/PipBoundsHandlerTest.java
index 3b00684786b8..b12db2b44e3d 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/pip/PipBoundsHandlerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/pip/PipBoundsHandlerTest.java
@@ -58,7 +58,7 @@ public class PipBoundsHandlerTest extends SysuiTestCase {
@Before
public void setUp() throws Exception {
initializeMockResources();
- mPipBoundsHandler = new PipBoundsHandler(mContext);
+ mPipBoundsHandler = new PipBoundsHandler(mContext, new PipSnapAlgorithm(mContext));
mPipBoundsHandler.onDisplayInfoChanged(mDefaultDisplayInfo);
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/pip/phone/PipTouchHandlerTest.java b/packages/SystemUI/tests/src/com/android/systemui/pip/phone/PipTouchHandlerTest.java
deleted file mode 100644
index 35abb14070bf..000000000000
--- a/packages/SystemUI/tests/src/com/android/systemui/pip/phone/PipTouchHandlerTest.java
+++ /dev/null
@@ -1,168 +0,0 @@
-/*
- * Copyright (C) 2020 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.systemui.pip.phone;
-
-import static org.junit.Assert.assertEquals;
-import static org.mockito.ArgumentMatchers.any;
-import static org.mockito.ArgumentMatchers.anyInt;
-import static org.mockito.Mockito.times;
-import static org.mockito.Mockito.verify;
-
-import android.app.IActivityManager;
-import android.app.IActivityTaskManager;
-import android.graphics.Point;
-import android.graphics.Rect;
-import android.testing.AndroidTestingRunner;
-import android.testing.TestableLooper;
-import android.util.Size;
-import android.view.DisplayInfo;
-
-import androidx.test.filters.SmallTest;
-
-import com.android.systemui.R;
-import com.android.systemui.SysuiTestCase;
-import com.android.systemui.pip.PipBoundsHandler;
-import com.android.systemui.pip.PipSnapAlgorithm;
-import com.android.systemui.pip.PipTaskOrganizer;
-import com.android.systemui.shared.system.InputConsumerController;
-import com.android.systemui.util.DeviceConfigProxy;
-import com.android.systemui.util.FloatingContentCoordinator;
-
-import org.junit.Before;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.mockito.Mock;
-import org.mockito.Mockito;
-import org.mockito.MockitoAnnotations;
-
-/**
- * Unit tests against {@link PipTouchHandler}, including but not limited to:
- * - Update movement bounds based on new bounds
- * - Update movement bounds based on IME/shelf
- * - Update movement bounds to PipResizeHandler
- */
-@RunWith(AndroidTestingRunner.class)
-@SmallTest
-@TestableLooper.RunWithLooper(setAsMainLooper = true)
-public class PipTouchHandlerTest extends SysuiTestCase {
- private static final int ROUNDING_ERROR_MARGIN = 10;
- private static final float DEFAULT_ASPECT_RATIO = 1f;
- private static final Rect EMPTY_CURRENT_BOUNDS = null;
-
- private PipTouchHandler mPipTouchHandler;
- private DisplayInfo mDefaultDisplayInfo;
-
- @Mock
- private IActivityManager mActivityManager;
-
- @Mock
- private IActivityTaskManager mIActivityTaskManager;
-
- @Mock
- private PipMenuActivityController mPipMenuActivityController;
-
- @Mock
- private InputConsumerController mInputConsumerController;
-
- @Mock
- private PipBoundsHandler mPipBoundsHandler;
-
- @Mock
- private PipTaskOrganizer mPipTaskOrganizer;
-
- @Mock
- private FloatingContentCoordinator mFloatingContentCoordinator;
-
- @Mock
- private DeviceConfigProxy mDeviceConfigProxy;
-
- private PipSnapAlgorithm mPipSnapAlgorithm;
- private PipMotionHelper mMotionHelper;
- private PipResizeGestureHandler mPipResizeGestureHandler;
-
- Rect mInsetBounds;
- Rect mMinBounds;
- Rect mCurBounds;
- boolean mFromImeAdjustment;
- boolean mFromShelfAdjustment;
- int mDisplayRotation;
-
-
- @Before
- public void setUp() throws Exception {
- MockitoAnnotations.initMocks(this);
- mPipTouchHandler = new PipTouchHandler(mContext, mActivityManager, mIActivityTaskManager,
- mPipMenuActivityController, mInputConsumerController, mPipBoundsHandler,
- mPipTaskOrganizer, mFloatingContentCoordinator, mDeviceConfigProxy);
- mPipSnapAlgorithm = new PipSnapAlgorithm(mContext);
- mMotionHelper = Mockito.spy(mPipTouchHandler.getMotionHelper());
- mPipResizeGestureHandler = Mockito.spy(mPipTouchHandler.getPipResizeGestureHandler());
- mPipTouchHandler.setPipMotionHelper(mMotionHelper);
- mPipTouchHandler.setPipResizeGestureHandler(mPipResizeGestureHandler);
-
- // Assume a display of 1000 x 1000
- // inset of 10
- mInsetBounds = new Rect(10, 10, 990, 990);
- // minBounds of 100x100 bottom right corner
- mMinBounds = new Rect(890, 890, 990, 990);
- mCurBounds = new Rect();
- mFromImeAdjustment = false;
- mFromShelfAdjustment = false;
- mDisplayRotation = 0;
- }
-
- @Test
- public void updateMovementBounds_minBounds() {
- Rect expectedMinMovementBounds = new Rect();
- mPipSnapAlgorithm.getMovementBounds(mMinBounds, mInsetBounds, expectedMinMovementBounds, 0);
-
- mPipTouchHandler.onMovementBoundsChanged(mInsetBounds, mMinBounds, mCurBounds,
- mFromImeAdjustment, mFromShelfAdjustment, mDisplayRotation);
-
- assertEquals(expectedMinMovementBounds, mPipTouchHandler.mMinMovementBounds);
- verify(mPipResizeGestureHandler, times(1))
- .updateMinSize(mMinBounds.width(), mMinBounds.height());
- }
-
- @Test
- public void updateMovementBounds_maxBounds() {
- Point displaySize = new Point();
- mContext.getDisplay().getRealSize(displaySize);
- Size maxSize = mPipSnapAlgorithm.getSizeForAspectRatio(1,
- mContext.getResources().getDimensionPixelSize(
- R.dimen.pip_expanded_shortest_edge_size), displaySize.x, displaySize.y);
- Rect maxBounds = new Rect(0, 0, maxSize.getWidth(), maxSize.getHeight());
- Rect expectedMaxMovementBounds = new Rect();
- mPipSnapAlgorithm.getMovementBounds(maxBounds, mInsetBounds, expectedMaxMovementBounds, 0);
-
- mPipTouchHandler.onMovementBoundsChanged(mInsetBounds, mMinBounds, mCurBounds,
- mFromImeAdjustment, mFromShelfAdjustment, mDisplayRotation);
-
- assertEquals(expectedMaxMovementBounds, mPipTouchHandler.mMaxMovementBounds);
- verify(mPipResizeGestureHandler, times(1))
- .updateMaxSize(maxBounds.width(), maxBounds.height());
- }
-
- @Test
- public void updateMovementBounds_withImeAdjustment_movesPip() {
- mFromImeAdjustment = true;
- mPipTouchHandler.onMovementBoundsChanged(mInsetBounds, mMinBounds, mCurBounds,
- mFromImeAdjustment, mFromShelfAdjustment, mDisplayRotation);
-
- verify(mMotionHelper, times(1)).animateToOffset(any(), anyInt());
- }
-}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/QSPanelTest.java b/packages/SystemUI/tests/src/com/android/systemui/qs/QSPanelTest.java
index 45c0cdd6bfd2..616399afe7a4 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/qs/QSPanelTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/qs/QSPanelTest.java
@@ -42,6 +42,7 @@ import com.android.systemui.plugins.qs.QSTileView;
import com.android.systemui.qs.customize.QSCustomizer;
import com.android.systemui.qs.logging.QSLogger;
import com.android.systemui.qs.tileimpl.QSTileImpl;
+import com.android.systemui.statusbar.NotificationMediaManager;
import org.junit.Before;
import org.junit.Test;
@@ -53,6 +54,7 @@ import java.io.FileDescriptor;
import java.io.PrintWriter;
import java.io.StringWriter;
import java.util.Collections;
+import java.util.concurrent.Executor;
@RunWith(AndroidTestingRunner.class)
@RunWithLooper
@@ -79,6 +81,10 @@ public class QSPanelTest extends SysuiTestCase {
private QSDetail.Callback mCallback;
@Mock
private QSTileView mQSTileView;
+ @Mock
+ private NotificationMediaManager mNotificationMediaManager;
+ @Mock
+ private Executor mBackgroundExecutor;
@Before
public void setup() throws Exception {
@@ -88,7 +94,7 @@ public class QSPanelTest extends SysuiTestCase {
mTestableLooper.runWithLooper(() -> {
mMetricsLogger = mDependency.injectMockDependency(MetricsLogger.class);
mQsPanel = new QSPanel(mContext, null, mDumpManager, mBroadcastDispatcher,
- mQSLogger);
+ mQSLogger, mNotificationMediaManager, mBackgroundExecutor);
// Provides a parent with non-zero size for QSPanel
mParentView = new FrameLayout(mContext);
mParentView.addView(mQsPanel);
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/MediaArtworkProcessorTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/MediaArtworkProcessorTest.kt
index a27c085e93a9..72e6df27a254 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/MediaArtworkProcessorTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/MediaArtworkProcessorTest.kt
@@ -16,14 +16,15 @@
package com.android.systemui.statusbar
+import com.google.common.truth.Truth.assertThat
+
import android.graphics.Bitmap
import android.graphics.Canvas
import android.graphics.Color
+import android.graphics.Point
import android.testing.AndroidTestingRunner
-import android.view.WindowManager.LayoutParams.TYPE_NOTIFICATION_SHADE
import androidx.test.filters.SmallTest
import com.android.systemui.SysuiTestCase
-import com.google.common.truth.Truth.assertThat
import org.junit.After
import org.junit.Before
import org.junit.Test
@@ -31,7 +32,6 @@ import org.junit.runner.RunWith
private const val WIDTH = 200
private const val HEIGHT = 200
-private const val WINDOW_TYPE = TYPE_NOTIFICATION_SHADE
@RunWith(AndroidTestingRunner::class)
@SmallTest
@@ -46,10 +46,10 @@ class MediaArtworkProcessorTest : SysuiTestCase() {
fun setUp() {
processor = MediaArtworkProcessor()
- val size = processor.getWindowSize(context, WINDOW_TYPE)
-
- screenWidth = size.width
- screenHeight = size.height
+ val point = Point()
+ context.display.getSize(point)
+ screenWidth = point.x
+ screenHeight = point.y
}
@After
@@ -63,7 +63,7 @@ class MediaArtworkProcessorTest : SysuiTestCase() {
val artwork = Bitmap.createBitmap(WIDTH, HEIGHT, Bitmap.Config.ARGB_8888)
Canvas(artwork).drawColor(Color.BLUE)
// WHEN the background is created from the artwork
- val background = processor.processArtwork(context, artwork, WINDOW_TYPE)!!
+ val background = processor.processArtwork(context, artwork)!!
// THEN the background has the size of the screen that has been downsamples
assertThat(background.height).isLessThan(screenHeight)
assertThat(background.width).isLessThan(screenWidth)
@@ -76,8 +76,8 @@ class MediaArtworkProcessorTest : SysuiTestCase() {
val artwork = Bitmap.createBitmap(WIDTH, HEIGHT, Bitmap.Config.ARGB_8888)
Canvas(artwork).drawColor(Color.BLUE)
// WHEN the background is processed twice
- val background1 = processor.processArtwork(context, artwork, WINDOW_TYPE)!!
- val background2 = processor.processArtwork(context, artwork, WINDOW_TYPE)!!
+ val background1 = processor.processArtwork(context, artwork)!!
+ val background2 = processor.processArtwork(context, artwork)!!
// THEN the two bitmaps are the same
// Note: This is currently broken and trying to use caching causes issues
assertThat(background1).isNotSameAs(background2)
@@ -89,7 +89,7 @@ class MediaArtworkProcessorTest : SysuiTestCase() {
val artwork = Bitmap.createBitmap(WIDTH, HEIGHT, Bitmap.Config.ALPHA_8)
Canvas(artwork).drawColor(Color.BLUE)
// WHEN the background is created from the artwork
- val background = processor.processArtwork(context, artwork, WINDOW_TYPE)!!
+ val background = processor.processArtwork(context, artwork)!!
// THEN the background has Config ARGB_8888
assertThat(background.config).isEqualTo(Bitmap.Config.ARGB_8888)
}
@@ -102,7 +102,7 @@ class MediaArtworkProcessorTest : SysuiTestCase() {
// AND the artwork is recycled
artwork.recycle()
// WHEN the background is created from the artwork
- val background = processor.processArtwork(context, artwork, WINDOW_TYPE)
+ val background = processor.processArtwork(context, artwork)
// THEN the processed bitmap is null
assertThat(background).isNull()
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/SbnBuilder.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/SbnBuilder.java
index 62f406ff835a..1b0ed112cea1 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/SbnBuilder.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/SbnBuilder.java
@@ -22,6 +22,8 @@ import android.content.Context;
import android.os.UserHandle;
import android.service.notification.StatusBarNotification;
+import com.android.internal.logging.InstanceId;
+
/**
* Convenience builder for {@link StatusBarNotification} since its constructor is terrifying.
*
@@ -40,6 +42,7 @@ public class SbnBuilder {
private UserHandle mUser = UserHandle.of(0);
private String mOverrideGroupKey;
private long mPostTime;
+ private InstanceId mInstanceId;
public SbnBuilder() {
}
@@ -55,6 +58,7 @@ public class SbnBuilder {
mUser = source.getUser();
mOverrideGroupKey = source.getOverrideGroupKey();
mPostTime = source.getPostTime();
+ mInstanceId = source.getInstanceId();
}
public StatusBarNotification build() {
@@ -71,7 +75,7 @@ public class SbnBuilder {
notification.setBubbleMetadata(mBubbleMetadata);
}
- return new StatusBarNotification(
+ StatusBarNotification result = new StatusBarNotification(
mPkg,
mOpPkg,
mId,
@@ -82,6 +86,10 @@ public class SbnBuilder {
mUser,
mOverrideGroupKey,
mPostTime);
+ if (mInstanceId != null) {
+ result.setInstanceId(mInstanceId);
+ }
+ return result;
}
public SbnBuilder setPkg(String pkg) {
@@ -175,4 +183,9 @@ public class SbnBuilder {
mBubbleMetadata = data;
return this;
}
+
+ public SbnBuilder setInstanceId(InstanceId instanceId) {
+ mInstanceId = instanceId;
+ return this;
+ }
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/HighPriorityProviderTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/HighPriorityProviderTest.java
index e4865b633083..78e9b336f79a 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/HighPriorityProviderTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/HighPriorityProviderTest.java
@@ -20,6 +20,9 @@ import static android.app.NotificationManager.IMPORTANCE_HIGH;
import static android.app.NotificationManager.IMPORTANCE_LOW;
import static android.app.NotificationManager.IMPORTANCE_MIN;
+import static com.android.systemui.statusbar.notification.people.PeopleNotificationIdentifier.TYPE_NON_PERSON;
+import static com.android.systemui.statusbar.notification.people.PeopleNotificationIdentifier.TYPE_PERSON;
+
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
import static org.mockito.Mockito.mock;
@@ -60,8 +63,9 @@ public class HighPriorityProviderTest extends SysuiTestCase {
final NotificationEntry entry = new NotificationEntryBuilder()
.setImportance(IMPORTANCE_HIGH)
.build();
- when(mPeopleNotificationIdentifier.isPeopleNotification(entry.getSbn(), entry.getRanking()))
- .thenReturn(false);
+ when(mPeopleNotificationIdentifier
+ .getPeopleNotificationType(entry.getSbn(), entry.getRanking()))
+ .thenReturn(TYPE_NON_PERSON);
// THEN it has high priority
assertTrue(mHighPriorityProvider.isHighPriority(entry));
@@ -76,8 +80,9 @@ public class HighPriorityProviderTest extends SysuiTestCase {
.setNotification(notification)
.setImportance(IMPORTANCE_LOW)
.build();
- when(mPeopleNotificationIdentifier.isPeopleNotification(entry.getSbn(), entry.getRanking()))
- .thenReturn(true);
+ when(mPeopleNotificationIdentifier
+ .getPeopleNotificationType(entry.getSbn(), entry.getRanking()))
+ .thenReturn(TYPE_PERSON);
// THEN it has high priority
assertTrue(mHighPriorityProvider.isHighPriority(entry));
@@ -92,8 +97,9 @@ public class HighPriorityProviderTest extends SysuiTestCase {
final NotificationEntry entry = new NotificationEntryBuilder()
.setNotification(notification)
.build();
- when(mPeopleNotificationIdentifier.isPeopleNotification(entry.getSbn(), entry.getRanking()))
- .thenReturn(false);
+ when(mPeopleNotificationIdentifier
+ .getPeopleNotificationType(entry.getSbn(), entry.getRanking()))
+ .thenReturn(TYPE_NON_PERSON);
// THEN it has high priority
assertTrue(mHighPriorityProvider.isHighPriority(entry));
@@ -109,8 +115,9 @@ public class HighPriorityProviderTest extends SysuiTestCase {
.setNotification(notification)
.setImportance(IMPORTANCE_LOW)
.build();
- when(mPeopleNotificationIdentifier.isPeopleNotification(entry.getSbn(), entry.getRanking()))
- .thenReturn(false);
+ when(mPeopleNotificationIdentifier
+ .getPeopleNotificationType(entry.getSbn(), entry.getRanking()))
+ .thenReturn(TYPE_NON_PERSON);
// THEN it has high priority
assertTrue(mHighPriorityProvider.isHighPriority(entry));
@@ -126,8 +133,9 @@ public class HighPriorityProviderTest extends SysuiTestCase {
.setNotification(notification)
.setImportance(IMPORTANCE_MIN)
.build();
- when(mPeopleNotificationIdentifier.isPeopleNotification(entry.getSbn(), entry.getRanking()))
- .thenReturn(false);
+ when(mPeopleNotificationIdentifier
+ .getPeopleNotificationType(entry.getSbn(), entry.getRanking()))
+ .thenReturn(TYPE_NON_PERSON);
// THEN it does NOT have high priority
assertFalse(mHighPriorityProvider.isHighPriority(entry));
@@ -149,8 +157,9 @@ public class HighPriorityProviderTest extends SysuiTestCase {
.setNotification(notification)
.setChannel(channel)
.build();
- when(mPeopleNotificationIdentifier.isPeopleNotification(entry.getSbn(), entry.getRanking()))
- .thenReturn(true);
+ when(mPeopleNotificationIdentifier
+ .getPeopleNotificationType(entry.getSbn(), entry.getRanking()))
+ .thenReturn(TYPE_PERSON);
// THEN it does NOT have high priority
assertFalse(mHighPriorityProvider.isHighPriority(entry));
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/NotificationEntryBuilder.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/NotificationEntryBuilder.java
index 92a908033472..261dc829c7e2 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/NotificationEntryBuilder.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/NotificationEntryBuilder.java
@@ -26,6 +26,7 @@ import android.os.UserHandle;
import android.service.notification.SnoozeCriterion;
import android.service.notification.StatusBarNotification;
+import com.android.internal.logging.InstanceId;
import com.android.systemui.statusbar.RankingBuilder;
import com.android.systemui.statusbar.SbnBuilder;
@@ -141,6 +142,11 @@ public class NotificationEntryBuilder {
return this;
}
+ public NotificationEntryBuilder setInstanceId(InstanceId instanceId) {
+ mSbnBuilder.setInstanceId(instanceId);
+ return this;
+ }
+
/* Delegated to Notification.Builder (via SbnBuilder) */
public NotificationEntryBuilder setContentTitle(Context context, String contentTitle) {
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/NotificationRankingManagerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/NotificationRankingManagerTest.kt
index 5a6f888b53ed..cdf0f2d67c1a 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/NotificationRankingManagerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/NotificationRankingManagerTest.kt
@@ -32,6 +32,8 @@ import com.android.systemui.statusbar.notification.NotificationFilter
import com.android.systemui.statusbar.notification.NotificationSectionsFeatureManager
import com.android.systemui.statusbar.notification.collection.provider.HighPriorityProvider
import com.android.systemui.statusbar.notification.people.PeopleNotificationIdentifier
+import com.android.systemui.statusbar.notification.people.PeopleNotificationIdentifier.Companion.TYPE_IMPORTANT_PERSON
+import com.android.systemui.statusbar.notification.people.PeopleNotificationIdentifier.Companion.TYPE_PERSON
import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow
import com.android.systemui.statusbar.notification.stack.NotificationSectionsManager.BUCKET_ALERTING
import com.android.systemui.statusbar.notification.stack.NotificationSectionsManager.BUCKET_SILENT
@@ -166,10 +168,8 @@ class NotificationRankingManagerTest : SysuiTestCase() {
.setOverrideGroupKey("")
.build()
- whenever(personNotificationIdentifier.isImportantPeopleNotification(a.sbn, a.ranking))
- .thenReturn(true)
- whenever(personNotificationIdentifier.isPeopleNotification(a.sbn, a.ranking))
- .thenReturn(true)
+ whenever(personNotificationIdentifier.getPeopleNotificationType(a.sbn, a.ranking))
+ .thenReturn(TYPE_IMPORTANT_PERSON)
val bN = Notification.Builder(mContext, "test")
.setStyle(Notification.MessagingStyle(""))
@@ -188,10 +188,8 @@ class NotificationRankingManagerTest : SysuiTestCase() {
whenever(it.isHeadsUp).thenReturn(true)
}
- whenever(personNotificationIdentifier.isImportantPeopleNotification(a.sbn, a.ranking))
- .thenReturn(false)
- whenever(personNotificationIdentifier.isPeopleNotification(a.sbn, a.ranking))
- .thenReturn(false)
+ whenever(personNotificationIdentifier.getPeopleNotificationType(a.sbn, a.ranking))
+ .thenReturn(TYPE_PERSON)
assertEquals(listOf(b, a), rankingManager.updateRanking(null, listOf(a, b), "test"))
}
@@ -213,10 +211,8 @@ class NotificationRankingManagerTest : SysuiTestCase() {
.setUser(mContext.user)
.setOverrideGroupKey("")
.build()
- whenever(personNotificationIdentifier.isImportantPeopleNotification(a.sbn, a.ranking))
- .thenReturn(false)
- whenever(personNotificationIdentifier.isPeopleNotification(a.sbn, a.ranking))
- .thenReturn(true)
+ whenever(personNotificationIdentifier.getPeopleNotificationType(a.sbn, a.ranking))
+ .thenReturn(TYPE_PERSON)
val bN = Notification.Builder(mContext, "test")
.setStyle(Notification.MessagingStyle(""))
@@ -231,10 +227,8 @@ class NotificationRankingManagerTest : SysuiTestCase() {
.setUser(mContext.user)
.setOverrideGroupKey("")
.build()
- whenever(personNotificationIdentifier.isImportantPeopleNotification(b.sbn, b.ranking))
- .thenReturn(true)
- whenever(personNotificationIdentifier.isPeopleNotification(b.sbn, b.ranking))
- .thenReturn(true)
+ whenever(personNotificationIdentifier.getPeopleNotificationType(b.sbn, b.ranking))
+ .thenReturn(TYPE_IMPORTANT_PERSON)
assertEquals(
listOf(b, a),
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/logging/NotificationLoggerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/logging/NotificationLoggerTest.java
index d826ce1bbdd8..d39b2c202fd9 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/logging/NotificationLoggerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/logging/NotificationLoggerTest.java
@@ -16,7 +16,10 @@
package com.android.systemui.statusbar.notification.logging;
+import static com.android.systemui.statusbar.notification.stack.NotificationSectionsManager.BUCKET_ALERTING;
+
import static org.junit.Assert.assertArrayEquals;
+import static org.junit.Assert.assertEquals;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.Mockito.doAnswer;
import static org.mockito.Mockito.mock;
@@ -34,6 +37,7 @@ import android.testing.TestableLooper;
import androidx.test.filters.SmallTest;
+import com.android.internal.logging.InstanceId;
import com.android.internal.statusbar.IStatusBarService;
import com.android.internal.statusbar.NotificationVisibility;
import com.android.systemui.SysuiTestCase;
@@ -43,6 +47,7 @@ import com.android.systemui.statusbar.notification.NotificationEntryListener;
import com.android.systemui.statusbar.notification.NotificationEntryManager;
import com.android.systemui.statusbar.notification.collection.NotificationEntry;
import com.android.systemui.statusbar.notification.collection.NotificationEntryBuilder;
+import com.android.systemui.statusbar.notification.logging.nano.Notifications;
import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow;
import com.android.systemui.statusbar.notification.stack.NotificationListContainer;
import com.android.systemui.util.concurrency.FakeExecutor;
@@ -81,9 +86,10 @@ public class NotificationLoggerTest extends SysuiTestCase {
private NotificationEntry mEntry;
private TestableNotificationLogger mLogger;
- private NotificationEntryListener mNotificationEntryListener;
private ConcurrentLinkedQueue<AssertionError> mErrorQueue = new ConcurrentLinkedQueue<>();
private FakeExecutor mUiBgExecutor = new FakeExecutor(new FakeSystemClock());
+ private NotificationPanelLoggerFake mNotificationPanelLoggerFake =
+ new NotificationPanelLoggerFake();
@Before
public void setUp() {
@@ -97,6 +103,7 @@ public class NotificationLoggerTest extends SysuiTestCase {
.setUid(TEST_UID)
.setNotification(new Notification())
.setUser(UserHandle.CURRENT)
+ .setInstanceId(InstanceId.fakeInstanceId(1))
.build();
mEntry.setRow(mRow);
@@ -105,7 +112,6 @@ public class NotificationLoggerTest extends SysuiTestCase {
mExpansionStateLogger);
mLogger.setUpWithContainer(mListContainer);
verify(mEntryManager).addNotificationEntryListener(mEntryListenerCaptor.capture());
- mNotificationEntryListener = mEntryListenerCaptor.getValue();
}
@Test
@@ -164,6 +170,41 @@ public class NotificationLoggerTest extends SysuiTestCase {
verify(mBarService, times(1)).onNotificationVisibilityChanged(any(), any());
}
+ @Test
+ public void testLogPanelShownOnLoggingStart() {
+ when(mEntryManager.getVisibleNotifications()).thenReturn(Lists.newArrayList(mEntry));
+ mLogger.startNotificationLogging();
+ assertEquals(1, mNotificationPanelLoggerFake.getCalls().size());
+ assertEquals(false, mNotificationPanelLoggerFake.get(0).isLockscreen);
+ assertEquals(1, mNotificationPanelLoggerFake.get(0).list.notifications.length);
+ Notifications.Notification n = mNotificationPanelLoggerFake.get(0).list.notifications[0];
+ assertEquals(TEST_PACKAGE_NAME, n.packageName);
+ assertEquals(TEST_UID, n.uid);
+ assertEquals(1, n.instanceId);
+ assertEquals(false, n.isGroupSummary);
+ assertEquals(1 + BUCKET_ALERTING, n.section);
+ }
+
+ @Test
+ public void testLogPanelShownHandlesNullInstanceIds() {
+ // Construct a NotificationEntry like mEntry, but with a null instance id.
+ NotificationEntry entry = new NotificationEntryBuilder()
+ .setPkg(TEST_PACKAGE_NAME)
+ .setOpPkg(TEST_PACKAGE_NAME)
+ .setUid(TEST_UID)
+ .setNotification(new Notification())
+ .setUser(UserHandle.CURRENT)
+ .build();
+ entry.setRow(mRow);
+
+ when(mEntryManager.getVisibleNotifications()).thenReturn(Lists.newArrayList(entry));
+ mLogger.startNotificationLogging();
+ assertEquals(1, mNotificationPanelLoggerFake.getCalls().size());
+ assertEquals(1, mNotificationPanelLoggerFake.get(0).list.notifications.length);
+ Notifications.Notification n = mNotificationPanelLoggerFake.get(0).list.notifications[0];
+ assertEquals(0, n.instanceId);
+ }
+
private class TestableNotificationLogger extends NotificationLogger {
TestableNotificationLogger(NotificationListener notificationListener,
@@ -173,7 +214,7 @@ public class NotificationLoggerTest extends SysuiTestCase {
IStatusBarService barService,
ExpansionStateLogger expansionStateLogger) {
super(notificationListener, uiBgExecutor, entryManager, statusBarStateController,
- expansionStateLogger);
+ expansionStateLogger, mNotificationPanelLoggerFake);
mBarService = barService;
// Make this on the current thread so we can wait for it during tests.
mHandler = Handler.createAsync(Looper.myLooper());
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/logging/NotificationPanelLoggerFake.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/logging/NotificationPanelLoggerFake.java
new file mode 100644
index 000000000000..7e97629e82e2
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/logging/NotificationPanelLoggerFake.java
@@ -0,0 +1,51 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.statusbar.notification.logging;
+
+import com.android.systemui.statusbar.notification.collection.NotificationEntry;
+import com.android.systemui.statusbar.notification.logging.nano.Notifications;
+
+import java.util.ArrayList;
+import java.util.List;
+
+public class NotificationPanelLoggerFake implements NotificationPanelLogger {
+ private List<CallRecord> mCalls = new ArrayList<>();
+
+ List<CallRecord> getCalls() {
+ return mCalls;
+ }
+
+ CallRecord get(int index) {
+ return mCalls.get(index);
+ }
+
+ @Override
+ public void logPanelShown(boolean isLockscreen,
+ List<NotificationEntry> visibleNotifications) {
+ mCalls.add(new CallRecord(isLockscreen,
+ NotificationPanelLogger.toNotificationProto(visibleNotifications)));
+ }
+
+ public static class CallRecord {
+ public boolean isLockscreen;
+ public Notifications.NotificationList list;
+ CallRecord(boolean isLockscreen, Notifications.NotificationList list) {
+ this.isLockscreen = isLockscreen;
+ this.list = list;
+ }
+ }
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/people/PeopleHubViewControllerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/people/PeopleHubViewControllerTest.kt
index b1288f8c33f4..79fa43604c38 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/people/PeopleHubViewControllerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/people/PeopleHubViewControllerTest.kt
@@ -16,8 +16,6 @@
package com.android.systemui.statusbar.notification.people
-import android.app.PendingIntent
-import android.content.Intent
import android.graphics.drawable.Drawable
import android.testing.AndroidTestingRunner
import android.view.View
@@ -151,7 +149,7 @@ private fun fakePersonModel(
clickRunnable: Runnable,
userId: Int = 0
): PersonModel =
- PersonModel(id, name, mock(Drawable::class.java), clickRunnable, userId)
+ PersonModel(id, userId, name, mock(Drawable::class.java), clickRunnable)
private fun fakePersonViewModel(name: CharSequence): PersonViewModel =
PersonViewModel(name, mock(Drawable::class.java), mock({}.javaClass))
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationEntryManagerInflationTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationEntryManagerInflationTest.java
index 2c9fd2c64291..5d0349dbbb60 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationEntryManagerInflationTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationEntryManagerInflationTest.java
@@ -64,6 +64,7 @@ import com.android.systemui.statusbar.notification.collection.inflation.Notifica
import com.android.systemui.statusbar.notification.collection.provider.HighPriorityProvider;
import com.android.systemui.statusbar.notification.logging.NotificationLogger;
import com.android.systemui.statusbar.notification.people.PeopleNotificationIdentifier;
+import com.android.systemui.statusbar.notification.row.NotificationRowContentBinder.InflationFlag;
import com.android.systemui.statusbar.notification.row.dagger.ExpandableNotificationRowComponent;
import com.android.systemui.statusbar.notification.row.dagger.NotificationRowComponent;
import com.android.systemui.statusbar.notification.stack.NotificationListContainer;
@@ -76,6 +77,7 @@ import com.android.systemui.util.time.FakeSystemClock;
import org.junit.After;
import org.junit.Before;
+import org.junit.Ignore;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.ArgumentCaptor;
@@ -84,12 +86,11 @@ import org.mockito.Mockito;
import org.mockito.MockitoAnnotations;
import org.mockito.stubbing.Answer;
-import java.util.concurrent.CountDownLatch;
-
/**
* Functional tests for notification inflation from {@link NotificationEntryManager}.
*/
@SmallTest
+@Ignore("Flaking")
@RunWith(AndroidTestingRunner.class)
@TestableLooper.RunWithLooper(setAsMainLooper = true)
public class NotificationEntryManagerInflationTest extends SysuiTestCase {
@@ -131,7 +132,6 @@ public class NotificationEntryManagerInflationTest extends SysuiTestCase {
private NotificationEntryManager mEntryManager;
private NotificationRowBinderImpl mRowBinder;
private Handler mHandler;
- private CountDownLatch mCountDownLatch;
@Before
public void setUp() {
@@ -305,7 +305,9 @@ public class NotificationEntryManagerInflationTest extends SysuiTestCase {
verify(mEntryListener).onPendingEntryAdded(entryCaptor.capture());
NotificationEntry entry = entryCaptor.getValue();
- waitForInflation();
+ // Wait for inflation
+ // row inflation, system notification, remote views, contracted view
+ waitForMessages(4);
// THEN the notification has its row inflated
assertNotNull(entry.getRow());
@@ -332,7 +334,7 @@ public class NotificationEntryManagerInflationTest extends SysuiTestCase {
NotificationEntry.class);
verify(mEntryListener).onPendingEntryAdded(entryCaptor.capture());
NotificationEntry entry = entryCaptor.getValue();
- waitForInflation();
+ waitForMessages(4);
Mockito.reset(mEntryListener);
Mockito.reset(mPresenter);
@@ -340,7 +342,9 @@ public class NotificationEntryManagerInflationTest extends SysuiTestCase {
// WHEN the notification is updated
mEntryManager.updateNotification(mSbn, mRankingMap);
- waitForInflation();
+ // Wait for inflation
+ // remote views, contracted view
+ waitForMessages(2);
// THEN the notification has its row and inflated
assertNotNull(entry.getRow());
@@ -353,31 +357,32 @@ public class NotificationEntryManagerInflationTest extends SysuiTestCase {
verify(mPresenter).updateNotificationViews();
}
- private void waitForInflation() {
+ /**
+ * Wait for a certain number of messages to finish before continuing, timing out if they never
+ * occur.
+ *
+ * As part of the inflation pipeline, the main thread is forced to deal with several callbacks
+ * due to the nature of the API used (generally because they're {@link android.os.AsyncTask}
+ * callbacks). In order, these are
+ *
+ * 1) Callback after row inflation. See {@link RowInflaterTask}.
+ * 2) Callback checking if row is system notification. See
+ * {@link ExpandableNotificationRow#setEntry}
+ * 3) Callback after remote views are created. See
+ * {@link NotificationContentInflater.AsyncInflationTask}.
+ * 4-6) Callback after each content view is inflated/rebound from remote view. See
+ * {@link NotificationContentInflater#applyRemoteView} and {@link InflationFlag}.
+ *
+ * Depending on the test, only some of these will be necessary. For example, generally, not
+ * every content view is inflated or the row may not be inflated if one already exists.
+ *
+ * Currently, the burden is on the developer to figure these out until we have a much more
+ * test-friendly way of executing inflation logic (i.e. pass in an executor).
+ */
+ private void waitForMessages(int numMessages) {
mHandler.postDelayed(TIMEOUT_RUNNABLE, TIMEOUT_TIME);
- final CountDownLatch latch = new CountDownLatch(1);
- NotificationEntryListener inflationListener = new NotificationEntryListener() {
- @Override
- public void onEntryInflated(NotificationEntry entry) {
- latch.countDown();
- }
-
- @Override
- public void onEntryReinflated(NotificationEntry entry) {
- latch.countDown();
- }
-
- @Override
- public void onInflationError(StatusBarNotification notification, Exception exception) {
- latch.countDown();
- }
- };
- mEntryManager.addNotificationEntryListener(inflationListener);
- while (latch.getCount() != 0) {
- TestableLooper.get(this).processMessages(1);
- }
+ TestableLooper.get(this).processMessages(numMessages);
mHandler.removeCallbacks(TIMEOUT_RUNNABLE);
- mEntryManager.removeNotificationEntryListener(inflationListener);
}
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationGutsManagerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationGutsManagerTest.java
index 54c0bde13408..e9dca699917c 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationGutsManagerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationGutsManagerTest.java
@@ -316,74 +316,9 @@ public class NotificationGutsManagerTest extends SysuiTestCase {
}
@Test
- public void testInitializeNotificationInfoView_showBlockingHelper() throws Exception {
- NotificationInfo notificationInfoView = mock(NotificationInfo.class);
- ExpandableNotificationRow row = spy(mHelper.createRow());
- row.setBlockingHelperShowing(true);
- modifyRanking(row.getEntry())
- .setUserSentiment(USER_SENTIMENT_NEGATIVE)
- .build();
- when(row.getIsNonblockable()).thenReturn(false);
- StatusBarNotification statusBarNotification = row.getEntry().getSbn();
- NotificationEntry entry = row.getEntry();
-
- mGutsManager.initializeNotificationInfo(row, notificationInfoView);
-
- verify(notificationInfoView).bindNotification(
- any(PackageManager.class),
- any(INotificationManager.class),
- eq(mVisualStabilityManager),
- eq(statusBarNotification.getPackageName()),
- any(NotificationChannel.class),
- anySet(),
- eq(entry),
- any(NotificationInfo.CheckSaveListener.class),
- any(NotificationInfo.OnSettingsClickListener.class),
- any(NotificationInfo.OnAppSettingsClickListener.class),
- eq(false),
- eq(false),
- eq(true) /* isForBlockingHelper */,
- eq(0),
- eq(false) /* wasShownHighPriority */);
- }
-
- @Test
- public void testInitializeNotificationInfoView_dontShowBlockingHelper() throws Exception {
- NotificationInfo notificationInfoView = mock(NotificationInfo.class);
- ExpandableNotificationRow row = spy(mHelper.createRow());
- row.setBlockingHelperShowing(false);
- modifyRanking(row.getEntry())
- .setUserSentiment(USER_SENTIMENT_NEGATIVE)
- .build();
- when(row.getIsNonblockable()).thenReturn(false);
- StatusBarNotification statusBarNotification = row.getEntry().getSbn();
- NotificationEntry entry = row.getEntry();
-
- mGutsManager.initializeNotificationInfo(row, notificationInfoView);
-
- verify(notificationInfoView).bindNotification(
- any(PackageManager.class),
- any(INotificationManager.class),
- eq(mVisualStabilityManager),
- eq(statusBarNotification.getPackageName()),
- any(NotificationChannel.class),
- anySet(),
- eq(entry),
- any(NotificationInfo.CheckSaveListener.class),
- any(NotificationInfo.OnSettingsClickListener.class),
- any(NotificationInfo.OnAppSettingsClickListener.class),
- eq(false),
- eq(false),
- eq(false) /* isForBlockingHelper */,
- eq(0),
- eq(false) /* wasShownHighPriority */);
- }
-
- @Test
public void testInitializeNotificationInfoView_highPriority() throws Exception {
NotificationInfo notificationInfoView = mock(NotificationInfo.class);
ExpandableNotificationRow row = spy(mHelper.createRow());
- row.setBlockingHelperShowing(true);
final NotificationEntry entry = row.getEntry();
modifyRanking(entry)
.setUserSentiment(USER_SENTIMENT_NEGATIVE)
@@ -403,13 +338,10 @@ public class NotificationGutsManagerTest extends SysuiTestCase {
any(NotificationChannel.class),
anySet(),
eq(entry),
- any(NotificationInfo.CheckSaveListener.class),
any(NotificationInfo.OnSettingsClickListener.class),
any(NotificationInfo.OnAppSettingsClickListener.class),
eq(false),
eq(false),
- eq(true) /* isForBlockingHelper */,
- eq(IMPORTANCE_HIGH),
eq(true) /* wasShownHighPriority */);
}
@@ -437,13 +369,10 @@ public class NotificationGutsManagerTest extends SysuiTestCase {
any(NotificationChannel.class),
anySet(),
eq(entry),
- any(NotificationInfo.CheckSaveListener.class),
any(NotificationInfo.OnSettingsClickListener.class),
any(NotificationInfo.OnAppSettingsClickListener.class),
eq(true),
eq(false),
- eq(false) /* isForBlockingHelper */,
- eq(0),
eq(false) /* wasShownHighPriority */);
}
@@ -469,13 +398,10 @@ public class NotificationGutsManagerTest extends SysuiTestCase {
any(NotificationChannel.class),
anySet(),
eq(entry),
- any(NotificationInfo.CheckSaveListener.class),
any(NotificationInfo.OnSettingsClickListener.class),
any(NotificationInfo.OnAppSettingsClickListener.class),
eq(false),
eq(false),
- eq(true) /* isForBlockingHelper */,
- eq(0),
eq(false) /* wasShownHighPriority */);
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationInfoTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationInfoTest.java
index c62487a830fc..98ef691ee28c 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationInfoTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationInfoTest.java
@@ -119,15 +119,10 @@ public class NotificationInfoTest extends SysuiTestCase {
@Mock
private PackageManager mMockPackageManager;
@Mock
- private NotificationBlockingHelperManager mBlockingHelperManager;
- @Mock
private VisualStabilityManager mVisualStabilityManager;
@Before
public void setUp() throws Exception {
- mDependency.injectTestDependency(
- NotificationBlockingHelperManager.class,
- mBlockingHelperManager);
mTestableLooper = TestableLooper.get(this);
mDependency.injectTestDependency(Dependency.BG_LOOPER, mTestableLooper.getLooper());
@@ -183,13 +178,6 @@ public class NotificationInfoTest extends SysuiTestCase {
NOTIFICATION_NEW_INTERRUPTION_MODEL, 0);
}
- // TODO: if tests are taking too long replace this with something that makes the animation
- // finish instantly.
- private void waitForUndoButton() {
- PollingCheck.waitFor(1000,
- () -> VISIBLE == mNotificationInfo.findViewById(R.id.confirmation).getVisibility());
- }
-
@Test
public void testBindNotification_SetsTextApplicationName() throws Exception {
when(mMockPackageManager.getApplicationLabel(any())).thenReturn("App Name");
@@ -203,12 +191,10 @@ public class NotificationInfoTest extends SysuiTestCase {
mEntry,
null,
null,
- null,
true,
false,
- IMPORTANCE_DEFAULT,
true);
- final TextView textView = mNotificationInfo.findViewById(R.id.pkgname);
+ final TextView textView = mNotificationInfo.findViewById(R.id.pkg_name);
assertTrue(textView.getText().toString().contains("App Name"));
assertEquals(VISIBLE, mNotificationInfo.findViewById(R.id.header).getVisibility());
}
@@ -228,12 +214,10 @@ public class NotificationInfoTest extends SysuiTestCase {
mEntry,
null,
null,
- null,
true,
false,
- IMPORTANCE_DEFAULT,
true);
- final ImageView iconView = mNotificationInfo.findViewById(R.id.pkgicon);
+ final ImageView iconView = mNotificationInfo.findViewById(R.id.pkg_icon);
assertEquals(iconDrawable, iconView.getDrawable());
}
@@ -249,14 +233,12 @@ public class NotificationInfoTest extends SysuiTestCase {
mEntry,
null,
null,
- null,
true,
false,
- IMPORTANCE_DEFAULT,
true);
final TextView nameView = mNotificationInfo.findViewById(R.id.delegate_name);
assertEquals(GONE, nameView.getVisibility());
- final TextView dividerView = mNotificationInfo.findViewById(R.id.pkg_divider);
+ final TextView dividerView = mNotificationInfo.findViewById(R.id.group_divider);
assertEquals(GONE, dividerView.getVisibility());
}
@@ -281,16 +263,12 @@ public class NotificationInfoTest extends SysuiTestCase {
entry,
null,
null,
- null,
true,
false,
- IMPORTANCE_DEFAULT,
true);
final TextView nameView = mNotificationInfo.findViewById(R.id.delegate_name);
assertEquals(VISIBLE, nameView.getVisibility());
assertTrue(nameView.getText().toString().contains("Proxied"));
- final TextView dividerView = mNotificationInfo.findViewById(R.id.pkg_divider);
- assertEquals(VISIBLE, dividerView.getVisibility());
}
@Test
@@ -305,13 +283,13 @@ public class NotificationInfoTest extends SysuiTestCase {
mEntry,
null,
null,
- null,
true,
false,
- IMPORTANCE_DEFAULT,
true);
final TextView groupNameView = mNotificationInfo.findViewById(R.id.group_name);
assertEquals(GONE, groupNameView.getVisibility());
+ final TextView dividerView = mNotificationInfo.findViewById(R.id.group_divider);
+ assertEquals(GONE, dividerView.getVisibility());
}
@Test
@@ -332,14 +310,14 @@ public class NotificationInfoTest extends SysuiTestCase {
mEntry,
null,
null,
- null,
true,
false,
- IMPORTANCE_DEFAULT,
true);
final TextView groupNameView = mNotificationInfo.findViewById(R.id.group_name);
assertEquals(View.VISIBLE, groupNameView.getVisibility());
assertEquals("Test Group Name", groupNameView.getText());
+ final TextView dividerView = mNotificationInfo.findViewById(R.id.group_divider);
+ assertEquals(View.VISIBLE, dividerView.getVisibility());
}
@Test
@@ -354,10 +332,8 @@ public class NotificationInfoTest extends SysuiTestCase {
mEntry,
null,
null,
- null,
true,
false,
- IMPORTANCE_DEFAULT,
true);
final TextView textView = mNotificationInfo.findViewById(R.id.channel_name);
assertEquals(TEST_CHANNEL_NAME, textView.getText());
@@ -375,10 +351,8 @@ public class NotificationInfoTest extends SysuiTestCase {
mEntry,
null,
null,
- null,
true,
false,
- IMPORTANCE_DEFAULT,
true);
final TextView textView = mNotificationInfo.findViewById(R.id.channel_name);
assertEquals(GONE, textView.getVisibility());
@@ -387,7 +361,7 @@ public class NotificationInfoTest extends SysuiTestCase {
@Test
public void testBindNotification_DefaultChannelUsesChannelNameIfMoreChannelsExist()
throws Exception {
- // Package has one channel by default.
+ // Package has more than one channel by default.
when(mMockINotificationManager.getNumNotificationChannelsForPackage(
eq(TEST_PACKAGE_NAME), eq(TEST_UID), anyBoolean())).thenReturn(10);
mNotificationInfo.bindNotification(
@@ -400,10 +374,8 @@ public class NotificationInfoTest extends SysuiTestCase {
mEntry,
null,
null,
- null,
true,
false,
- IMPORTANCE_DEFAULT,
true);
final TextView textView = mNotificationInfo.findViewById(R.id.channel_name);
assertEquals(VISIBLE, textView.getVisibility());
@@ -421,42 +393,14 @@ public class NotificationInfoTest extends SysuiTestCase {
mEntry,
null,
null,
- null,
true,
true,
- IMPORTANCE_DEFAULT,
true);
final TextView textView = mNotificationInfo.findViewById(R.id.channel_name);
assertEquals(VISIBLE, textView.getVisibility());
}
@Test
- public void testBindNotification_BlockLink_BlockingHelper() throws Exception {
- mNotificationInfo.bindNotification(
- mMockPackageManager,
- mMockINotificationManager,
- mVisualStabilityManager,
- TEST_PACKAGE_NAME,
- mNotificationChannel,
- mNotificationChannelSet,
- mEntry,
- null,
- mock(NotificationInfo.OnSettingsClickListener.class),
- null,
- true,
- false,
- true /* isBlockingHelper */,
- IMPORTANCE_DEFAULT,
- true);
- final View block =
- mNotificationInfo.findViewById(R.id.blocking_helper_turn_off_notifications);
- final View interruptivenessSettings = mNotificationInfo.findViewById(
- R.id.inline_controls);
- assertEquals(VISIBLE, block.getVisibility());
- assertEquals(GONE, interruptivenessSettings.getVisibility());
- }
-
- @Test
public void testBindNotification_SetsOnClickListenerForSettings() throws Exception {
final CountDownLatch latch = new CountDownLatch(1);
mNotificationInfo.bindNotification(
@@ -467,7 +411,6 @@ public class NotificationInfoTest extends SysuiTestCase {
mNotificationChannel,
mNotificationChannelSet,
mEntry,
- null,
(View v, NotificationChannel c, int appUid) -> {
assertEquals(mNotificationChannel, c);
latch.countDown();
@@ -475,7 +418,6 @@ public class NotificationInfoTest extends SysuiTestCase {
null,
true,
false,
- IMPORTANCE_DEFAULT,
true);
final View settingsButton = mNotificationInfo.findViewById(R.id.info);
@@ -496,10 +438,8 @@ public class NotificationInfoTest extends SysuiTestCase {
mEntry,
null,
null,
- null,
true,
false,
- IMPORTANCE_DEFAULT,
true);
final View settingsButton = mNotificationInfo.findViewById(R.id.info);
assertTrue(settingsButton.getVisibility() != View.VISIBLE);
@@ -516,14 +456,12 @@ public class NotificationInfoTest extends SysuiTestCase {
mNotificationChannel,
mNotificationChannelSet,
mEntry,
- null,
(View v, NotificationChannel c, int appUid) -> {
assertEquals(mNotificationChannel, c);
},
null,
false,
false,
- IMPORTANCE_DEFAULT,
true);
final View settingsButton = mNotificationInfo.findViewById(R.id.info);
assertTrue(settingsButton.getVisibility() != View.VISIBLE);
@@ -541,10 +479,8 @@ public class NotificationInfoTest extends SysuiTestCase {
mEntry,
null,
null,
- null,
true,
false,
- IMPORTANCE_DEFAULT,
true);
mNotificationInfo.bindNotification(
mMockPackageManager,
@@ -554,89 +490,16 @@ public class NotificationInfoTest extends SysuiTestCase {
mNotificationChannel,
mNotificationChannelSet,
mEntry,
- null,
(View v, NotificationChannel c, int appUid) -> { },
null,
true,
false,
- IMPORTANCE_DEFAULT,
true);
final View settingsButton = mNotificationInfo.findViewById(R.id.info);
assertEquals(View.VISIBLE, settingsButton.getVisibility());
}
@Test
- public void testBindNotificationLogging_notBlockingHelper() throws Exception {
- mNotificationInfo.bindNotification(
- mMockPackageManager,
- mMockINotificationManager,
- mVisualStabilityManager,
- TEST_PACKAGE_NAME,
- mNotificationChannel,
- mNotificationChannelSet,
- mEntry,
- null,
- null,
- null,
- true,
- false,
- IMPORTANCE_DEFAULT,
- true);
- verify(mMetricsLogger).write(argThat(logMaker ->
- logMaker.getCategory() == MetricsEvent.ACTION_NOTE_CONTROLS
- && logMaker.getType() == MetricsEvent.TYPE_OPEN
- && logMaker.getSubtype() == MetricsEvent.BLOCKING_HELPER_UNKNOWN
- ));
- }
-
- @Test
- public void testBindNotificationLogging_BlockingHelper() throws Exception {
- mNotificationInfo.bindNotification(
- mMockPackageManager,
- mMockINotificationManager,
- mVisualStabilityManager,
- TEST_PACKAGE_NAME,
- mNotificationChannel,
- mNotificationChannelSet,
- mEntry,
- null,
- null,
- null,
- false,
- true,
- true,
- IMPORTANCE_DEFAULT,
- true);
- verify(mMetricsLogger).write(argThat(logMaker ->
- logMaker.getCategory() == MetricsEvent.ACTION_NOTE_CONTROLS
- && logMaker.getType() == MetricsEvent.TYPE_OPEN
- && logMaker.getSubtype() == MetricsEvent.BLOCKING_HELPER_DISPLAY
- ));
- }
-
- @Test
- public void testLogBlockingHelperCounter_logsForBlockingHelper() throws Exception {
- mNotificationInfo.bindNotification(
- mMockPackageManager,
- mMockINotificationManager,
- mVisualStabilityManager,
- TEST_PACKAGE_NAME,
- mNotificationChannel,
- mNotificationChannelSet,
- mEntry,
- null,
- null,
- null,
- false,
- true,
- true,
- IMPORTANCE_DEFAULT,
- true);
- mNotificationInfo.logBlockingHelperCounter("HowCanNotifsBeRealIfAppsArent");
- verify(mMetricsLogger).count(eq("HowCanNotifsBeRealIfAppsArent"), eq(1));
- }
-
- @Test
public void testOnClickListenerPassesNullChannelForBundle() throws Exception {
final CountDownLatch latch = new CountDownLatch(1);
mNotificationInfo.bindNotification(
@@ -646,7 +509,6 @@ public class NotificationInfoTest extends SysuiTestCase {
TEST_PACKAGE_NAME, mNotificationChannel,
createMultipleChannelSet(MULTIPLE_CHANNEL_COUNT),
mEntry,
- null,
(View v, NotificationChannel c, int appUid) -> {
assertEquals(null, c);
latch.countDown();
@@ -654,7 +516,6 @@ public class NotificationInfoTest extends SysuiTestCase {
null,
true,
true,
- IMPORTANCE_DEFAULT,
true);
mNotificationInfo.findViewById(R.id.info).performClick();
@@ -676,10 +537,8 @@ public class NotificationInfoTest extends SysuiTestCase {
mEntry,
null,
null,
- null,
true,
false,
- IMPORTANCE_DEFAULT,
true);
final TextView channelNameView =
mNotificationInfo.findViewById(R.id.channel_name);
@@ -699,10 +558,8 @@ public class NotificationInfoTest extends SysuiTestCase {
mEntry,
null,
null,
- null,
true,
false,
- IMPORTANCE_DEFAULT,
true);
assertEquals(GONE, mNotificationInfo.findViewById(
R.id.interruptiveness_settings).getVisibility());
@@ -722,10 +579,8 @@ public class NotificationInfoTest extends SysuiTestCase {
mEntry,
null,
null,
- null,
true,
true,
- IMPORTANCE_DEFAULT,
true);
final TextView view = mNotificationInfo.findViewById(R.id.non_configurable_text);
assertEquals(View.VISIBLE, view.getVisibility());
@@ -747,10 +602,8 @@ public class NotificationInfoTest extends SysuiTestCase {
mEntry,
null,
null,
- null,
true,
false,
- IMPORTANCE_DEFAULT,
true);
assertTrue(mNotificationInfo.findViewById(R.id.alert).isSelected());
}
@@ -767,10 +620,8 @@ public class NotificationInfoTest extends SysuiTestCase {
mEntry,
null,
null,
- null,
true,
false,
- IMPORTANCE_DEFAULT,
false);
assertTrue(mNotificationInfo.findViewById(R.id.silence).isSelected());
}
@@ -787,10 +638,8 @@ public class NotificationInfoTest extends SysuiTestCase {
mEntry,
null,
null,
- null,
true,
false,
- IMPORTANCE_DEFAULT,
true);
mTestableLooper.processAllMessages();
verify(mMockINotificationManager, never()).updateNotificationChannelForPackage(
@@ -810,10 +659,8 @@ public class NotificationInfoTest extends SysuiTestCase {
mEntry,
null,
null,
- null,
true,
false,
- IMPORTANCE_LOW,
false);
mNotificationInfo.findViewById(R.id.alert).performClick();
@@ -836,10 +683,8 @@ public class NotificationInfoTest extends SysuiTestCase {
mEntry,
null,
null,
- null,
true,
false,
- IMPORTANCE_DEFAULT,
true);
mNotificationInfo.findViewById(R.id.silence).performClick();
@@ -862,10 +707,8 @@ public class NotificationInfoTest extends SysuiTestCase {
mEntry,
null,
null,
- null,
true,
false,
- IMPORTANCE_DEFAULT,
true);
mNotificationInfo.handleCloseControls(true, false);
@@ -889,10 +732,8 @@ public class NotificationInfoTest extends SysuiTestCase {
mEntry,
null,
null,
- null,
true,
false,
- IMPORTANCE_UNSPECIFIED,
true);
mNotificationInfo.handleCloseControls(true, false);
@@ -904,225 +745,6 @@ public class NotificationInfoTest extends SysuiTestCase {
}
@Test
- public void testCloseControls_nonNullCheckSaveListenerDoesntDelayKeepShowing_BlockingHelper()
- throws Exception {
- NotificationInfo.CheckSaveListener listener =
- mock(NotificationInfo.CheckSaveListener.class);
- mNotificationChannel.setImportance(IMPORTANCE_DEFAULT);
- mNotificationInfo.bindNotification(
- mMockPackageManager,
- mMockINotificationManager,
- mVisualStabilityManager,
- TEST_PACKAGE_NAME,
- mNotificationChannel /* notificationChannel */,
- createMultipleChannelSet(10) /* numUniqueChannelsInRow */,
- mEntry,
- listener /* checkSaveListener */,
- null /* onSettingsClick */,
- null /* onAppSettingsClick */,
- true /* provisioned */,
- false /* isNonblockable */,
- true /* isForBlockingHelper */,
- IMPORTANCE_DEFAULT,
- true);
-
- NotificationGuts guts = spy(new NotificationGuts(mContext, null));
- when(guts.getWindowToken()).thenReturn(mock(IBinder.class));
- doNothing().when(guts).animateClose(anyInt(), anyInt(), anyBoolean());
- doNothing().when(guts).setExposed(anyBoolean(), anyBoolean());
- guts.setGutsContent(mNotificationInfo);
- mNotificationInfo.setGutsParent(guts);
-
- mNotificationInfo.findViewById(R.id.keep_showing).performClick();
-
- verify(mBlockingHelperManager).dismissCurrentBlockingHelper();
- mTestableLooper.processAllMessages();
- verify(mMockINotificationManager, times(1))
- .setNotificationsEnabledWithImportanceLockForPackage(
- anyString(), eq(TEST_UID), eq(true));
- }
-
- @Test
- public void testCloseControls_nonNullCheckSaveListenerDoesntDelayDismiss_BlockingHelper()
- throws Exception {
- NotificationInfo.CheckSaveListener listener =
- mock(NotificationInfo.CheckSaveListener.class);
- mNotificationChannel.setImportance(IMPORTANCE_DEFAULT);
- mNotificationInfo.bindNotification(
- mMockPackageManager,
- mMockINotificationManager,
- mVisualStabilityManager,
- TEST_PACKAGE_NAME,
- mNotificationChannel /* notificationChannel */,
- createMultipleChannelSet(10) /* numUniqueChannelsInRow */,
- mEntry,
- listener /* checkSaveListener */,
- null /* onSettingsClick */,
- null /* onAppSettingsClick */,
- false /* isNonblockable */,
- true /* isForBlockingHelper */,
- true, IMPORTANCE_DEFAULT,
- true);
-
- mNotificationInfo.handleCloseControls(true /* save */, false /* force */);
-
- mTestableLooper.processAllMessages();
- verify(listener, times(0)).checkSave(any(Runnable.class), eq(mSbn));
- }
-
- @Test
- public void testCloseControls_checkSaveListenerDelaysStopNotifications_BlockingHelper()
- throws Exception {
- NotificationInfo.CheckSaveListener listener =
- mock(NotificationInfo.CheckSaveListener.class);
- mNotificationChannel.setImportance(IMPORTANCE_DEFAULT);
- mNotificationInfo.bindNotification(
- mMockPackageManager,
- mMockINotificationManager,
- mVisualStabilityManager,
- TEST_PACKAGE_NAME,
- mNotificationChannel /* notificationChannel */,
- createMultipleChannelSet(10) /* numUniqueChannelsInRow */,
- mEntry,
- listener /* checkSaveListener */,
- null /* onSettingsClick */,
- null /* onAppSettingsClick */,
- true /* provisioned */,
- false /* isNonblockable */,
- true /* isForBlockingHelper */,
- IMPORTANCE_DEFAULT,
- true);
-
- mNotificationInfo.findViewById(R.id.deliver_silently).performClick();
- mTestableLooper.processAllMessages();
- verify(listener).checkSave(any(Runnable.class), eq(mSbn));
- }
-
- @Test
- public void testCloseControls_blockingHelperDismissedIfShown() throws Exception {
- mNotificationChannel.setImportance(IMPORTANCE_DEFAULT);
- mNotificationInfo.bindNotification(
- mMockPackageManager,
- mMockINotificationManager,
- mVisualStabilityManager,
- TEST_PACKAGE_NAME,
- mNotificationChannel,
- mNotificationChannelSet /* numChannels */,
- mEntry,
- null /* checkSaveListener */,
- null /* onSettingsClick */,
- null /* onAppSettingsClick */,
- false /* isNonblockable */,
- true /* isForBlockingHelper */,
- true,
- IMPORTANCE_DEFAULT,
- true);
- NotificationGuts guts = mock(NotificationGuts.class);
- doCallRealMethod().when(guts).closeControls(anyInt(), anyInt(), anyBoolean(), anyBoolean());
- mNotificationInfo.setGutsParent(guts);
-
- mNotificationInfo.closeControls(mNotificationInfo, true);
-
- verify(mBlockingHelperManager).dismissCurrentBlockingHelper();
- }
-
- @Test
- public void testSilentlyChangedCallsUpdateNotificationChannel_blockingHelper()
- throws Exception {
- mNotificationChannel.setImportance(IMPORTANCE_DEFAULT);
- mNotificationInfo.bindNotification(
- mMockPackageManager,
- mMockINotificationManager,
- mVisualStabilityManager,
- TEST_PACKAGE_NAME,
- mNotificationChannel,
- mNotificationChannelSet /* numChannels */,
- mEntry,
- null /* checkSaveListener */,
- null /* onSettingsClick */,
- null /* onAppSettingsClick */,
- true /*provisioned */,
- false /* isNonblockable */,
- true /* isForBlockingHelper */,
- IMPORTANCE_DEFAULT,
- true);
-
- mNotificationInfo.findViewById(R.id.deliver_silently).performClick();
- waitForUndoButton();
- mNotificationInfo.handleCloseControls(true, false);
-
- mTestableLooper.processAllMessages();
- ArgumentCaptor<NotificationChannel> updated =
- ArgumentCaptor.forClass(NotificationChannel.class);
- verify(mMockINotificationManager, times(1)).updateNotificationChannelForPackage(
- anyString(), eq(TEST_UID), updated.capture());
- assertTrue((updated.getValue().getUserLockedFields()
- & USER_LOCKED_IMPORTANCE) != 0);
- assertEquals(IMPORTANCE_LOW, updated.getValue().getImportance());
- }
-
- @Test
- public void testKeepUpdatesNotificationChannel_blockingHelper() throws Exception {
- mNotificationChannel.setImportance(IMPORTANCE_LOW);
- mNotificationInfo.bindNotification(
- mMockPackageManager,
- mMockINotificationManager,
- mVisualStabilityManager,
- TEST_PACKAGE_NAME,
- mNotificationChannel,
- mNotificationChannelSet,
- mEntry,
- null,
- null,
- null,
- true,
- true,
- IMPORTANCE_LOW,
- false);
-
- mNotificationInfo.findViewById(R.id.keep_showing).performClick();
- mNotificationInfo.handleCloseControls(true, false);
-
- mTestableLooper.processAllMessages();
- ArgumentCaptor<NotificationChannel> updated =
- ArgumentCaptor.forClass(NotificationChannel.class);
- verify(mMockINotificationManager, times(1)).updateNotificationChannelForPackage(
- anyString(), eq(TEST_UID), updated.capture());
- assertTrue(0 != (mNotificationChannel.getUserLockedFields() & USER_LOCKED_IMPORTANCE));
- assertEquals(IMPORTANCE_LOW, mNotificationChannel.getImportance());
- }
-
- @Test
- public void testNoActionsUpdatesNotificationChannel_blockingHelper() throws Exception {
- mNotificationChannel.setImportance(IMPORTANCE_DEFAULT);
- mNotificationInfo.bindNotification(
- mMockPackageManager,
- mMockINotificationManager,
- mVisualStabilityManager,
- TEST_PACKAGE_NAME,
- mNotificationChannel,
- mNotificationChannelSet,
- mEntry,
- null,
- null,
- null,
- true,
- true,
- IMPORTANCE_DEFAULT,
- true);
-
- mNotificationInfo.handleCloseControls(true, false);
-
- mTestableLooper.processAllMessages();
- ArgumentCaptor<NotificationChannel> updated =
- ArgumentCaptor.forClass(NotificationChannel.class);
- verify(mMockINotificationManager, times(1)).updateNotificationChannelForPackage(
- anyString(), eq(TEST_UID), updated.capture());
- assertTrue(0 != (mNotificationChannel.getUserLockedFields() & USER_LOCKED_IMPORTANCE));
- assertEquals(IMPORTANCE_DEFAULT, mNotificationChannel.getImportance());
- }
-
- @Test
public void testSilenceCallsUpdateNotificationChannel() throws Exception {
mNotificationChannel.setImportance(IMPORTANCE_DEFAULT);
mNotificationInfo.bindNotification(
@@ -1135,10 +757,8 @@ public class NotificationInfoTest extends SysuiTestCase {
mEntry,
null,
null,
- null,
true,
false,
- IMPORTANCE_DEFAULT,
true);
mNotificationInfo.findViewById(R.id.silence).performClick();
@@ -1168,10 +788,8 @@ public class NotificationInfoTest extends SysuiTestCase {
mEntry,
null,
null,
- null,
true,
false,
- IMPORTANCE_LOW,
false);
mNotificationInfo.findViewById(R.id.alert).performClick();
@@ -1202,10 +820,8 @@ public class NotificationInfoTest extends SysuiTestCase {
mEntry,
null,
null,
- null,
true,
false,
- IMPORTANCE_UNSPECIFIED,
true);
mNotificationInfo.findViewById(R.id.silence).performClick();
@@ -1236,10 +852,8 @@ public class NotificationInfoTest extends SysuiTestCase {
mEntry,
null,
null,
- null,
true,
false,
- IMPORTANCE_MIN,
false);
assertEquals(mContext.getString(R.string.inline_done_button),
@@ -1273,10 +887,8 @@ public class NotificationInfoTest extends SysuiTestCase {
mEntry,
null,
null,
- null,
true,
false,
- IMPORTANCE_MIN,
false);
assertEquals(mContext.getString(R.string.inline_done_button),
@@ -1309,10 +921,8 @@ public class NotificationInfoTest extends SysuiTestCase {
mEntry,
null,
null,
- null,
true,
false,
- IMPORTANCE_DEFAULT,
true);
mNotificationInfo.findViewById(R.id.silence).performClick();
@@ -1336,10 +946,8 @@ public class NotificationInfoTest extends SysuiTestCase {
mEntry,
null,
null,
- null,
true,
false,
- IMPORTANCE_LOW,
false);
assertEquals(mContext.getString(R.string.inline_done_button),
@@ -1366,10 +974,8 @@ public class NotificationInfoTest extends SysuiTestCase {
mEntry,
null,
null,
- null,
true,
false,
- IMPORTANCE_LOW,
false);
mNotificationInfo.findViewById(R.id.alert).performClick();
@@ -1399,10 +1005,8 @@ public class NotificationInfoTest extends SysuiTestCase {
mEntry,
null,
null,
- null,
true,
false,
- IMPORTANCE_LOW,
false);
mNotificationInfo.findViewById(R.id.alert).performClick();
@@ -1425,14 +1029,10 @@ public class NotificationInfoTest extends SysuiTestCase {
mNotificationChannel,
mNotificationChannelSet,
mEntry,
- (Runnable saveImportance, StatusBarNotification sbn) -> {
- saveImportance.run();
- },
null,
null,
true,
false,
- IMPORTANCE_LOW,
false
);
@@ -1460,14 +1060,10 @@ public class NotificationInfoTest extends SysuiTestCase {
mNotificationChannel,
mNotificationChannelSet,
mEntry,
- (Runnable saveImportance, StatusBarNotification sbn) -> {
- saveImportance.run();
- },
null,
null,
true,
false,
- IMPORTANCE_LOW,
false
);
@@ -1488,14 +1084,10 @@ public class NotificationInfoTest extends SysuiTestCase {
mNotificationChannel,
mNotificationChannelSet,
mEntry,
- (Runnable saveImportance, StatusBarNotification sbn) -> {
- saveImportance.run();
- },
null,
null,
true,
false,
- IMPORTANCE_LOW,
false
);
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationSectionsManagerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationSectionsManagerTest.java
index c64dd093a4c2..a263a7232352 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationSectionsManagerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationSectionsManagerTest.java
@@ -315,6 +315,24 @@ public class NotificationSectionsManagerTest extends SysuiTestCase {
verify(mNssl).changeViewPosition(mSectionsManager.getPeopleHeaderView(), 0);
}
+ @Test
+ public void testPeopleFiltering_keepPeopleHeaderWhenSectionEmpty() {
+ mSectionsManager.setPeopleHubVisible(true);
+ enablePeopleFiltering();
+
+ setStackState(
+ ChildType.PEOPLE_HEADER,
+ ChildType.ALERTING_HEADER,
+ ChildType.ALERTING,
+ ChildType.GENTLE_HEADER,
+ ChildType.GENTLE
+ );
+ mSectionsManager.updateSectionBoundaries();
+
+ verify(mNssl, never()).removeView(mSectionsManager.getPeopleHeaderView());
+ verify(mNssl).changeViewPosition(mSectionsManager.getPeopleHeaderView(), 0);
+ }
+
private void enablePeopleFiltering() {
when(mSectionsFeatureManager.isFilteringEnabled()).thenReturn(true);
when(mSectionsFeatureManager.getNumberOfBuckets()).thenReturn(4);
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutTest.java
index 0cb658540f0d..ef2071ef090e 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutTest.java
@@ -46,6 +46,7 @@ import androidx.test.filters.SmallTest;
import com.android.internal.logging.MetricsLogger;
import com.android.internal.logging.nano.MetricsProto;
+import com.android.internal.logging.testing.UiEventLoggerFake;
import com.android.systemui.ExpandHelper;
import com.android.systemui.R;
import com.android.systemui.SysuiTestCase;
@@ -139,6 +140,7 @@ public class NotificationStackScrollLayoutTest extends SysuiTestCase {
private UserChangedListener mUserChangedListener;
private TestableNotificationEntryManager mEntryManager;
private int mOriginalInterruptionModelSetting;
+ private UiEventLoggerFake mUiEventLoggerFake = new UiEventLoggerFake();
@Before
@@ -214,7 +216,8 @@ public class NotificationStackScrollLayoutTest extends SysuiTestCase {
mFeatureFlags,
mock(NotifPipeline.class),
mEntryManager,
- mock(NotifCollection.class)
+ mock(NotifCollection.class),
+ mUiEventLoggerFake
);
verify(mLockscreenUserManager).addUserChangedListener(userChangedCaptor.capture());
mUserChangedListener = userChangedCaptor.getValue();
@@ -506,6 +509,22 @@ public class NotificationStackScrollLayoutTest extends SysuiTestCase {
MetricsProto.MetricsEvent.TYPE_ACTION));
}
+ @Test
+ public void testClearNotifications_All() {
+ mStackScroller.clearNotifications(NotificationStackScrollLayout.ROWS_ALL, true);
+ assertEquals(1, mUiEventLoggerFake.numLogs());
+ assertEquals(NotificationStackScrollLayout.NotificationPanelEvent
+ .DISMISS_ALL_NOTIFICATIONS_PANEL.getId(), mUiEventLoggerFake.eventId(0));
+ }
+
+ @Test
+ public void testClearNotifications_Gentle() {
+ mStackScroller.clearNotifications(NotificationStackScrollLayout.ROWS_GENTLE, false);
+ assertEquals(1, mUiEventLoggerFake.numLogs());
+ assertEquals(NotificationStackScrollLayout.NotificationPanelEvent
+ .DISMISS_SILENT_NOTIFICATIONS_PANEL.getId(), mUiEventLoggerFake.eventId(0));
+ }
+
private void setBarStateForTest(int state) {
// Can't inject this through the listener or we end up on the actual implementation
// rather than the mock because the spy just coppied the anonymous inner /shruggie.
@@ -517,8 +536,4 @@ public class NotificationStackScrollLayoutTest extends SysuiTestCase {
mEntryManager.addActiveNotificationForTest(e);
}
}
-
- private void addActiveNotificationsToManager(List<NotificationEntry> entries) {
- mEntryManager.setActiveNotificationList(entries);
- }
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/LockscreenIconControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/LockscreenIconControllerTest.java
index 05f10e376f61..487885ac244e 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/LockscreenIconControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/LockscreenIconControllerTest.java
@@ -29,8 +29,10 @@ import androidx.test.runner.AndroidJUnit4;
import com.android.internal.widget.LockPatternUtils;
import com.android.keyguard.KeyguardUpdateMonitor;
import com.android.systemui.SysuiTestCase;
+import com.android.systemui.dock.DockManager;
import com.android.systemui.plugins.statusbar.StatusBarStateController;
import com.android.systemui.statusbar.KeyguardIndicationController;
+import com.android.systemui.statusbar.notification.NotificationWakeUpCoordinator;
import com.android.systemui.statusbar.policy.AccessibilityController;
import com.android.systemui.statusbar.policy.ConfigurationController;
@@ -63,6 +65,13 @@ public class LockscreenIconControllerTest extends SysuiTestCase {
private StatusBarStateController mStatusBarStateController;
@Mock
private ConfigurationController mConfigurationController;
+ @Mock
+ private NotificationWakeUpCoordinator mNotificationWakeUpCoordinator;
+ @Mock
+ private KeyguardBypassController mKeyguardBypassController;
+ @Mock
+ private DockManager mDockManager;
+
@Before
public void setUp() {
@@ -71,7 +80,8 @@ public class LockscreenIconControllerTest extends SysuiTestCase {
mLockIconController = new LockscreenLockIconController(
mLockscreenGestureLogger, mKeyguardUpdateMonitor, mLockPatternUtils,
mShadeController, mAccessibilityController, mKeyguardIndicationController,
- mStatusBarStateController, mConfigurationController);
+ mStatusBarStateController, mConfigurationController, mNotificationWakeUpCoordinator,
+ mKeyguardBypassController, mDockManager);
mLockIconController.attach(mLockIcon);
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarTest.java
index 0d7734e13621..e4079275ddfc 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarTest.java
@@ -122,6 +122,7 @@ import com.android.systemui.statusbar.notification.collection.NotificationEntry;
import com.android.systemui.statusbar.notification.collection.NotificationEntryBuilder;
import com.android.systemui.statusbar.notification.init.NotificationsController;
import com.android.systemui.statusbar.notification.logging.NotificationLogger;
+import com.android.systemui.statusbar.notification.logging.NotificationPanelLoggerFake;
import com.android.systemui.statusbar.notification.row.NotificationGutsManager;
import com.android.systemui.statusbar.notification.stack.NotificationStackScrollLayout;
import com.android.systemui.statusbar.phone.dagger.StatusBarComponent;
@@ -273,7 +274,7 @@ public class StatusBarTest extends SysuiTestCase {
mMetricsLogger = new FakeMetricsLogger();
NotificationLogger notificationLogger = new NotificationLogger(mNotificationListener,
mUiBgExecutor, mock(NotificationEntryManager.class), mStatusBarStateController,
- mExpansionStateLogger);
+ mExpansionStateLogger, new NotificationPanelLoggerFake());
notificationLogger.setVisibilityReporter(mock(Runnable.class));
when(mCommandQueue.asBinder()).thenReturn(new Binder());
diff --git a/packages/SystemUI/tests/src/com/android/systemui/util/sensors/ProximitySensorTest.java b/packages/SystemUI/tests/src/com/android/systemui/util/sensors/ProximitySensorTest.java
index 37b315fec26e..526fba726e9d 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/util/sensors/ProximitySensorTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/util/sensors/ProximitySensorTest.java
@@ -104,6 +104,30 @@ public class ProximitySensorTest extends SysuiTestCase {
}
@Test
+ public void testDuplicateListener() {
+ TestableListener listenerA = new TestableListener();
+
+ assertFalse(mProximitySensor.isRegistered());
+
+ mProximitySensor.register(listenerA);
+ waitForSensorManager();
+ assertTrue(mProximitySensor.isRegistered());
+ mProximitySensor.register(listenerA);
+ waitForSensorManager();
+ assertTrue(mProximitySensor.isRegistered());
+ assertNull(listenerA.mLastEvent);
+
+ mFakeProximitySensor.sendProximityResult(true);
+ assertFalse(listenerA.mLastEvent.getNear());
+ assertEquals(listenerA.mCallCount, 1);
+ mFakeProximitySensor.sendProximityResult(false);
+ assertTrue(listenerA.mLastEvent.getNear());
+ assertEquals(listenerA.mCallCount, 2);
+
+ mProximitySensor.unregister(listenerA);
+ waitForSensorManager();
+ }
+ @Test
public void testUnregister() {
TestableListener listener = new TestableListener();
diff --git a/packages/SystemUI/tests/src/com/android/systemui/volume/EventsTest.java b/packages/SystemUI/tests/src/com/android/systemui/volume/EventsTest.java
index 701b2fab5f85..a853f1d84176 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/volume/EventsTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/volume/EventsTest.java
@@ -102,9 +102,9 @@ public class EventsTest extends SysuiTestCase {
assertEquals(mExpectedMetrics[1], logs.remove().getCategory());
}
}
- Queue<UiEventLoggerFake.FakeUiEvent> events = mUiEventLogger.getLogs();
if (mUiEvent != null) {
- assertEquals(mUiEvent.getId(), events.remove().eventId);
+ assertEquals(1, mUiEventLogger.numLogs());
+ assertEquals(mUiEvent.getId(), mUiEventLogger.eventId(0));
}
}
diff --git a/packages/Tethering/common/TetheringLib/src/android/net/ITetheringEventCallback.aidl b/packages/Tethering/common/TetheringLib/src/android/net/ITetheringEventCallback.aidl
index a55419383380..b4e3ba46791c 100644
--- a/packages/Tethering/common/TetheringLib/src/android/net/ITetheringEventCallback.aidl
+++ b/packages/Tethering/common/TetheringLib/src/android/net/ITetheringEventCallback.aidl
@@ -35,4 +35,5 @@ oneway interface ITetheringEventCallback
void onConfigurationChanged(in TetheringConfigurationParcel config);
void onTetherStatesChanged(in TetherStatesParcel states);
void onTetherClientsChanged(in List<TetheredClient> clients);
+ void onOffloadStatusChanged(int status);
}
diff --git a/packages/Tethering/common/TetheringLib/src/android/net/TetheringCallbackStartedParcel.aidl b/packages/Tethering/common/TetheringLib/src/android/net/TetheringCallbackStartedParcel.aidl
index c064aa4d9a61..253eacbd23e7 100644
--- a/packages/Tethering/common/TetheringLib/src/android/net/TetheringCallbackStartedParcel.aidl
+++ b/packages/Tethering/common/TetheringLib/src/android/net/TetheringCallbackStartedParcel.aidl
@@ -31,4 +31,5 @@ parcelable TetheringCallbackStartedParcel {
TetheringConfigurationParcel config;
TetherStatesParcel states;
List<TetheredClient> tetheredClients;
-} \ No newline at end of file
+ int offloadStatus;
+}
diff --git a/packages/Tethering/common/TetheringLib/src/android/net/TetheringManager.java b/packages/Tethering/common/TetheringLib/src/android/net/TetheringManager.java
index fd9f7137c85d..7f831ced7bec 100644
--- a/packages/Tethering/common/TetheringLib/src/android/net/TetheringManager.java
+++ b/packages/Tethering/common/TetheringLib/src/android/net/TetheringManager.java
@@ -18,6 +18,7 @@ package android.net;
import static android.annotation.SystemApi.Client.MODULE_LIBRARIES;
import android.Manifest;
+import android.annotation.IntDef;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.annotation.RequiresPermission;
@@ -34,6 +35,8 @@ import android.util.Log;
import com.android.internal.annotations.GuardedBy;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
@@ -172,6 +175,23 @@ public class TetheringManager {
public static final int TETHER_ERROR_NO_CHANGE_TETHERING_PERMISSION = 14;
public static final int TETHER_ERROR_NO_ACCESS_TETHERING_PERMISSION = 15;
+ /** @hide */
+ @Retention(RetentionPolicy.SOURCE)
+ @IntDef(flag = false, value = {
+ TETHER_HARDWARE_OFFLOAD_STOPPED,
+ TETHER_HARDWARE_OFFLOAD_STARTED,
+ TETHER_HARDWARE_OFFLOAD_FAILED,
+ })
+ public @interface TetherOffloadStatus {
+ }
+
+ /** Tethering offload status is stopped. */
+ public static final int TETHER_HARDWARE_OFFLOAD_STOPPED = 0;
+ /** Tethering offload status is started. */
+ public static final int TETHER_HARDWARE_OFFLOAD_STARTED = 1;
+ /** Fail to start tethering offload. */
+ public static final int TETHER_HARDWARE_OFFLOAD_FAILED = 2;
+
/**
* Create a TetheringManager object for interacting with the tethering service.
*
@@ -378,6 +398,9 @@ public class TetheringManager {
@Override
public void onTetherClientsChanged(List<TetheredClient> clients) { }
+ @Override
+ public void onOffloadStatusChanged(int status) { }
+
public void waitForStarted() {
mWaitForCallback.block(DEFAULT_TIMEOUT_MS);
throwIfPermissionFailure(mError);
@@ -802,6 +825,14 @@ public class TetheringManager {
* @param clients The new set of tethered clients; the collection is not ordered.
*/
public void onClientsChanged(@NonNull Collection<TetheredClient> clients) {}
+
+ /**
+ * Called when tethering offload status changes.
+ *
+ * <p>This will be called immediately after the callback is registered.
+ * @param status The offload status.
+ */
+ public void onOffloadStatusChanged(@TetherOffloadStatus int status) {}
}
/**
@@ -925,6 +956,7 @@ public class TetheringManager {
maybeSendTetherableIfacesChangedCallback(parcel.states);
maybeSendTetheredIfacesChangedCallback(parcel.states);
callback.onClientsChanged(parcel.tetheredClients);
+ callback.onOffloadStatusChanged(parcel.offloadStatus);
});
}
@@ -960,6 +992,11 @@ public class TetheringManager {
public void onTetherClientsChanged(final List<TetheredClient> clients) {
executor.execute(() -> callback.onClientsChanged(clients));
}
+
+ @Override
+ public void onOffloadStatusChanged(final int status) {
+ executor.execute(() -> callback.onOffloadStatusChanged(status));
+ }
};
getConnector(c -> c.registerTetheringEventCallback(remoteCallback, callerPkg));
mTetheringEventCallbacks.put(callback, remoteCallback);
@@ -1131,6 +1168,25 @@ public class TetheringManager {
public boolean isTetheringSupported() {
final String callerPkg = mContext.getOpPackageName();
+ return isTetheringSupported(callerPkg);
+ }
+
+ /**
+ * Check if the device allows for tethering. It may be disabled via {@code ro.tether.denied}
+ * system property, Settings.TETHER_SUPPORTED or due to device configuration. This is useful
+ * for system components that query this API on behalf of an app. In particular, Bluetooth
+ * has @UnsupportedAppUsage calls that will let apps turn on bluetooth tethering if they have
+ * the right permissions, but such an app needs to know whether it can (permissions as well
+ * as support from the device) turn on tethering in the first place to show the appropriate UI.
+ *
+ * @param callerPkg The caller package name, if it is not matching the calling uid,
+ * SecurityException would be thrown.
+ * @return a boolean - {@code true} indicating Tethering is supported.
+ * @hide
+ */
+ @SystemApi(client = MODULE_LIBRARIES)
+ public boolean isTetheringSupported(@NonNull final String callerPkg) {
+
final RequestDispatcher dispatcher = new RequestDispatcher();
final int ret = dispatcher.waitForResult((connector, listener) -> {
try {
diff --git a/packages/Tethering/src/android/net/ip/IpServer.java b/packages/Tethering/src/android/net/ip/IpServer.java
index 3acc76657731..38f8609e217f 100644
--- a/packages/Tethering/src/android/net/ip/IpServer.java
+++ b/packages/Tethering/src/android/net/ip/IpServer.java
@@ -810,7 +810,7 @@ public class IpServer extends StateMachine {
rule.dstMac.toByteArray());
mIpv6ForwardingRules.put(rule.address, rule);
} catch (RemoteException | ServiceSpecificException e) {
- Log.e(TAG, "Could not add IPv6 downstream rule: " + e);
+ mLog.e("Could not add IPv6 downstream rule: ", e);
}
}
@@ -821,10 +821,17 @@ public class IpServer extends StateMachine {
mIpv6ForwardingRules.remove(rule.address);
}
} catch (RemoteException | ServiceSpecificException e) {
- Log.e(TAG, "Could not remove IPv6 downstream rule: " + e);
+ mLog.e("Could not remove IPv6 downstream rule: ", e);
}
}
+ private void clearIpv6ForwardingRules() {
+ for (Ipv6ForwardingRule rule : mIpv6ForwardingRules.values()) {
+ removeIpv6ForwardingRule(rule, false /*removeFromMap*/);
+ }
+ mIpv6ForwardingRules.clear();
+ }
+
// Convenience method to replace a rule with the same rule on a new upstream interface.
// Allows replacing the rules in one iteration pass without ConcurrentModificationExceptions.
// Relies on the fact that rules are in a map indexed by IP address.
@@ -837,6 +844,12 @@ public class IpServer extends StateMachine {
// changes or if a neighbor event is received.
private void updateIpv6ForwardingRules(int prevUpstreamIfindex, int upstreamIfindex,
NeighborEvent e) {
+ // If we no longer have an upstream, clear forwarding rules and do nothing else.
+ if (upstreamIfindex == 0) {
+ clearIpv6ForwardingRules();
+ return;
+ }
+
// If the upstream interface has changed, remove all rules and re-add them with the new
// upstream interface.
if (prevUpstreamIfindex != upstreamIfindex) {
@@ -846,13 +859,14 @@ public class IpServer extends StateMachine {
}
// If we're here to process a NeighborEvent, do so now.
+ // mInterfaceParams must be non-null or the event would not have arrived.
if (e == null) return;
if (!(e.ip instanceof Inet6Address) || e.ip.isMulticastAddress()
|| e.ip.isLoopbackAddress() || e.ip.isLinkLocalAddress()) {
return;
}
- Ipv6ForwardingRule rule = new Ipv6ForwardingRule(mLastIPv6UpstreamIfindex,
+ Ipv6ForwardingRule rule = new Ipv6ForwardingRule(upstreamIfindex,
mInterfaceParams.index, (Inet6Address) e.ip, mInterfaceParams.macAddr,
e.macAddr);
if (e.isValid()) {
@@ -1095,6 +1109,7 @@ public class IpServer extends StateMachine {
for (String ifname : mUpstreamIfaceSet.ifnames) cleanupUpstreamInterface(ifname);
mUpstreamIfaceSet = null;
+ clearIpv6ForwardingRules();
}
private void cleanupUpstreamInterface(String upstreamIface) {
diff --git a/packages/Tethering/src/com/android/server/connectivity/tethering/OffloadController.java b/packages/Tethering/src/com/android/server/connectivity/tethering/OffloadController.java
index cc36f4a9c516..a402ffa47355 100644
--- a/packages/Tethering/src/com/android/server/connectivity/tethering/OffloadController.java
+++ b/packages/Tethering/src/com/android/server/connectivity/tethering/OffloadController.java
@@ -288,10 +288,18 @@ public class OffloadController {
@Override
public void setLimit(String iface, long quotaBytes) {
- mLog.i("setLimit: " + iface + "," + quotaBytes);
// Listen for all iface is necessary since upstream might be changed after limit
// is set.
mHandler.post(() -> {
+ final Long curIfaceQuota = mInterfaceQuotas.get(iface);
+
+ // If the quota is set to unlimited, the value set to HAL is Long.MAX_VALUE,
+ // which is ~8.4 x 10^6 TiB, no one can actually reach it. Thus, it is not
+ // useful to set it multiple times.
+ // Otherwise, the quota needs to be updated to tell HAL to re-count from now even
+ // if the quota is the same as the existing one.
+ if (null == curIfaceQuota && QUOTA_UNLIMITED == quotaBytes) return;
+
if (quotaBytes == QUOTA_UNLIMITED) {
mInterfaceQuotas.remove(iface);
} else {
@@ -323,7 +331,6 @@ public class OffloadController {
@Override
public void requestStatsUpdate(int token) {
- mLog.i("requestStatsUpdate: " + token);
// Do not attempt to update stats by querying the offload HAL
// synchronously from a different thread than the Handler thread. http://b/64771555.
mHandler.post(() -> {
diff --git a/packages/Tethering/src/com/android/server/connectivity/tethering/Tethering.java b/packages/Tethering/src/com/android/server/connectivity/tethering/Tethering.java
index ca74430f706c..f89da849ea91 100644
--- a/packages/Tethering/src/com/android/server/connectivity/tethering/Tethering.java
+++ b/packages/Tethering/src/com/android/server/connectivity/tethering/Tethering.java
@@ -44,6 +44,9 @@ import static android.net.TetheringManager.TETHER_ERROR_NO_ERROR;
import static android.net.TetheringManager.TETHER_ERROR_SERVICE_UNAVAIL;
import static android.net.TetheringManager.TETHER_ERROR_UNAVAIL_IFACE;
import static android.net.TetheringManager.TETHER_ERROR_UNKNOWN_IFACE;
+import static android.net.TetheringManager.TETHER_HARDWARE_OFFLOAD_FAILED;
+import static android.net.TetheringManager.TETHER_HARDWARE_OFFLOAD_STARTED;
+import static android.net.TetheringManager.TETHER_HARDWARE_OFFLOAD_STOPPED;
import static android.net.util.TetheringMessageBase.BASE_MASTER;
import static android.net.wifi.WifiManager.EXTRA_WIFI_AP_INTERFACE_NAME;
import static android.net.wifi.WifiManager.EXTRA_WIFI_AP_MODE;
@@ -220,6 +223,7 @@ public class Tethering {
private final UserRestrictionActionListener mTetheringRestriction;
private final ActiveDataSubIdListener mActiveDataSubIdListener;
private final ConnectedClientsTracker mConnectedClientsTracker;
+ private final TetheringThreadExecutor mExecutor;
private int mActiveDataSubId = INVALID_SUBSCRIPTION_ID;
// All the usage of mTetheringEventCallback should run in the same thread.
private ITetheringEventCallback mTetheringEventCallback = null;
@@ -236,6 +240,7 @@ public class Tethering {
private TetherStatesParcel mTetherStatesParcel;
private boolean mDataSaverEnabled = false;
private String mWifiP2pTetherInterface = null;
+ private int mOffloadStatus = TETHER_HARDWARE_OFFLOAD_STOPPED;
@GuardedBy("mPublicSync")
private EthernetManager.TetheredInterfaceRequest mEthernetIfaceRequest;
@@ -296,8 +301,8 @@ public class Tethering {
final UserManager userManager = (UserManager) mContext.getSystemService(
Context.USER_SERVICE);
mTetheringRestriction = new UserRestrictionActionListener(userManager, this);
- final TetheringThreadExecutor executor = new TetheringThreadExecutor(mHandler);
- mActiveDataSubIdListener = new ActiveDataSubIdListener(executor);
+ mExecutor = new TetheringThreadExecutor(mHandler);
+ mActiveDataSubIdListener = new ActiveDataSubIdListener(mExecutor);
// Load tethering configuration.
updateConfiguration();
@@ -315,9 +320,7 @@ public class Tethering {
final WifiManager wifiManager = getWifiManager();
if (wifiManager != null) {
- wifiManager.registerSoftApCallback(
- mHandler::post /* executor */,
- new TetheringSoftApCallback());
+ wifiManager.registerSoftApCallback(mExecutor, new TetheringSoftApCallback());
}
}
@@ -606,14 +609,17 @@ public class Tethering {
Context.ETHERNET_SERVICE);
synchronized (mPublicSync) {
if (enable) {
+ if (mEthernetCallback != null) return TETHER_ERROR_NO_ERROR;
+
mEthernetCallback = new EthernetCallback();
- mEthernetIfaceRequest = em.requestTetheredInterface(mEthernetCallback);
+ mEthernetIfaceRequest = em.requestTetheredInterface(mExecutor, mEthernetCallback);
} else {
- if (mConfiguredEthernetIface != null) {
- stopEthernetTetheringLocked();
+ stopEthernetTetheringLocked();
+ if (mEthernetCallback != null) {
mEthernetIfaceRequest.release();
+ mEthernetCallback = null;
+ mEthernetIfaceRequest = null;
}
- mEthernetCallback = null;
}
}
return TETHER_ERROR_NO_ERROR;
@@ -1899,12 +1905,15 @@ public class Tethering {
// OffloadController implementation.
class OffloadWrapper {
public void start() {
- mOffloadController.start();
+ final int status = mOffloadController.start() ? TETHER_HARDWARE_OFFLOAD_STARTED
+ : TETHER_HARDWARE_OFFLOAD_FAILED;
+ updateOffloadStatus(status);
sendOffloadExemptPrefixes();
}
public void stop() {
mOffloadController.stop();
+ updateOffloadStatus(TETHER_HARDWARE_OFFLOAD_STOPPED);
}
public void updateUpstreamNetworkState(UpstreamNetworkState ns) {
@@ -1965,6 +1974,13 @@ public class Tethering {
mOffloadController.setLocalPrefixes(localPrefixes);
}
+
+ private void updateOffloadStatus(final int newStatus) {
+ if (newStatus == mOffloadStatus) return;
+
+ mOffloadStatus = newStatus;
+ reportOffloadStatusChanged(mOffloadStatus);
+ }
}
}
@@ -1999,6 +2015,7 @@ public class Tethering {
parcel.tetheredClients = hasListPermission
? mConnectedClientsTracker.getLastTetheredClients()
: Collections.emptyList();
+ parcel.offloadStatus = mOffloadStatus;
try {
callback.onCallbackStarted(parcel);
} catch (RemoteException e) {
@@ -2093,6 +2110,21 @@ public class Tethering {
}
}
+ private void reportOffloadStatusChanged(final int status) {
+ final int length = mTetheringEventCallbacks.beginBroadcast();
+ try {
+ for (int i = 0; i < length; i++) {
+ try {
+ mTetheringEventCallbacks.getBroadcastItem(i).onOffloadStatusChanged(status);
+ } catch (RemoteException e) {
+ // Not really very much to do here.
+ }
+ }
+ } finally {
+ mTetheringEventCallbacks.finishBroadcast();
+ }
+ }
+
void dump(@NonNull FileDescriptor fd, @NonNull PrintWriter writer, @Nullable String[] args) {
// Binder.java closes the resource for us.
@SuppressWarnings("resource")
diff --git a/packages/Tethering/tests/unit/src/android/net/ip/IpServerTest.java b/packages/Tethering/tests/unit/src/android/net/ip/IpServerTest.java
index 33b35586eecf..948266d3cf50 100644
--- a/packages/Tethering/tests/unit/src/android/net/ip/IpServerTest.java
+++ b/packages/Tethering/tests/unit/src/android/net/ip/IpServerTest.java
@@ -43,6 +43,7 @@ import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;
import static org.mockito.ArgumentMatchers.argThat;
import static org.mockito.Matchers.any;
+import static org.mockito.Matchers.anyInt;
import static org.mockito.Matchers.anyString;
import static org.mockito.Matchers.eq;
import static org.mockito.Mockito.doAnswer;
@@ -546,9 +547,9 @@ public class IpServerTest {
reset(mNetd);
// Link-local and multicast neighbors are ignored.
- recvNewNeigh(notMyIfindex, neighLL, NUD_REACHABLE, macA);
+ recvNewNeigh(myIfindex, neighLL, NUD_REACHABLE, macA);
verifyNoMoreInteractions(mNetd);
- recvNewNeigh(notMyIfindex, neighMC, NUD_REACHABLE, macA);
+ recvNewNeigh(myIfindex, neighMC, NUD_REACHABLE, macA);
verifyNoMoreInteractions(mNetd);
// A neighbor that is no longer valid causes the rule to be removed.
@@ -578,6 +579,52 @@ public class IpServerTest {
eq(neighB.getAddress()), eq(myMac.toByteArray()), eq(macB.toByteArray()));
inOrder.verify(mNetd).tetherRuleRemoveDownstreamIpv6(eq(UPSTREAM_IFINDEX),
eq(neighB.getAddress()));
+ reset(mNetd);
+
+ // When the upstream is lost, rules are removed.
+ dispatchTetherConnectionChanged(null, null);
+ verify(mNetd).tetherRuleRemoveDownstreamIpv6(eq(UPSTREAM_IFINDEX2),
+ eq(neighA.getAddress()));
+ verify(mNetd).tetherRuleRemoveDownstreamIpv6(eq(UPSTREAM_IFINDEX2),
+ eq(neighB.getAddress()));
+ reset(mNetd);
+
+ // If the upstream is IPv4-only, no rules are added.
+ dispatchTetherConnectionChanged(UPSTREAM_IFACE);
+ reset(mNetd);
+ recvNewNeigh(myIfindex, neighA, NUD_REACHABLE, macA);
+ verifyNoMoreInteractions(mNetd);
+
+ // Rules can be added again once upstream IPv6 connectivity is available.
+ lp.setInterfaceName(UPSTREAM_IFACE);
+ dispatchTetherConnectionChanged(UPSTREAM_IFACE, lp);
+ recvNewNeigh(myIfindex, neighB, NUD_REACHABLE, macB);
+ verify(mNetd).tetherRuleAddDownstreamIpv6(eq(myIfindex), eq(UPSTREAM_IFINDEX),
+ eq(neighB.getAddress()), eq(myMac.toByteArray()), eq(macB.toByteArray()));
+ verify(mNetd, never()).tetherRuleAddDownstreamIpv6(anyInt(), anyInt(),
+ eq(neighA.getAddress()), any(), any());
+
+ // If upstream IPv6 connectivity is lost, rules are removed.
+ reset(mNetd);
+ dispatchTetherConnectionChanged(UPSTREAM_IFACE, null);
+ verify(mNetd).tetherRuleRemoveDownstreamIpv6(eq(UPSTREAM_IFINDEX), eq(neighB.getAddress()));
+
+ // When the interface goes down, rules are removed.
+ lp.setInterfaceName(UPSTREAM_IFACE);
+ dispatchTetherConnectionChanged(UPSTREAM_IFACE, lp);
+ recvNewNeigh(myIfindex, neighA, NUD_REACHABLE, macA);
+ recvNewNeigh(myIfindex, neighB, NUD_REACHABLE, macB);
+ verify(mNetd).tetherRuleAddDownstreamIpv6(eq(myIfindex), eq(UPSTREAM_IFINDEX),
+ eq(neighA.getAddress()), eq(myMac.toByteArray()), eq(macA.toByteArray()));
+ verify(mNetd).tetherRuleAddDownstreamIpv6(eq(myIfindex), eq(UPSTREAM_IFINDEX),
+ eq(neighB.getAddress()), eq(myMac.toByteArray()), eq(macB.toByteArray()));
+ reset(mNetd);
+
+ mIpServer.stop();
+ mLooper.dispatchAll();
+ verify(mNetd).tetherRuleRemoveDownstreamIpv6(eq(UPSTREAM_IFINDEX), eq(neighA.getAddress()));
+ verify(mNetd).tetherRuleRemoveDownstreamIpv6(eq(UPSTREAM_IFINDEX), eq(neighB.getAddress()));
+ reset(mNetd);
}
private void assertDhcpStarted(IpPrefix expectedPrefix) throws Exception {
@@ -624,16 +671,15 @@ public class IpServerTest {
* @param v6lp IPv6 LinkProperties of the upstream interface, or null for an IPv4-only upstream.
*/
private void dispatchTetherConnectionChanged(String upstreamIface, LinkProperties v6lp) {
- mIpServer.sendMessage(IpServer.CMD_TETHER_CONNECTION_CHANGED,
- new InterfaceSet(upstreamIface));
- if (v6lp != null) {
- mIpServer.sendMessage(IpServer.CMD_IPV6_TETHER_UPDATE, v6lp);
- }
+ dispatchTetherConnectionChanged(upstreamIface);
+ mIpServer.sendMessage(IpServer.CMD_IPV6_TETHER_UPDATE, v6lp);
mLooper.dispatchAll();
}
private void dispatchTetherConnectionChanged(String upstreamIface) {
- dispatchTetherConnectionChanged(upstreamIface, null);
+ final InterfaceSet ifs = (upstreamIface != null) ? new InterfaceSet(upstreamIface) : null;
+ mIpServer.sendMessage(IpServer.CMD_TETHER_CONNECTION_CHANGED, ifs);
+ mLooper.dispatchAll();
}
private void assertIPv4AddressAndDirectlyConnectedRoute(LinkProperties lp) {
diff --git a/packages/Tethering/tests/unit/src/com/android/server/connectivity/tethering/TetheringTest.java b/packages/Tethering/tests/unit/src/com/android/server/connectivity/tethering/TetheringTest.java
index f2074bd46886..af7ad662b8a5 100644
--- a/packages/Tethering/tests/unit/src/com/android/server/connectivity/tethering/TetheringTest.java
+++ b/packages/Tethering/tests/unit/src/com/android/server/connectivity/tethering/TetheringTest.java
@@ -28,11 +28,15 @@ import static android.net.TetheringManager.ACTION_TETHER_STATE_CHANGED;
import static android.net.TetheringManager.EXTRA_ACTIVE_LOCAL_ONLY;
import static android.net.TetheringManager.EXTRA_ACTIVE_TETHER;
import static android.net.TetheringManager.EXTRA_AVAILABLE_TETHER;
+import static android.net.TetheringManager.TETHERING_ETHERNET;
import static android.net.TetheringManager.TETHERING_NCM;
import static android.net.TetheringManager.TETHERING_USB;
import static android.net.TetheringManager.TETHERING_WIFI;
import static android.net.TetheringManager.TETHER_ERROR_NO_ERROR;
import static android.net.TetheringManager.TETHER_ERROR_UNKNOWN_IFACE;
+import static android.net.TetheringManager.TETHER_HARDWARE_OFFLOAD_FAILED;
+import static android.net.TetheringManager.TETHER_HARDWARE_OFFLOAD_STARTED;
+import static android.net.TetheringManager.TETHER_HARDWARE_OFFLOAD_STOPPED;
import static android.net.dhcp.IDhcpServer.STATUS_SUCCESS;
import static android.net.wifi.WifiManager.EXTRA_WIFI_AP_INTERFACE_NAME;
import static android.net.wifi.WifiManager.EXTRA_WIFI_AP_MODE;
@@ -75,6 +79,8 @@ import android.content.pm.ApplicationInfo;
import android.content.res.Resources;
import android.hardware.usb.UsbManager;
import android.net.ConnectivityManager;
+import android.net.EthernetManager;
+import android.net.EthernetManager.TetheredInterfaceRequest;
import android.net.INetd;
import android.net.ITetheringEventCallback;
import android.net.InetAddresses;
@@ -166,6 +172,7 @@ public class TetheringTest {
@Mock private Context mContext;
@Mock private NetworkStatsManager mStatsManager;
@Mock private OffloadHardwareInterface mOffloadHardwareInterface;
+ @Mock private OffloadHardwareInterface.ForwardedStats mForwardedStats;
@Mock private Resources mResources;
@Mock private TelephonyManager mTelephonyManager;
@Mock private UsbManager mUsbManager;
@@ -180,6 +187,7 @@ public class TetheringTest {
@Mock private UserManager mUserManager;
@Mock private NetworkRequest mNetworkRequest;
@Mock private ConnectivityManager mCm;
+ @Mock private EthernetManager mEm;
private final MockIpServerDependencies mIpServerDependencies =
spy(new MockIpServerDependencies());
@@ -232,6 +240,7 @@ public class TetheringTest {
if (Context.USER_SERVICE.equals(name)) return mUserManager;
if (Context.NETWORK_STATS_SERVICE.equals(name)) return mStatsManager;
if (Context.CONNECTIVITY_SERVICE.equals(name)) return mCm;
+ if (Context.ETHERNET_SERVICE.equals(name)) return mEm;
return super.getSystemService(name);
}
@@ -458,6 +467,9 @@ public class TetheringTest {
mInterfaceConfiguration.flags = new String[0];
when(mRouterAdvertisementDaemon.start())
.thenReturn(true);
+ initOffloadConfiguration(true /* offloadConfig */, true /* offloadControl */,
+ 0 /* defaultDisabled */);
+ when(mOffloadHardwareInterface.getForwardedStats(any())).thenReturn(mForwardedStats);
mServiceContext = new TestContext(mContext);
when(mContext.getSystemService(Context.NOTIFICATION_SERVICE)).thenReturn(null);
@@ -1131,6 +1143,7 @@ public class TetheringTest {
private final ArrayList<TetheringConfigurationParcel> mTetheringConfigs =
new ArrayList<>();
private final ArrayList<TetherStatesParcel> mTetherStates = new ArrayList<>();
+ private final ArrayList<Integer> mOffloadStatus = new ArrayList<>();
// This function will remove the recorded callbacks, so it must be called once for
// each callback. If this is called after multiple callback, the order matters.
@@ -1166,6 +1179,11 @@ public class TetheringTest {
assertNoConfigChangeCallback();
}
+ public void expectOffloadStatusChanged(final int expectedStatus) {
+ assertOffloadStatusChangedCallback();
+ assertEquals(mOffloadStatus.remove(0), new Integer(expectedStatus));
+ }
+
public TetherStatesParcel pollTetherStatesChanged() {
assertStateChangeCallback();
return mTetherStates.remove(0);
@@ -1192,10 +1210,16 @@ public class TetheringTest {
}
@Override
+ public void onOffloadStatusChanged(final int status) {
+ mOffloadStatus.add(status);
+ }
+
+ @Override
public void onCallbackStarted(TetheringCallbackStartedParcel parcel) {
mActualUpstreams.add(parcel.upstreamNetwork);
mTetheringConfigs.add(parcel.config);
mTetherStates.add(parcel.states);
+ mOffloadStatus.add(parcel.offloadStatus);
}
@Override
@@ -1217,6 +1241,10 @@ public class TetheringTest {
assertFalse(mTetherStates.isEmpty());
}
+ public void assertOffloadStatusChangedCallback() {
+ assertFalse(mOffloadStatus.isEmpty());
+ }
+
public void assertNoCallback() {
assertNoUpstreamChangeCallback();
assertNoConfigChangeCallback();
@@ -1265,6 +1293,7 @@ public class TetheringTest {
mTethering.getTetheringConfiguration().toStableParcelable());
TetherStatesParcel tetherState = callback.pollTetherStatesChanged();
assertTetherStatesNotNullButEmpty(tetherState);
+ callback.expectOffloadStatusChanged(TETHER_HARDWARE_OFFLOAD_STOPPED);
// 2. Enable wifi tethering.
UpstreamNetworkState upstreamState = buildMobileDualStackUpstreamState();
when(mUpstreamNetworkMonitor.getCurrentPreferredUpstream()).thenReturn(upstreamState);
@@ -1282,6 +1311,7 @@ public class TetheringTest {
tetherState = callback.pollTetherStatesChanged();
assertArrayEquals(tetherState.tetheredList, new String[] {TEST_WLAN_IFNAME});
callback.expectUpstreamChanged(upstreamState.network);
+ callback.expectOffloadStatusChanged(TETHER_HARDWARE_OFFLOAD_STARTED);
// 3. Register second callback.
mTethering.registerTetheringEventCallback(callback2);
@@ -1291,6 +1321,7 @@ public class TetheringTest {
mTethering.getTetheringConfiguration().toStableParcelable());
tetherState = callback2.pollTetherStatesChanged();
assertEquals(tetherState.tetheredList, new String[] {TEST_WLAN_IFNAME});
+ callback2.expectOffloadStatusChanged(TETHER_HARDWARE_OFFLOAD_STARTED);
// 4. Unregister first callback and disable wifi tethering
mTethering.unregisterTetheringEventCallback(callback);
@@ -1302,10 +1333,59 @@ public class TetheringTest {
assertArrayEquals(tetherState.availableList, new String[] {TEST_WLAN_IFNAME});
mLooper.dispatchAll();
callback2.expectUpstreamChanged(new Network[] {null});
+ callback2.expectOffloadStatusChanged(TETHER_HARDWARE_OFFLOAD_STOPPED);
callback.assertNoCallback();
}
@Test
+ public void testReportFailCallbackIfOffloadNotSupported() throws Exception {
+ final UpstreamNetworkState upstreamState = buildMobileDualStackUpstreamState();
+ TestTetheringEventCallback callback = new TestTetheringEventCallback();
+ mTethering.registerTetheringEventCallback(callback);
+ mLooper.dispatchAll();
+ callback.expectOffloadStatusChanged(TETHER_HARDWARE_OFFLOAD_STOPPED);
+
+ // 1. Offload fail if no OffloadConfig.
+ initOffloadConfiguration(false /* offloadConfig */, true /* offloadControl */,
+ 0 /* defaultDisabled */);
+ runUsbTethering(upstreamState);
+ callback.expectOffloadStatusChanged(TETHER_HARDWARE_OFFLOAD_FAILED);
+ runStopUSBTethering();
+ callback.expectOffloadStatusChanged(TETHER_HARDWARE_OFFLOAD_STOPPED);
+ reset(mUsbManager);
+ // 2. Offload fail if no OffloadControl.
+ initOffloadConfiguration(true /* offloadConfig */, false /* offloadControl */,
+ 0 /* defaultDisabled */);
+ runUsbTethering(upstreamState);
+ callback.expectOffloadStatusChanged(TETHER_HARDWARE_OFFLOAD_FAILED);
+ runStopUSBTethering();
+ callback.expectOffloadStatusChanged(TETHER_HARDWARE_OFFLOAD_STOPPED);
+ reset(mUsbManager);
+ // 3. Offload fail if disabled by settings.
+ initOffloadConfiguration(true /* offloadConfig */, true /* offloadControl */,
+ 1 /* defaultDisabled */);
+ runUsbTethering(upstreamState);
+ callback.expectOffloadStatusChanged(TETHER_HARDWARE_OFFLOAD_FAILED);
+ runStopUSBTethering();
+ callback.expectOffloadStatusChanged(TETHER_HARDWARE_OFFLOAD_STOPPED);
+ }
+
+ private void runStopUSBTethering() {
+ mTethering.stopTethering(TETHERING_USB);
+ mLooper.dispatchAll();
+ mTethering.interfaceRemoved(TEST_USB_IFNAME);
+ mLooper.dispatchAll();
+ }
+
+ private void initOffloadConfiguration(final boolean offloadConfig,
+ final boolean offloadControl, final int defaultDisabled) {
+ when(mOffloadHardwareInterface.initOffloadConfig()).thenReturn(offloadConfig);
+ when(mOffloadHardwareInterface.initOffloadControl(any())).thenReturn(offloadControl);
+ when(mOffloadHardwareInterface.getDefaultTetherOffloadDisabled()).thenReturn(
+ defaultDisabled);
+ }
+
+ @Test
public void testMultiSimAware() throws Exception {
final TetheringConfiguration initailConfig = mTethering.getTetheringConfiguration();
assertEquals(INVALID_SUBSCRIPTION_ID, initailConfig.activeDataSubId);
@@ -1316,6 +1396,24 @@ public class TetheringTest {
assertEquals(fakeSubId, newConfig.activeDataSubId);
}
+ @Test
+ public void testNoDuplicatedEthernetRequest() throws Exception {
+ final TetheredInterfaceRequest mockRequest = mock(TetheredInterfaceRequest.class);
+ when(mEm.requestTetheredInterface(any(), any())).thenReturn(mockRequest);
+ mTethering.startTethering(createTetheringRquestParcel(TETHERING_ETHERNET), null);
+ mLooper.dispatchAll();
+ verify(mEm, times(1)).requestTetheredInterface(any(), any());
+ mTethering.startTethering(createTetheringRquestParcel(TETHERING_ETHERNET), null);
+ mLooper.dispatchAll();
+ verifyNoMoreInteractions(mEm);
+ mTethering.stopTethering(TETHERING_ETHERNET);
+ mLooper.dispatchAll();
+ verify(mockRequest, times(1)).release();
+ mTethering.stopTethering(TETHERING_ETHERNET);
+ mLooper.dispatchAll();
+ verifyNoMoreInteractions(mEm);
+ }
+
private void workingWifiP2pGroupOwner(
boolean emulateInterfaceStatusChanged) throws Exception {
if (emulateInterfaceStatusChanged) {
diff --git a/services/art-profile b/services/art-profile
index 9a2023df2d28..ab55bfc377d7 100644
--- a/services/art-profile
+++ b/services/art-profile
@@ -16817,10 +16817,6 @@ HSPLcom/android/server/incident/RequestQueue;-><init>(Landroid/os/Handler;)V
PLcom/android/server/incident/RequestQueue;->access$000(Lcom/android/server/incident/RequestQueue;)Ljava/util/ArrayList;
PLcom/android/server/incident/RequestQueue;->enqueue(Landroid/os/IBinder;ZLjava/lang/Runnable;)V
PLcom/android/server/incident/RequestQueue;->start()V
-HSPLcom/android/server/incremental/IncrementalManagerService;-><init>(Landroid/content/Context;)V
-PLcom/android/server/incremental/IncrementalManagerService;->dump(Ljava/io/FileDescriptor;Ljava/io/PrintWriter;[Ljava/lang/String;)V
-HSPLcom/android/server/incremental/IncrementalManagerService;->start(Landroid/content/Context;)Lcom/android/server/incremental/IncrementalManagerService;
-PLcom/android/server/incremental/IncrementalManagerService;->systemReady()V
HPLcom/android/server/infra/-$$Lambda$AbstractMasterSystemService$1$TLhe3_2yHs5UB69Y7lf2s7OxJCo;-><init>(Ljava/lang/String;)V
PLcom/android/server/infra/-$$Lambda$AbstractMasterSystemService$1$TLhe3_2yHs5UB69Y7lf2s7OxJCo;->visit(Ljava/lang/Object;)V
HSPLcom/android/server/infra/-$$Lambda$AbstractMasterSystemService$_fKw-VUP0pSfcMMlgRqoT4OPhxw;-><init>(Lcom/android/server/infra/AbstractMasterSystemService;Ljava/lang/String;)V
@@ -43466,8 +43462,6 @@ Lcom/android/server/incident/PendingReports;
Lcom/android/server/incident/RequestQueue$1;
Lcom/android/server/incident/RequestQueue$Rec;
Lcom/android/server/incident/RequestQueue;
-Lcom/android/server/incremental/IncrementalManagerService;
-Lcom/android/server/incremental/IncrementalManagerShellCommand;
Lcom/android/server/infra/-$$Lambda$AbstractMasterSystemService$1$TLhe3_2yHs5UB69Y7lf2s7OxJCo;
Lcom/android/server/infra/-$$Lambda$AbstractMasterSystemService$_fKw-VUP0pSfcMMlgRqoT4OPhxw;
Lcom/android/server/infra/-$$Lambda$AbstractMasterSystemService$su3lJpEVIbL-C7doP4eboTpqjxU;
diff --git a/services/autofill/java/com/android/server/autofill/RemoteAugmentedAutofillService.java b/services/autofill/java/com/android/server/autofill/RemoteAugmentedAutofillService.java
index 2420e69b5d90..e73f9ce4f7c0 100644
--- a/services/autofill/java/com/android/server/autofill/RemoteAugmentedAutofillService.java
+++ b/services/autofill/java/com/android/server/autofill/RemoteAugmentedAutofillService.java
@@ -37,7 +37,7 @@ import android.os.ICancellationSignal;
import android.os.RemoteException;
import android.os.SystemClock;
import android.service.autofill.Dataset;
-import android.service.autofill.InlinePresentation;
+import android.service.autofill.InlineAction;
import android.service.autofill.augmented.AugmentedAutofillService;
import android.service.autofill.augmented.IAugmentedAutofillService;
import android.service.autofill.augmented.IFillCallback;
@@ -167,7 +167,7 @@ final class RemoteAugmentedAutofillService
new IFillCallback.Stub() {
@Override
public void onSuccess(@Nullable List<Dataset> inlineSuggestionsData,
- @Nullable List<InlinePresentation> inlineActions) {
+ @Nullable List<InlineAction> inlineActions) {
mCallbacks.resetLastResponse();
maybeRequestShowInlineSuggestions(sessionId,
inlineSuggestionsRequest, inlineSuggestionsData,
@@ -237,7 +237,7 @@ final class RemoteAugmentedAutofillService
private void maybeRequestShowInlineSuggestions(int sessionId,
@Nullable InlineSuggestionsRequest request,
@Nullable List<Dataset> inlineSuggestionsData,
- @Nullable List<InlinePresentation> inlineActions, @NonNull AutofillId focusedId,
+ @Nullable List<InlineAction> inlineActions, @NonNull AutofillId focusedId,
@Nullable Function<InlineSuggestionsResponse, Boolean> inlineSuggestionsCallback,
@NonNull IAutoFillManagerClient client, @NonNull Runnable onErrorCallback,
@Nullable RemoteInlineSuggestionRenderService remoteRenderService) {
@@ -250,7 +250,7 @@ final class RemoteAugmentedAutofillService
final InlineSuggestionsResponse inlineSuggestionsResponse =
InlineSuggestionFactory.createAugmentedInlineSuggestionsResponse(
- request, inlineSuggestionsData, inlineActions, focusedId, mContext,
+ request, inlineSuggestionsData, inlineActions, focusedId,
dataset -> {
mCallbacks.logAugmentedAutofillSelected(sessionId,
dataset.getId());
diff --git a/services/autofill/java/com/android/server/autofill/Session.java b/services/autofill/java/com/android/server/autofill/Session.java
index f14a7e906c5d..538082d2f67e 100644
--- a/services/autofill/java/com/android/server/autofill/Session.java
+++ b/services/autofill/java/com/android/server/autofill/Session.java
@@ -137,7 +137,6 @@ final class Session implements RemoteFillService.FillServiceCallbacks, ViewState
private final Handler mHandler;
private final Object mLock;
private final AutoFillUI mUi;
- private final Context mContext;
private final MetricsLogger mMetricsLogger = new MetricsLogger();
@@ -695,7 +694,6 @@ final class Session implements RemoteFillService.FillServiceCallbacks, ViewState
mLock = lock;
mUi = ui;
mHandler = handler;
- mContext = context;
mRemoteFillService = serviceComponentName == null ? null
: new RemoteFillService(context, serviceComponentName, userId, this,
bindInstantServiceAllowed);
@@ -2680,10 +2678,10 @@ final class Session implements RemoteFillService.FillServiceCallbacks, ViewState
InlineSuggestionsResponse inlineSuggestionsResponse =
InlineSuggestionFactory.createInlineSuggestionsResponse(
inlineSuggestionsRequest.get(),
- response, filterText, response.getInlineActions(), mCurrentViewId, mContext,
+ response, filterText, response.getInlineActions(), mCurrentViewId,
this, () -> {
synchronized (mLock) {
- requestHideFillUi(mCurrentViewId);
+ mInlineSuggestionSession.hideInlineSuggestionsUi(mCurrentViewId);
}
}, remoteRenderService);
if (inlineSuggestionsResponse == null) {
diff --git a/services/autofill/java/com/android/server/autofill/ui/InlineSuggestionFactory.java b/services/autofill/java/com/android/server/autofill/ui/InlineSuggestionFactory.java
index 4cf4463feaad..ee59d89b7f15 100644
--- a/services/autofill/java/com/android/server/autofill/ui/InlineSuggestionFactory.java
+++ b/services/autofill/java/com/android/server/autofill/ui/InlineSuggestionFactory.java
@@ -21,12 +21,13 @@ import static com.android.server.autofill.Helper.sVerbose;
import android.annotation.NonNull;
import android.annotation.Nullable;
-import android.content.Context;
+import android.content.IntentSender;
import android.os.IBinder;
import android.os.RemoteException;
import android.service.autofill.Dataset;
import android.service.autofill.FillResponse;
import android.service.autofill.IInlineSuggestionUiCallback;
+import android.service.autofill.InlineAction;
import android.service.autofill.InlinePresentation;
import android.text.TextUtils;
import android.util.Slog;
@@ -39,7 +40,6 @@ import android.view.inputmethod.InlineSuggestion;
import android.view.inputmethod.InlineSuggestionInfo;
import android.view.inputmethod.InlineSuggestionsRequest;
import android.view.inputmethod.InlineSuggestionsResponse;
-import android.widget.Toast;
import com.android.internal.view.inline.IInlineContentCallback;
import com.android.internal.view.inline.IInlineContentProvider;
@@ -73,8 +73,8 @@ public final class InlineSuggestionFactory {
@Nullable
public static InlineSuggestionsResponse createInlineSuggestionsResponse(
@NonNull InlineSuggestionsRequest request, @NonNull FillResponse response,
- @Nullable String filterText, @Nullable List<InlinePresentation> inlineActions,
- @NonNull AutofillId autofillId, @NonNull Context context,
+ @Nullable String filterText, @Nullable List<InlineAction> inlineActions,
+ @NonNull AutofillId autofillId,
@NonNull AutoFillUI.AutoFillUiCallback client, @NonNull Runnable onErrorCallback,
@Nullable RemoteInlineSuggestionRenderService remoteRenderService) {
if (sDebug) Slog.d(TAG, "createInlineSuggestionsResponse called");
@@ -97,7 +97,7 @@ public final class InlineSuggestionFactory {
response.getAuthentication() == null ? null : response.getInlinePresentation();
return createInlineSuggestionsResponseInternal(/* isAugmented= */ false, request,
response.getDatasets(), filterText, inlineAuthentication, inlineActions, autofillId,
- context, onErrorCallback, onClickFactory, remoteRenderService);
+ onErrorCallback, onClickFactory, remoteRenderService);
}
/**
@@ -107,15 +107,14 @@ public final class InlineSuggestionFactory {
@Nullable
public static InlineSuggestionsResponse createAugmentedInlineSuggestionsResponse(
@NonNull InlineSuggestionsRequest request, @NonNull List<Dataset> datasets,
- @Nullable List<InlinePresentation> inlineActions,
- @NonNull AutofillId autofillId, @NonNull Context context,
+ @Nullable List<InlineAction> inlineActions, @NonNull AutofillId autofillId,
@NonNull InlineSuggestionUiCallback inlineSuggestionUiCallback,
@NonNull Runnable onErrorCallback,
@Nullable RemoteInlineSuggestionRenderService remoteRenderService) {
if (sDebug) Slog.d(TAG, "createAugmentedInlineSuggestionsResponse called");
return createInlineSuggestionsResponseInternal(/* isAugmented= */ true, request,
datasets, /* filterText= */ null, /* inlineAuthentication= */ null,
- inlineActions, autofillId, context, onErrorCallback,
+ inlineActions, autofillId, onErrorCallback,
(dataset, datasetIndex) ->
inlineSuggestionUiCallback.autofill(dataset), remoteRenderService);
}
@@ -125,9 +124,8 @@ public final class InlineSuggestionFactory {
boolean isAugmented, @NonNull InlineSuggestionsRequest request,
@Nullable List<Dataset> datasets, @Nullable String filterText,
@Nullable InlinePresentation inlineAuthentication,
- @Nullable List<InlinePresentation> inlineActions, @NonNull AutofillId autofillId,
- @NonNull Context context, @NonNull Runnable onErrorCallback,
- @NonNull BiConsumer<Dataset, Integer> onClickFactory,
+ @Nullable List<InlineAction> inlineActions, @NonNull AutofillId autofillId,
+ @NonNull Runnable onErrorCallback, @NonNull BiConsumer<Dataset, Integer> onClickFactory,
@Nullable RemoteInlineSuggestionRenderService remoteRenderService) {
final ArrayList<InlineSuggestion> inlineSuggestions = new ArrayList<>();
@@ -169,14 +167,14 @@ public final class InlineSuggestionFactory {
inlineSuggestions.add(inlineSuggestion);
}
- // We should only add inline actions if there is at least one suggestion.
- if (!inlineSuggestions.isEmpty() && inlineActions != null) {
- for (InlinePresentation inlinePresentation : inlineActions) {
- final InlineSuggestion inlineAction = createInlineAction(isAugmented, context,
- mergedInlinePresentation(request, 0, inlinePresentation),
+ if (inlineActions != null) {
+ for (InlineAction inlineAction : inlineActions) {
+ final InlineSuggestion inlineActionSuggestion = createInlineAction(isAugmented,
+ mergedInlinePresentation(request, 0, inlineAction.getInlinePresentation()),
+ inlineAction.getAction(),
remoteRenderService, onErrorCallback, request.getHostInputToken(),
request.getHostDisplayId());
- inlineSuggestions.add(inlineAction);
+ inlineSuggestions.add(inlineActionSuggestion);
}
}
return new InlineSuggestionsResponse(inlineSuggestions);
@@ -215,22 +213,30 @@ public final class InlineSuggestionFactory {
private static InlineSuggestion createInlineAction(boolean isAugmented,
- @NonNull Context context,
- @NonNull InlinePresentation inlinePresentation,
+ @NonNull InlinePresentation presentation,
+ @NonNull IntentSender action,
@Nullable RemoteInlineSuggestionRenderService remoteRenderService,
@NonNull Runnable onErrorCallback, @Nullable IBinder hostInputToken,
int displayId) {
final InlineSuggestionInfo inlineSuggestionInfo = new InlineSuggestionInfo(
- inlinePresentation.getInlinePresentationSpec(),
+ presentation.getInlinePresentationSpec(),
isAugmented ? InlineSuggestionInfo.SOURCE_PLATFORM
: InlineSuggestionInfo.SOURCE_AUTOFILL,
- inlinePresentation.getAutofillHints(),
- InlineSuggestionInfo.TYPE_ACTION, inlinePresentation.isPinned());
+ presentation.getAutofillHints(), InlineSuggestionInfo.TYPE_ACTION,
+ presentation.isPinned());
final Runnable onClickAction = () -> {
- Toast.makeText(context, "icon clicked", Toast.LENGTH_SHORT).show();
+ try {
+ // TODO(b/150499490): route the intent to the client app to have it fired there,
+ // so that it will appear as a part of the same task as the client app (similar
+ // to the authentication flow).
+ action.sendIntent(null, 0, null, null, null);
+ } catch (IntentSender.SendIntentException e) {
+ onErrorCallback.run();
+ Slog.w(TAG, "Error sending inline action intent");
+ }
};
return new InlineSuggestion(inlineSuggestionInfo,
- createInlineContentProvider(inlinePresentation, onClickAction, onErrorCallback,
+ createInlineContentProvider(presentation, onClickAction, onErrorCallback,
remoteRenderService, hostInputToken, displayId));
}
diff --git a/services/core/Android.bp b/services/core/Android.bp
index 84ce34b4676f..4cc65900d099 100644
--- a/services/core/Android.bp
+++ b/services/core/Android.bp
@@ -94,6 +94,7 @@ java_library_static {
"services-stubs",
"services.net",
"android.hardware.light-V2.0-java",
+ "android.hardware.power-java",
"android.hardware.power-V1.0-java",
"android.hardware.tv.cec-V1.0-java",
"android.hardware.vibrator-java",
diff --git a/services/core/java/android/content/pm/PackageManagerInternal.java b/services/core/java/android/content/pm/PackageManagerInternal.java
index 485127a79c27..dadcd4e03f89 100644
--- a/services/core/java/android/content/pm/PackageManagerInternal.java
+++ b/services/core/java/android/content/pm/PackageManagerInternal.java
@@ -927,13 +927,11 @@ public abstract class PackageManagerInternal {
IntentSender intentSender, int flags);
/**
- * Get fingerprint of build that updated the runtime permissions for a user.
+ * Update fingerprint of build that updated the runtime permissions for a user.
*
* @param userId The user to update
- * @param fingerPrint The fingerprint to set
*/
- public abstract void setRuntimePermissionsFingerPrint(@NonNull String fingerPrint,
- @UserIdInt int userId);
+ public abstract void updateRuntimePermissionsFingerprint(@UserIdInt int userId);
/**
* Migrates legacy obb data to its new location.
@@ -961,8 +959,8 @@ public abstract class PackageManagerInternal {
public abstract boolean isCallerInstallerOfRecord(
@NonNull AndroidPackage pkg, int callingUid);
- /** Returns whether or not default runtime permissions are granted for the given user */
- public abstract boolean areDefaultRuntimePermissionsGranted(@UserIdInt int userId);
+ /** Returns whether or not permissions need to be upgraded for the given user */
+ public abstract boolean isPermissionUpgradeNeeded(@UserIdInt int userId);
/** Sets the enforcement of reading external storage */
public abstract void setReadExternalStorageEnforced(boolean enforced);
@@ -986,4 +984,11 @@ public abstract class PackageManagerInternal {
* Returns MIME types contained in {@code mimeGroup} from {@code packageName} package
*/
public abstract List<String> getMimeGroup(String packageName, String mimeGroup);
+
+ /**
+ * Toggles visibility logging to help in debugging the app enumeration feature.
+ * @param packageName the package name that should begin logging
+ * @param enabled true if visibility blocks should be logged
+ */
+ public abstract void setVisibilityLogging(String packageName, boolean enabled);
}
diff --git a/services/core/java/com/android/server/BluetoothManagerService.java b/services/core/java/com/android/server/BluetoothManagerService.java
index a4a42bcaecb1..03ca1c610f82 100644
--- a/services/core/java/com/android/server/BluetoothManagerService.java
+++ b/services/core/java/com/android/server/BluetoothManagerService.java
@@ -85,6 +85,7 @@ import java.util.LinkedList;
import java.util.Locale;
import java.util.Map;
import java.util.NoSuchElementException;
+import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.locks.ReentrantReadWriteLock;
@@ -272,6 +273,46 @@ class BluetoothManagerService extends IBluetoothManager.Stub {
}
};
+ public boolean onFactoryReset() {
+ // Wait for stable state if bluetooth is temporary state.
+ int state = getState();
+ if (state == BluetoothAdapter.STATE_BLE_TURNING_ON
+ || state == BluetoothAdapter.STATE_TURNING_ON
+ || state == BluetoothAdapter.STATE_TURNING_OFF) {
+ if (!waitForState(Set.of(BluetoothAdapter.STATE_BLE_ON, BluetoothAdapter.STATE_ON))) {
+ return false;
+ }
+ }
+
+ // Clear registered LE apps to force shut-off Bluetooth
+ clearBleApps();
+ state = getState();
+ try {
+ mBluetoothLock.readLock().lock();
+ if (mBluetooth == null) {
+ return false;
+ }
+ if (state == BluetoothAdapter.STATE_BLE_ON) {
+ addActiveLog(
+ BluetoothProtoEnums.ENABLE_DISABLE_REASON_FACTORY_RESET,
+ mContext.getPackageName(), false);
+ mBluetooth.onBrEdrDown();
+ return true;
+ } else if (state == BluetoothAdapter.STATE_ON) {
+ addActiveLog(
+ BluetoothProtoEnums.ENABLE_DISABLE_REASON_FACTORY_RESET,
+ mContext.getPackageName(), false);
+ mBluetooth.disable();
+ return true;
+ }
+ } catch (RemoteException e) {
+ Slog.e(TAG, "Unable to shutdown Bluetooth", e);
+ } finally {
+ mBluetoothLock.readLock().unlock();
+ }
+ return false;
+ }
+
public void onAirplaneModeChanged() {
synchronized (this) {
if (isBluetoothPersistedStateOn()) {
@@ -1670,7 +1711,8 @@ class BluetoothManagerService extends IBluetoothManager.Stub {
// the previous Bluetooth process has exited. The
// waiting period has three components:
// (a) Wait until the local state is STATE_OFF. This
- // is accomplished by "waitForOnOff(false, true)".
+ // is accomplished by
+ // "waitForState(Set.of(BluetoothAdapter.STATE_OFF))".
// (b) Wait until the STATE_OFF state is updated to
// all components.
// (c) Wait until the Bluetooth process exits, and
@@ -1680,7 +1722,7 @@ class BluetoothManagerService extends IBluetoothManager.Stub {
// message. The delay time is backed off if Bluetooth
// continuously failed to turn on itself.
//
- waitForOnOff(false, true);
+ waitForState(Set.of(BluetoothAdapter.STATE_OFF));
Message restartMsg =
mHandler.obtainMessage(MESSAGE_RESTART_BLUETOOTH_SERVICE);
mHandler.sendMessageDelayed(restartMsg, getServiceRestartMs());
@@ -1693,10 +1735,15 @@ class BluetoothManagerService extends IBluetoothManager.Stub {
}
mHandler.removeMessages(MESSAGE_RESTART_BLUETOOTH_SERVICE);
if (mEnable && mBluetooth != null) {
- waitForOnOff(true, false);
+ waitForState(Set.of(BluetoothAdapter.STATE_ON));
mEnable = false;
handleDisable();
- waitForOnOff(false, false);
+ waitForState(Set.of(BluetoothAdapter.STATE_OFF,
+ BluetoothAdapter.STATE_TURNING_ON,
+ BluetoothAdapter.STATE_TURNING_OFF,
+ BluetoothAdapter.STATE_BLE_TURNING_ON,
+ BluetoothAdapter.STATE_BLE_ON,
+ BluetoothAdapter.STATE_BLE_TURNING_OFF));
} else {
mEnable = false;
handleDisable();
@@ -1819,9 +1866,14 @@ class BluetoothManagerService extends IBluetoothManager.Stub {
}
if (!mEnable) {
- waitForOnOff(true, false);
+ waitForState(Set.of(BluetoothAdapter.STATE_ON));
handleDisable();
- waitForOnOff(false, false);
+ waitForState(Set.of(BluetoothAdapter.STATE_OFF,
+ BluetoothAdapter.STATE_TURNING_ON,
+ BluetoothAdapter.STATE_TURNING_OFF,
+ BluetoothAdapter.STATE_BLE_TURNING_ON,
+ BluetoothAdapter.STATE_BLE_ON,
+ BluetoothAdapter.STATE_BLE_TURNING_OFF));
}
break;
}
@@ -1853,7 +1905,7 @@ class BluetoothManagerService extends IBluetoothManager.Stub {
== BluetoothAdapter.STATE_OFF)) {
if (mEnable) {
Slog.d(TAG, "Entering STATE_OFF but mEnabled is true; restarting.");
- waitForOnOff(false, true);
+ waitForState(Set.of(BluetoothAdapter.STATE_OFF));
Message restartMsg =
mHandler.obtainMessage(MESSAGE_RESTART_BLUETOOTH_SERVICE);
mHandler.sendMessageDelayed(restartMsg, getServiceRestartMs());
@@ -1982,7 +2034,7 @@ class BluetoothManagerService extends IBluetoothManager.Stub {
mState = BluetoothAdapter.STATE_TURNING_ON;
}
- waitForOnOff(true, false);
+ waitForState(Set.of(BluetoothAdapter.STATE_ON));
if (mState == BluetoothAdapter.STATE_TURNING_ON) {
bluetoothStateChangeHandler(mState, BluetoothAdapter.STATE_ON);
@@ -1997,7 +2049,8 @@ class BluetoothManagerService extends IBluetoothManager.Stub {
bluetoothStateChangeHandler(BluetoothAdapter.STATE_ON,
BluetoothAdapter.STATE_TURNING_OFF);
- boolean didDisableTimeout = !waitForOnOff(false, true);
+ boolean didDisableTimeout =
+ !waitForState(Set.of(BluetoothAdapter.STATE_OFF));
bluetoothStateChangeHandler(BluetoothAdapter.STATE_TURNING_OFF,
BluetoothAdapter.STATE_OFF);
@@ -2243,12 +2296,7 @@ class BluetoothManagerService extends IBluetoothManager.Stub {
}
}
- /**
- * if on is true, wait for state become ON
- * if off is true, wait for state become OFF
- * if both on and off are false, wait for state not ON
- */
- private boolean waitForOnOff(boolean on, boolean off) {
+ private boolean waitForState(Set<Integer> states) {
int i = 0;
while (i < 10) {
try {
@@ -2256,18 +2304,8 @@ class BluetoothManagerService extends IBluetoothManager.Stub {
if (mBluetooth == null) {
break;
}
- if (on) {
- if (mBluetooth.getState() == BluetoothAdapter.STATE_ON) {
- return true;
- }
- } else if (off) {
- if (mBluetooth.getState() == BluetoothAdapter.STATE_OFF) {
- return true;
- }
- } else {
- if (mBluetooth.getState() != BluetoothAdapter.STATE_ON) {
- return true;
- }
+ if (states.contains(mBluetooth.getState())) {
+ return true;
}
} catch (RemoteException e) {
Slog.e(TAG, "getState()", e);
@@ -2275,14 +2313,10 @@ class BluetoothManagerService extends IBluetoothManager.Stub {
} finally {
mBluetoothLock.readLock().unlock();
}
- if (on || off) {
- SystemClock.sleep(300);
- } else {
- SystemClock.sleep(50);
- }
+ SystemClock.sleep(300);
i++;
}
- Slog.e(TAG, "waitForOnOff time out");
+ Slog.e(TAG, "waitForState " + states + " time out");
return false;
}
@@ -2343,7 +2377,7 @@ class BluetoothManagerService extends IBluetoothManager.Stub {
mContext.getPackageName(), false);
handleDisable();
- waitForOnOff(false, true);
+ waitForState(Set.of(BluetoothAdapter.STATE_OFF));
sendBluetoothServiceDownCallback();
@@ -2533,6 +2567,8 @@ class BluetoothManagerService extends IBluetoothManager.Stub {
return "USER_SWITCH";
case BluetoothProtoEnums.ENABLE_DISABLE_REASON_RESTORE_USER_SETTING:
return "RESTORE_USER_SETTING";
+ case BluetoothProtoEnums.ENABLE_DISABLE_REASON_FACTORY_RESET:
+ return "FACTORY_RESET";
case BluetoothProtoEnums.ENABLE_DISABLE_REASON_UNSPECIFIED:
default: return "UNKNOWN[" + reason + "]";
}
diff --git a/services/core/java/com/android/server/ConnectivityService.java b/services/core/java/com/android/server/ConnectivityService.java
index 16dd3ada12c7..7287a44600fa 100644
--- a/services/core/java/com/android/server/ConnectivityService.java
+++ b/services/core/java/com/android/server/ConnectivityService.java
@@ -101,7 +101,6 @@ import android.net.NetworkPolicyManager;
import android.net.NetworkProvider;
import android.net.NetworkQuotaInfo;
import android.net.NetworkRequest;
-import android.net.NetworkScore;
import android.net.NetworkSpecifier;
import android.net.NetworkStack;
import android.net.NetworkStackClient;
@@ -274,9 +273,6 @@ public class ConnectivityService extends IConnectivityManager.Stub
// connect anyway?" dialog after the user selects a network that doesn't validate.
private static final int PROMPT_UNVALIDATED_DELAY_MS = 8 * 1000;
- // How long to dismiss network notification.
- private static final int TIMEOUT_NOTIFICATION_DELAY_MS = 20 * 1000;
-
// Default to 30s linger time-out. Modifiable only for testing.
private static final String LINGER_DELAY_PROPERTY = "persist.netmon.linger";
private static final int DEFAULT_LINGER_DELAY_MS = 30_000;
@@ -524,18 +520,13 @@ public class ConnectivityService extends IConnectivityManager.Stub
private static final int EVENT_PROVISIONING_NOTIFICATION = 43;
/**
- * This event can handle dismissing notification by given network id.
- */
- private static final int EVENT_TIMEOUT_NOTIFICATION = 44;
-
- /**
* Used to specify whether a network should be used even if connectivity is partial.
* arg1 = whether to accept the network if its connectivity is partial (1 for true or 0 for
* false)
* arg2 = whether to remember this choice in the future (1 for true or 0 for false)
* obj = network
*/
- private static final int EVENT_SET_ACCEPT_PARTIAL_CONNECTIVITY = 45;
+ private static final int EVENT_SET_ACCEPT_PARTIAL_CONNECTIVITY = 44;
/**
* Event for NetworkMonitor to inform ConnectivityService that the probe status has changed.
@@ -544,7 +535,7 @@ public class ConnectivityService extends IConnectivityManager.Stub
* arg1 = A bitmask to describe which probes are completed.
* arg2 = A bitmask to describe which probes are successful.
*/
- public static final int EVENT_PROBE_STATUS_CHANGED = 46;
+ public static final int EVENT_PROBE_STATUS_CHANGED = 45;
/**
* Event for NetworkMonitor to inform ConnectivityService that captive portal data has changed.
@@ -552,7 +543,7 @@ public class ConnectivityService extends IConnectivityManager.Stub
* arg2 = netId
* obj = captive portal data
*/
- private static final int EVENT_CAPPORT_DATA_CHANGED = 47;
+ private static final int EVENT_CAPPORT_DATA_CHANGED = 46;
/**
* Argument for {@link #EVENT_PROVISIONING_NOTIFICATION} to indicate that the notification
@@ -2731,8 +2722,7 @@ public class ConnectivityService extends IConnectivityManager.Stub
break;
}
case NetworkAgent.EVENT_NETWORK_SCORE_CHANGED: {
- final NetworkScore ns = (NetworkScore) msg.obj;
- updateNetworkScore(nai, ns);
+ updateNetworkScore(nai, msg.arg1);
break;
}
case NetworkAgent.EVENT_SET_EXPLICITLY_SELECTED: {
@@ -2879,13 +2869,6 @@ public class ConnectivityService extends IConnectivityManager.Stub
final boolean valid = ((testResult & NETWORK_VALIDATION_RESULT_VALID) != 0);
final boolean wasValidated = nai.lastValidated;
final boolean wasDefault = isDefaultNetwork(nai);
- // Only show a connected notification if the network is pending validation
- // after the captive portal app was open, and it has now validated.
- if (nai.captivePortalValidationPending && valid) {
- // User is now logged in, network validated.
- nai.captivePortalValidationPending = false;
- showNetworkNotification(nai, NotificationType.LOGGED_IN);
- }
if (DBG) {
final String logMsg = !TextUtils.isEmpty(redirectUrl)
@@ -3766,12 +3749,6 @@ public class ConnectivityService extends IConnectivityManager.Stub
new CaptivePortal(new CaptivePortalImpl(network).asBinder()));
appIntent.setFlags(Intent.FLAG_ACTIVITY_BROUGHT_TO_FRONT | Intent.FLAG_ACTIVITY_NEW_TASK);
- // This runs on a random binder thread, but getNetworkAgentInfoForNetwork is thread-safe,
- // and captivePortalValidationPending is volatile.
- final NetworkAgentInfo nai = getNetworkAgentInfoForNetwork(network);
- if (nai != null) {
- nai.captivePortalValidationPending = true;
- }
Binder.withCleanCallingIdentity(() ->
mContext.startActivityAsUser(appIntent, UserHandle.CURRENT));
}
@@ -3890,14 +3867,6 @@ public class ConnectivityService extends IConnectivityManager.Stub
final String action;
final boolean highPriority;
switch (type) {
- case LOGGED_IN:
- action = Settings.ACTION_WIFI_SETTINGS;
- mHandler.removeMessages(EVENT_TIMEOUT_NOTIFICATION);
- mHandler.sendMessageDelayed(mHandler.obtainMessage(EVENT_TIMEOUT_NOTIFICATION,
- nai.network.netId, 0), TIMEOUT_NOTIFICATION_DELAY_MS);
- // High priority because it is a direct result of the user logging in to a portal.
- highPriority = true;
- break;
case NO_INTERNET:
action = ConnectivityManager.ACTION_PROMPT_UNVALIDATED;
// High priority because it is only displayed for explicitly selected networks.
@@ -3925,7 +3894,7 @@ public class ConnectivityService extends IConnectivityManager.Stub
}
Intent intent = new Intent(action);
- if (type != NotificationType.LOGGED_IN && type != NotificationType.PRIVATE_DNS_BROKEN) {
+ if (type != NotificationType.PRIVATE_DNS_BROKEN) {
intent.setData(Uri.fromParts("netId", Integer.toString(nai.network.netId), null));
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
intent.setClassName("com.android.settings",
@@ -4141,9 +4110,6 @@ public class ConnectivityService extends IConnectivityManager.Stub
case EVENT_DATA_SAVER_CHANGED:
handleRestrictBackgroundChanged(toBool(msg.arg1));
break;
- case EVENT_TIMEOUT_NOTIFICATION:
- mNotifier.clearNotification(msg.arg1, NotificationType.LOGGED_IN);
- break;
}
}
}
@@ -5819,12 +5785,10 @@ public class ConnectivityService extends IConnectivityManager.Stub
// TODO: Instead of passing mDefaultRequest, provide an API to determine whether a Network
// satisfies mDefaultRequest.
final NetworkCapabilities nc = new NetworkCapabilities(networkCapabilities);
- final NetworkScore ns = new NetworkScore();
- ns.putIntExtension(NetworkScore.LEGACY_SCORE, currentScore);
final NetworkAgentInfo nai = new NetworkAgentInfo(messenger, new AsyncChannel(),
new Network(mNetIdManager.reserveNetId()), new NetworkInfo(networkInfo), lp, nc,
- ns, mContext, mTrackerHandler, new NetworkAgentConfig(networkAgentConfig), this,
- mNetd, mDnsResolver, mNMS, providerId);
+ currentScore, mContext, mTrackerHandler, new NetworkAgentConfig(networkAgentConfig),
+ this, mNetd, mDnsResolver, mNMS, providerId);
// Make sure the network capabilities reflect what the agent info says.
nai.getAndSetNetworkCapabilities(mixInCapabilities(nai, nc));
final String extraInfo = networkInfo.getExtraInfo();
@@ -7082,9 +7046,9 @@ public class ConnectivityService extends IConnectivityManager.Stub
}
}
- private void updateNetworkScore(NetworkAgentInfo nai, NetworkScore ns) {
- if (VDBG || DDBG) log("updateNetworkScore for " + nai.toShortString() + " to " + ns);
- nai.setNetworkScore(ns);
+ private void updateNetworkScore(@NonNull final NetworkAgentInfo nai, final int score) {
+ if (VDBG || DDBG) log("updateNetworkScore for " + nai.toShortString() + " to " + score);
+ nai.setScore(score);
rematchAllNetworksAndRequests();
sendUpdatedScoreToFactories(nai);
}
diff --git a/services/core/java/com/android/server/DynamicSystemService.java b/services/core/java/com/android/server/DynamicSystemService.java
index 41207c97492a..318a03074492 100644
--- a/services/core/java/com/android/server/DynamicSystemService.java
+++ b/services/core/java/com/android/server/DynamicSystemService.java
@@ -21,6 +21,7 @@ import android.content.pm.PackageManager;
import android.gsi.AvbPublicKey;
import android.gsi.GsiProgress;
import android.gsi.IGsiService;
+import android.gsi.IGsiServiceCallback;
import android.gsi.IGsid;
import android.os.Environment;
import android.os.IBinder;
@@ -115,6 +116,20 @@ public class DynamicSystemService extends IDynamicSystemService.Stub implements
}
}
+ class GsiServiceCallback extends IGsiServiceCallback.Stub {
+ // 0 for success
+ private int mResult = -1;
+
+ public synchronized void onResult(int result) {
+ mResult = result;
+ notify();
+ }
+
+ public int getResult() {
+ return mResult;
+ }
+ }
+
@Override
public boolean startInstallation(String dsuSlot) throws RemoteException {
IGsiService service = getGsiService();
@@ -186,7 +201,9 @@ public class DynamicSystemService extends IDynamicSystemService.Stub implements
@Override
public boolean isInstalled() throws RemoteException {
- return getGsiService().isGsiInstalled();
+ boolean installed = SystemProperties.getBoolean("gsid.image_installed", false);
+ Slog.i(TAG, "isInstalled(): " + installed);
+ return installed;
}
@Override
@@ -196,16 +213,37 @@ public class DynamicSystemService extends IDynamicSystemService.Stub implements
@Override
public boolean remove() throws RemoteException {
- IGsiService gsiService = getGsiService();
- String install_dir = gsiService.getInstalledGsiImageDir();
- return getGsiService().removeGsi();
+ try {
+ GsiServiceCallback callback = new GsiServiceCallback();
+ synchronized (callback) {
+ getGsiService().removeGsiAsync(callback);
+ callback.wait(GSID_ROUGH_TIMEOUT_MS);
+ }
+ return callback.getResult() == 0;
+ } catch (InterruptedException e) {
+ Slog.e(TAG, "remove() was interrupted");
+ return false;
+ }
}
@Override
public boolean setEnable(boolean enable, boolean oneShot) throws RemoteException {
IGsiService gsiService = getGsiService();
if (enable) {
- return gsiService.enableGsi(oneShot, mDsuSlot) == 0;
+ try {
+ if (mDsuSlot == null) {
+ mDsuSlot = gsiService.getActiveDsuSlot();
+ }
+ GsiServiceCallback callback = new GsiServiceCallback();
+ synchronized (callback) {
+ gsiService.enableGsiAsync(oneShot, mDsuSlot, callback);
+ callback.wait(GSID_ROUGH_TIMEOUT_MS);
+ }
+ return callback.getResult() == 0;
+ } catch (InterruptedException e) {
+ Slog.e(TAG, "setEnable() was interrupted");
+ return false;
+ }
} else {
return gsiService.disableGsi();
}
diff --git a/services/core/java/com/android/server/PackageWatchdog.java b/services/core/java/com/android/server/PackageWatchdog.java
index b464422e9e3d..2cfe404f8c6f 100644
--- a/services/core/java/com/android/server/PackageWatchdog.java
+++ b/services/core/java/com/android/server/PackageWatchdog.java
@@ -161,6 +161,9 @@ public class PackageWatchdog {
private final Runnable mSaveToFile = this::saveToFile;
private final SystemClock mSystemClock;
private final BootThreshold mBootThreshold;
+ // The set of packages that have been synced with the ExplicitHealthCheckController
+ @GuardedBy("mLock")
+ private Set<String> mRequestedHealthCheckPackages = new ArraySet<>();
@GuardedBy("mLock")
private boolean mIsPackagesReady;
// Flag to control whether explicit health checks are supported or not
@@ -624,17 +627,22 @@ public class PackageWatchdog {
* @see #syncRequestsAsync
*/
private void syncRequests() {
- Set<String> packages = null;
+ boolean syncRequired = false;
synchronized (mLock) {
if (mIsPackagesReady) {
- packages = getPackagesPendingHealthChecksLocked();
+ Set<String> packages = getPackagesPendingHealthChecksLocked();
+ if (!packages.equals(mRequestedHealthCheckPackages)) {
+ syncRequired = true;
+ mRequestedHealthCheckPackages = packages;
+ }
} // else, we will sync requests when packages become ready
}
// Call outside lock to avoid holding lock when calling into the controller.
- if (packages != null) {
- Slog.i(TAG, "Syncing health check requests for packages: " + packages);
- mHealthCheckController.syncRequests(packages);
+ if (syncRequired) {
+ Slog.i(TAG, "Syncing health check requests for packages: "
+ + mRequestedHealthCheckPackages);
+ mHealthCheckController.syncRequests(mRequestedHealthCheckPackages);
}
}
diff --git a/services/core/java/com/android/server/StorageManagerService.java b/services/core/java/com/android/server/StorageManagerService.java
index 57c6e5b876b1..b7d050a25484 100644
--- a/services/core/java/com/android/server/StorageManagerService.java
+++ b/services/core/java/com/android/server/StorageManagerService.java
@@ -335,6 +335,8 @@ class StorageManagerService extends IStorageManager.Stub
Manifest.permission.WRITE_EXTERNAL_STORAGE
};
+ @Nullable public static String sMediaStoreAuthorityProcessName;
+
private final AtomicFile mSettingsFile;
/**
@@ -1840,6 +1842,7 @@ class StorageManagerService extends IStorageManager.Stub
UserHandle.getUserId(UserHandle.USER_SYSTEM));
if (provider != null) {
mMediaStoreAuthorityAppId = UserHandle.getAppId(provider.applicationInfo.uid);
+ sMediaStoreAuthorityProcessName = provider.applicationInfo.processName;
}
provider = mPmInternal.resolveContentProvider(
diff --git a/services/core/java/com/android/server/TelephonyRegistry.java b/services/core/java/com/android/server/TelephonyRegistry.java
index 14154339ac4a..7dedad7f2fea 100644
--- a/services/core/java/com/android/server/TelephonyRegistry.java
+++ b/services/core/java/com/android/server/TelephonyRegistry.java
@@ -167,14 +167,13 @@ public class TelephonyRegistry extends ITelephonyRegistry.Stub {
@Override
public String toString() {
- return "{callingPackage=" + callingPackage + " binder=" + binder
- + " callback=" + callback
+ return "{callingPackage=" + pii(callingPackage) + " callerUid=" + callerUid + " binder="
+ + binder + " callback=" + callback
+ " onSubscriptionsChangedListenererCallback="
+ onSubscriptionsChangedListenerCallback
+ " onOpportunisticSubscriptionsChangedListenererCallback="
- + onOpportunisticSubscriptionsChangedListenerCallback
- + " callerUid=" + callerUid + " subId=" + subId + " phoneId=" + phoneId
- + " events=" + Integer.toHexString(events) + "}";
+ + onOpportunisticSubscriptionsChangedListenerCallback + " subId=" + subId
+ + " phoneId=" + phoneId + " events=" + Integer.toHexString(events) + "}";
}
}
@@ -598,9 +597,9 @@ public class TelephonyRegistry extends ITelephonyRegistry.Stub {
int callerUserId = UserHandle.getCallingUserId();
mAppOps.checkPackage(Binder.getCallingUid(), callingPackage);
if (VDBG) {
- log("listen oscl: E pkg=" + callingPackage + " myUserId=" + UserHandle.myUserId()
- + " callerUserId=" + callerUserId + " callback=" + callback
- + " callback.asBinder=" + callback.asBinder());
+ log("listen oscl: E pkg=" + pii(callingPackage) + " uid=" + Binder.getCallingUid()
+ + " myUserId=" + UserHandle.myUserId() + " callerUserId=" + callerUserId
+ + " callback=" + callback + " callback.asBinder=" + callback.asBinder());
}
synchronized (mRecords) {
@@ -652,9 +651,9 @@ public class TelephonyRegistry extends ITelephonyRegistry.Stub {
int callerUserId = UserHandle.getCallingUserId();
mAppOps.checkPackage(Binder.getCallingUid(), callingPackage);
if (VDBG) {
- log("listen ooscl: E pkg=" + callingPackage + " myUserId=" + UserHandle.myUserId()
- + " callerUserId=" + callerUserId + " callback=" + callback
- + " callback.asBinder=" + callback.asBinder());
+ log("listen ooscl: E pkg=" + pii(callingPackage) + " uid=" + Binder.getCallingUid()
+ + " myUserId=" + UserHandle.myUserId() + " callerUserId=" + callerUserId
+ + " callback=" + callback + " callback.asBinder=" + callback.asBinder());
}
synchronized (mRecords) {
@@ -769,9 +768,9 @@ public class TelephonyRegistry extends ITelephonyRegistry.Stub {
IPhoneStateListener callback, int events, boolean notifyNow, int subId) {
int callerUserId = UserHandle.getCallingUserId();
mAppOps.checkPackage(Binder.getCallingUid(), callingPackage);
- String str = "listen: E pkg=" + callingPackage + " events=0x" + Integer.toHexString(events)
- + " notifyNow=" + notifyNow + " subId=" + subId + " myUserId="
- + UserHandle.myUserId() + " callerUserId=" + callerUserId;
+ String str = "listen: E pkg=" + pii(callingPackage) + " uid=" + Binder.getCallingUid()
+ + " events=0x" + Integer.toHexString(events) + " notifyNow=" + notifyNow + " subId="
+ + subId + " myUserId=" + UserHandle.myUserId() + " callerUserId=" + callerUserId;
mListenLog.log(str);
if (VDBG) {
log(str);
@@ -2957,4 +2956,14 @@ public class TelephonyRegistry extends ITelephonyRegistry.Stub {
if (info == null) return INVALID_SIM_SLOT_INDEX;
return info.getSimSlotIndex();
}
+
+ /**
+ * On certain build types, we should redact information by default. UID information will be
+ * preserved in the same log line, so no debugging capability is lost in full bug reports.
+ * However, privacy-constrained bug report types (e.g. connectivity) cannot display raw
+ * package names on user builds as it's considered an information leak.
+ */
+ private static String pii(String packageName) {
+ return Build.IS_DEBUGGABLE ? packageName : "***";
+ }
}
diff --git a/services/core/java/com/android/server/UiModeManagerService.java b/services/core/java/com/android/server/UiModeManagerService.java
index 88b517c597c4..7c833faee1bd 100644
--- a/services/core/java/com/android/server/UiModeManagerService.java
+++ b/services/core/java/com/android/server/UiModeManagerService.java
@@ -467,9 +467,9 @@ final class UiModeManagerService extends SystemService {
mNightMode = Secure.getIntForUser(context.getContentResolver(),
Secure.UI_NIGHT_MODE, defaultNightMode, userId);
mOverrideNightModeOn = Secure.getIntForUser(context.getContentResolver(),
- Secure.UI_NIGHT_MODE_OVERRIDE_ON, defaultNightMode, userId) != 0;
+ Secure.UI_NIGHT_MODE_OVERRIDE_ON, 0, userId) != 0;
mOverrideNightModeOff = Secure.getIntForUser(context.getContentResolver(),
- Secure.UI_NIGHT_MODE_OVERRIDE_OFF, defaultNightMode, userId) != 0;
+ Secure.UI_NIGHT_MODE_OVERRIDE_OFF, 0, userId) != 0;
mCustomAutoNightModeStartMilliseconds = LocalTime.ofNanoOfDay(
Secure.getLongForUser(context.getContentResolver(),
Secure.DARK_THEME_CUSTOM_START_TIME,
@@ -1045,7 +1045,6 @@ final class UiModeManagerService extends SystemService {
final TwilightState lastState = mTwilightManager.getLastTwilightState();
activateNightMode = lastState == null ? mComputedNightMode : lastState.isNight();
}
-
updateComputedNightModeLocked(activateNightMode);
} else {
if (mTwilightManager != null) {
@@ -1375,6 +1374,9 @@ final class UiModeManagerService extends SystemService {
private void updateComputedNightModeLocked(boolean activate) {
mComputedNightMode = activate;
+ if (mNightMode == MODE_NIGHT_YES || mNightMode == UiModeManager.MODE_NIGHT_NO) {
+ return;
+ }
if (mOverrideNightModeOn && !mComputedNightMode) {
mComputedNightMode = true;
return;
diff --git a/services/core/java/com/android/server/Watchdog.java b/services/core/java/com/android/server/Watchdog.java
index ac7867f29a79..056156745966 100644
--- a/services/core/java/com/android/server/Watchdog.java
+++ b/services/core/java/com/android/server/Watchdog.java
@@ -69,21 +69,21 @@ public class Watchdog extends Thread {
public static final boolean DEBUG = false;
// Set this to true to use debug default values.
- static final boolean DB = false;
+ private static final boolean DB = false;
// Note 1: Do not lower this value below thirty seconds without tightening the invoke-with
// timeout in com.android.internal.os.ZygoteConnection, or wrapped applications
// can trigger the watchdog.
// Note 2: The debug value is already below the wait time in ZygoteConnection. Wrapped
// applications may not work with a debug build. CTS will fail.
- static final long DEFAULT_TIMEOUT = DB ? 10*1000 : 60*1000;
- static final long CHECK_INTERVAL = DEFAULT_TIMEOUT / 2;
+ private static final long DEFAULT_TIMEOUT = DB ? 10 * 1000 : 60 * 1000;
+ private static final long CHECK_INTERVAL = DEFAULT_TIMEOUT / 2;
// These are temporally ordered: larger values as lateness increases
- static final int COMPLETED = 0;
- static final int WAITING = 1;
- static final int WAITED_HALF = 2;
- static final int OVERDUE = 3;
+ private static final int COMPLETED = 0;
+ private static final int WAITING = 1;
+ private static final int WAITED_HALF = 2;
+ private static final int OVERDUE = 3;
// Which native processes to dump into dropbox's stack traces
public static final String[] NATIVE_STACKS_OF_INTEREST = new String[] {
@@ -110,8 +110,10 @@ public class Watchdog extends Thread {
"android.hardware.audio@5.0::IDevicesFactory",
"android.hardware.audio@6.0::IDevicesFactory",
"android.hardware.biometrics.face@1.0::IBiometricsFace",
+ "android.hardware.biometrics.fingerprint@2.1::IBiometricsFingerprint",
"android.hardware.bluetooth@1.0::IBluetoothHci",
"android.hardware.camera.provider@2.4::ICameraProvider",
+ "android.hardware.gnss@1.0::IGnss",
"android.hardware.graphics.allocator@2.0::IAllocator",
"android.hardware.graphics.composer@2.1::IComposer",
"android.hardware.health@2.0::IHealth",
@@ -124,17 +126,17 @@ public class Watchdog extends Thread {
"android.system.suspend@1.0::ISystemSuspend"
);
- static Watchdog sWatchdog;
+ private static Watchdog sWatchdog;
/* This handler will be used to post message back onto the main thread */
- final ArrayList<HandlerChecker> mHandlerCheckers = new ArrayList<>();
- final HandlerChecker mMonitorChecker;
- ActivityManagerService mActivity;
+ private final ArrayList<HandlerChecker> mHandlerCheckers = new ArrayList<>();
+ private final HandlerChecker mMonitorChecker;
+ private ActivityManagerService mActivity;
- int mPhonePid;
- IActivityController mController;
- boolean mAllowRestart = true;
- final OpenFdMonitor mOpenFdMonitor;
+ private IActivityController mController;
+ private boolean mAllowRestart = true;
+ private final OpenFdMonitor mOpenFdMonitor;
+ private final List<Integer> mInterestingJavaPids = new ArrayList<>();
/**
* Used for checking status of handle threads and scheduling monitor callbacks.
@@ -341,6 +343,8 @@ public class Watchdog extends Thread {
mOpenFdMonitor = OpenFdMonitor.create();
+ mInterestingJavaPids.add(Process.myPid());
+
// See the notes on DEFAULT_TIMEOUT.
assert DB ||
DEFAULT_TIMEOUT > ZygoteConnectionConstants.WRAPPED_PID_TIMEOUT_MILLIS;
@@ -358,10 +362,32 @@ public class Watchdog extends Thread {
android.Manifest.permission.REBOOT, null);
}
- public void processStarted(String name, int pid) {
- synchronized (this) {
- if ("com.android.phone".equals(name)) {
- mPhonePid = pid;
+ private static boolean isInterestingJavaProcess(String processName) {
+ return processName.equals(StorageManagerService.sMediaStoreAuthorityProcessName)
+ || processName.equals("com.android.phone");
+ }
+
+ /**
+ * Notifies the watchdog when a Java process with {@code pid} is started.
+ * This process may have its stack trace dumped during an ANR.
+ */
+ public void processStarted(String processName, int pid) {
+ if (isInterestingJavaProcess(processName)) {
+ Slog.i(TAG, "Interesting Java process " + processName + " started. Pid " + pid);
+ synchronized (this) {
+ mInterestingJavaPids.add(pid);
+ }
+ }
+ }
+
+ /**
+ * Notifies the watchdog when a Java process with {@code pid} dies.
+ */
+ public void processDied(String processName, int pid) {
+ if (isInterestingJavaProcess(processName)) {
+ Slog.i(TAG, "Interesting Java process " + processName + " died. Pid " + pid);
+ synchronized (this) {
+ mInterestingJavaPids.remove(Integer.valueOf(pid));
}
}
}
@@ -581,8 +607,7 @@ public class Watchdog extends Thread {
Slog.i(TAG, "WAITED_HALF");
// We've waited half the deadlock-detection interval. Pull a stack
// trace and wait another half.
- ArrayList<Integer> pids = new ArrayList<Integer>();
- pids.add(Process.myPid());
+ ArrayList<Integer> pids = new ArrayList<>(mInterestingJavaPids);
ActivityManagerService.dumpStackTraces(pids, null, null,
getInterestingNativePids(), null);
waitedHalf = true;
@@ -605,9 +630,7 @@ public class Watchdog extends Thread {
// Then kill this process so that the system will restart.
EventLog.writeEvent(EventLogTags.WATCHDOG, subject);
- ArrayList<Integer> pids = new ArrayList<>();
- pids.add(Process.myPid());
- if (mPhonePid > 0) pids.add(mPhonePid);
+ ArrayList<Integer> pids = new ArrayList<>(mInterestingJavaPids);
long anrTime = SystemClock.uptimeMillis();
StringBuilder report = new StringBuilder();
diff --git a/services/core/java/com/android/server/am/ActivityManagerConstants.java b/services/core/java/com/android/server/am/ActivityManagerConstants.java
index 8fbe923cedc6..6b917bc2249d 100644
--- a/services/core/java/com/android/server/am/ActivityManagerConstants.java
+++ b/services/core/java/com/android/server/am/ActivityManagerConstants.java
@@ -19,16 +19,12 @@ package com.android.server.am;
import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_POWER_QUICK;
import android.app.ActivityThread;
-import android.content.ComponentName;
import android.content.ContentResolver;
import android.content.Context;
-import android.content.pm.UserInfo;
import android.database.ContentObserver;
import android.net.Uri;
import android.os.Build;
import android.os.Handler;
-import android.os.UserHandle;
-import android.os.UserManager;
import android.provider.DeviceConfig;
import android.provider.DeviceConfig.OnPropertiesChangedListener;
import android.provider.DeviceConfig.Properties;
@@ -37,7 +33,6 @@ import android.text.TextUtils;
import android.util.ArraySet;
import android.util.KeyValueListParser;
import android.util.Slog;
-import android.util.SparseArray;
import java.io.PrintWriter;
import java.util.Arrays;
@@ -294,12 +289,6 @@ final class ActivityManagerConstants extends ContentObserver {
// started, the restriction is on while-in-use permissions.)
volatile boolean mFlagBackgroundFgsStartRestrictionEnabled = true;
- /**
- * UserId to Assistant ComponentName mapping.
- * Per user Assistant ComponentName is from {@link android.provider.Settings.Secure#ASSISTANT}
- */
- SparseArray<ComponentName> mAssistants = new SparseArray<>();
-
private final ActivityManagerService mService;
private ContentResolver mResolver;
private final KeyValueListParser mParser = new KeyValueListParser(',');
@@ -375,8 +364,6 @@ final class ActivityManagerConstants extends ContentObserver {
Settings.Global.getUriFor(
Settings.Global.FOREGROUND_SERVICE_STARTS_LOGGING_ENABLED);
- private static final Uri ASSISTANT_URI = Settings.Secure.getUriFor(Settings.Secure.ASSISTANT);
-
private static final Uri ENABLE_AUTOMATIC_SYSTEM_SERVER_HEAP_DUMPS_URI =
Settings.Global.getUriFor(Settings.Global.ENABLE_AUTOMATIC_SYSTEM_SERVER_HEAP_DUMPS);
@@ -443,8 +430,6 @@ final class ActivityManagerConstants extends ContentObserver {
mResolver.registerContentObserver(ACTIVITY_STARTS_LOGGING_ENABLED_URI, false, this);
mResolver.registerContentObserver(FOREGROUND_SERVICE_STARTS_LOGGING_ENABLED_URI,
false, this);
- mResolver.registerContentObserver(ASSISTANT_URI, false, this,
- UserHandle.USER_ALL);
if (mSystemServerAutomaticHeapDumpEnabled) {
mResolver.registerContentObserver(ENABLE_AUTOMATIC_SYSTEM_SERVER_HEAP_DUMPS_URI,
false, this);
@@ -460,7 +445,6 @@ final class ActivityManagerConstants extends ContentObserver {
// The following read from Settings.
updateActivityStartsLoggingEnabled();
updateForegroundServiceStartsLoggingEnabled();
- updateAssistant();
}
private void loadDeviceConfigConstants() {
@@ -492,8 +476,6 @@ final class ActivityManagerConstants extends ContentObserver {
updateForegroundServiceStartsLoggingEnabled();
} else if (ENABLE_AUTOMATIC_SYSTEM_SERVER_HEAP_DUMPS_URI.equals(uri)) {
updateEnableAutomaticSystemServerHeapDumps();
- } else if (ASSISTANT_URI.equals(uri)) {
- updateAssistant();
}
}
@@ -590,32 +572,6 @@ final class ActivityManagerConstants extends ContentObserver {
mFlagForegroundServiceStartsLoggingEnabled = Settings.Global.getInt(mResolver,
Settings.Global.FOREGROUND_SERVICE_STARTS_LOGGING_ENABLED, 1) == 1;
}
-
- private void updateAssistant() {
- final List<UserInfo> users =
- mService.mContext.getSystemService(UserManager.class).getUsers();
- SparseArray<ComponentName> componentNames = new SparseArray<>();
- for (int i = 0; i < users.size(); i++) {
- final int userId = users.get(i).id;
- final String str = Settings.Secure.getStringForUser(mResolver,
- Settings.Secure.ASSISTANT, userId);
- if (!TextUtils.isEmpty(str)) {
- componentNames.put(userId, ComponentName.unflattenFromString(str));
- }
- }
- synchronized (mService) {
- for (int i = 0; i < mAssistants.size(); i++) {
- mService.mServices.mWhiteListAllowWhileInUsePermissionInFgs.remove(
- mAssistants.valueAt(i).getPackageName());
- }
- mAssistants = componentNames;
- for (int i = 0; i < mAssistants.size(); i++) {
- mService.mServices.mWhiteListAllowWhileInUsePermissionInFgs.add(
- mAssistants.valueAt(i).getPackageName());
- }
- }
- }
-
private void updateBackgroundFgsStartsRestriction() {
mFlagBackgroundFgsStartRestrictionEnabled = DeviceConfig.getBoolean(
DeviceConfig.NAMESPACE_ACTIVITY_MANAGER,
diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java
index fbcb0102eb47..f64272bf08d1 100644
--- a/services/core/java/com/android/server/am/ActivityManagerService.java
+++ b/services/core/java/com/android/server/am/ActivityManagerService.java
@@ -81,6 +81,8 @@ import static android.os.Process.removeAllProcessGroups;
import static android.os.Process.sendSignal;
import static android.os.Process.setThreadPriority;
import static android.os.Process.setThreadScheduler;
+import static android.permission.PermissionManager.KILL_APP_REASON_GIDS_CHANGED;
+import static android.permission.PermissionManager.KILL_APP_REASON_PERMISSIONS_REVOKED;
import static android.provider.Settings.Global.ALWAYS_FINISH_ACTIVITIES;
import static android.provider.Settings.Global.DEBUG_APP;
import static android.provider.Settings.Global.NETWORK_ACCESS_TIMEOUT_MS;
@@ -4243,7 +4245,8 @@ public class ActivityManagerService extends IActivityManager.Stub
}
synchronized (this) {
mProcessList.killPackageProcessesLocked(packageName, appId, targetUserId,
- ProcessList.SERVICE_ADJ, "kill background");
+ ProcessList.SERVICE_ADJ, ApplicationExitInfo.REASON_USER_REQUESTED,
+ ApplicationExitInfo.SUBREASON_UNKNOWN, "kill background");
}
}
} finally {
@@ -4269,7 +4272,10 @@ public class ActivityManagerService extends IActivityManager.Stub
// because this method is also used to simulate low memory.
mAllowLowerMemLevel = true;
mProcessList.killPackageProcessesLocked(null /* packageName */, -1 /* appId */,
- UserHandle.USER_ALL, ProcessList.CACHED_APP_MIN_ADJ, "kill all background");
+ UserHandle.USER_ALL, ProcessList.CACHED_APP_MIN_ADJ,
+ ApplicationExitInfo.REASON_USER_REQUESTED,
+ ApplicationExitInfo.SUBREASON_UNKNOWN,
+ "kill all background");
doLowMemReportIfNeededLocked(null);
}
@@ -4757,7 +4763,11 @@ public class ActivityManagerService extends IActivityManager.Stub
boolean didSomething = mProcessList.killPackageProcessesLocked(packageName, appId, userId,
ProcessList.INVALID_ADJ, callerWillRestart, false /* allowRestart */, doit,
evenPersistent, true /* setRemoved */,
- packageName == null ? ("stop user " + userId) : ("stop " + packageName));
+ packageName == null ? ApplicationExitInfo.REASON_USER_STOPPED
+ : ApplicationExitInfo.REASON_USER_REQUESTED,
+ ApplicationExitInfo.SUBREASON_UNKNOWN,
+ (packageName == null ? ("stop user " + userId) : ("stop " + packageName))
+ + " due to " + reason);
didSomething |=
mAtmInternal.onForceStopPackage(packageName, doit, evenPersistent, userId);
@@ -4820,7 +4830,10 @@ public class ActivityManagerService extends IActivityManager.Stub
@GuardedBy("this")
private final void processContentProviderPublishTimedOutLocked(ProcessRecord app) {
cleanupAppInLaunchingProvidersLocked(app, true);
- mProcessList.removeProcessLocked(app, false, true, "timeout publishing content providers");
+ mProcessList.removeProcessLocked(app, false, true,
+ ApplicationExitInfo.REASON_INITIALIZATION_FAILURE,
+ ApplicationExitInfo.SUBREASON_UNKNOWN,
+ "timeout publishing content providers");
}
@GuardedBy("this")
@@ -4925,7 +4938,7 @@ public class ActivityManagerService extends IActivityManager.Stub
if (pid > 0 && pid != MY_PID) {
killProcessQuiet(pid);
//TODO: killProcessGroup(app.info.uid, pid);
- mProcessList.noteAppKill(app, ApplicationExitInfo.REASON_OTHER,
+ mProcessList.noteAppKill(app, ApplicationExitInfo.REASON_INITIALIZATION_FAILURE,
ApplicationExitInfo.SUBREASON_UNKNOWN, "attach failed");
} else {
try {
@@ -9054,7 +9067,8 @@ public class ActivityManagerService extends IActivityManager.Stub
}
int adj = proc.setAdj;
if (adj >= worstType && !proc.killedByAm) {
- proc.kill(reason, ApplicationExitInfo.REASON_OTHER, true);
+ proc.kill(reason, ApplicationExitInfo.REASON_OTHER,
+ ApplicationExitInfo.SUBREASON_KILL_PID, true);
killed = true;
}
}
@@ -9068,10 +9082,17 @@ public class ActivityManagerService extends IActivityManager.Stub
synchronized (this) {
final long identity = Binder.clearCallingIdentity();
try {
+ boolean permissionChange = KILL_APP_REASON_PERMISSIONS_REVOKED.equals(reason)
+ || KILL_APP_REASON_GIDS_CHANGED.equals(reason);
mProcessList.killPackageProcessesLocked(null /* packageName */, appId, userId,
ProcessList.PERSISTENT_PROC_ADJ, false /* callerWillRestart */,
true /* callerWillRestart */, true /* doit */, true /* evenPersistent */,
- false /* setRemoved */, reason != null ? reason : "kill uid");
+ false /* setRemoved */,
+ permissionChange ? ApplicationExitInfo.REASON_PERMISSION_CHANGE
+ : ApplicationExitInfo.REASON_OTHER,
+ permissionChange ? ApplicationExitInfo.SUBREASON_UNKNOWN
+ : ApplicationExitInfo.SUBREASON_KILL_UID,
+ reason != null ? reason : "kill uid");
} finally {
Binder.restoreCallingIdentity(identity);
}
@@ -9396,7 +9417,10 @@ public class ActivityManagerService extends IActivityManager.Stub
for (int i=procsToKill.size()-1; i>=0; i--) {
ProcessRecord proc = procsToKill.get(i);
Slog.i(TAG, "Removing system update proc: " + proc);
- mProcessList.removeProcessLocked(proc, true, false, "system update done");
+ mProcessList.removeProcessLocked(proc, true, false,
+ ApplicationExitInfo.REASON_OTHER,
+ ApplicationExitInfo.SUBREASON_SYSTEM_UPDATE_DONE,
+ "system update done");
}
}
@@ -14400,7 +14424,8 @@ public class ActivityManagerService extends IActivityManager.Stub
+ cpr.name.flattenToShortString()
+ " in dying proc " + (proc != null ? proc.processName : "??")
+ " (adj " + (proc != null ? proc.setAdj : "??") + ")",
- ApplicationExitInfo.REASON_OTHER,
+ ApplicationExitInfo.REASON_DEPENDENCY_DIED,
+ ApplicationExitInfo.SUBREASON_UNKNOWN,
true);
}
} else if (capp.thread != null && conn.provider.provider != null) {
@@ -15892,7 +15917,10 @@ public class ActivityManagerService extends IActivityManager.Stub
-1);
mProcessList.killPackageProcessesLocked(ssp,
UserHandle.getAppId(extraUid),
- userId, ProcessList.INVALID_ADJ, "change " + ssp);
+ userId, ProcessList.INVALID_ADJ,
+ ApplicationExitInfo.REASON_USER_REQUESTED,
+ ApplicationExitInfo.SUBREASON_UNKNOWN,
+ "change " + ssp);
}
cleanupDisabledPackageComponentsLocked(ssp, userId,
intent.getStringArrayExtra(
@@ -17039,6 +17067,7 @@ public class ActivityManagerService extends IActivityManager.Stub
proc.lastCachedPss = pss;
proc.lastCachedSwapPss = swapPss;
}
+ proc.mLastRss = rss;
final SparseArray<Pair<Long, String>> watchUids
= mMemWatchProcesses.getMap().get(proc.processName);
@@ -18622,7 +18651,10 @@ public class ActivityManagerService extends IActivityManager.Stub
final int N = procs.size();
for (int i = 0; i < N; i++) {
- mProcessList.removeProcessLocked(procs.get(i), false, true, "kill all fg");
+ mProcessList.removeProcessLocked(procs.get(i), false, true,
+ ApplicationExitInfo.REASON_OTHER,
+ ApplicationExitInfo.SUBREASON_KILL_ALL_FG,
+ "kill all fg");
}
}
}
@@ -18844,7 +18876,8 @@ public class ActivityManagerService extends IActivityManager.Stub
final ProcessRecord pr = (ProcessRecord) wpc.mOwner;
if (pr.setSchedGroup == ProcessList.SCHED_GROUP_BACKGROUND
&& pr.curReceivers.isEmpty()) {
- pr.kill("remove task", ApplicationExitInfo.REASON_OTHER, true);
+ pr.kill("remove task", ApplicationExitInfo.REASON_USER_REQUESTED,
+ ApplicationExitInfo.SUBREASON_UNKNOWN, true);
} else {
// We delay killing processes that are not in the background or running a
// receiver.
@@ -18861,7 +18894,7 @@ public class ActivityManagerService extends IActivityManager.Stub
true /* keepIfLarge */);
if (proc != null) {
mProcessList.removeProcessLocked(proc, false /* callerWillRestart */,
- true /* allowRestart */, reason);
+ true /* allowRestart */, ApplicationExitInfo.REASON_OTHER, reason);
}
}
}
@@ -19547,7 +19580,10 @@ public class ActivityManagerService extends IActivityManager.Stub
try {
synchronized(this) {
mProcessList.killPackageProcessesLocked(packageName, UserHandle.getAppId(pkgUid),
- userId, ProcessList.FOREGROUND_APP_ADJ, "dep: " + packageName);
+ userId, ProcessList.FOREGROUND_APP_ADJ,
+ ApplicationExitInfo.REASON_DEPENDENCY_DIED,
+ ApplicationExitInfo.SUBREASON_UNKNOWN,
+ "dep: " + packageName);
}
} finally {
Binder.restoreCallingIdentity(callingId);
diff --git a/services/core/java/com/android/server/am/AppErrors.java b/services/core/java/com/android/server/am/AppErrors.java
index 789f7199948d..b1fc0296518b 100644
--- a/services/core/java/com/android/server/am/AppErrors.java
+++ b/services/core/java/com/android/server/am/AppErrors.java
@@ -395,7 +395,7 @@ class AppErrors {
() -> {
synchronized (mService) {
killAppImmediateLocked(p, ApplicationExitInfo.REASON_OTHER,
- ApplicationExitInfo.SUBREASON_UNKNOWN,
+ ApplicationExitInfo.SUBREASON_INVALID_STATE,
"forced", "killed for invalid state");
}
},
@@ -510,8 +510,8 @@ class AppErrors {
stopReportingCrashesLocked(r);
}
if (res == AppErrorDialog.RESTART) {
- mService.mProcessList.removeProcessLocked(r, false, true, "crash",
- ApplicationExitInfo.REASON_CRASH);
+ mService.mProcessList.removeProcessLocked(r, false, true,
+ ApplicationExitInfo.REASON_CRASH, "crash");
if (taskId != INVALID_TASK_ID) {
try {
mService.startActivityFromRecents(taskId,
@@ -529,8 +529,8 @@ class AppErrors {
// Kill it with fire!
mService.mAtmInternal.onHandleAppCrash(r.getWindowProcessController());
if (!r.isPersistent()) {
- mService.mProcessList.removeProcessLocked(r, false, false, "crash",
- ApplicationExitInfo.REASON_CRASH);
+ mService.mProcessList.removeProcessLocked(r, false, false,
+ ApplicationExitInfo.REASON_CRASH, "crash");
mService.mAtmInternal.resumeTopActivities(false /* scheduleIdle */);
}
} finally {
@@ -747,8 +747,8 @@ class AppErrors {
// Don't let services in this process be restarted and potentially
// annoy the user repeatedly. Unless it is persistent, since those
// processes run critical code.
- mService.mProcessList.removeProcessLocked(app, false, tryAgain, "crash",
- ApplicationExitInfo.REASON_CRASH);
+ mService.mProcessList.removeProcessLocked(app, false, tryAgain,
+ ApplicationExitInfo.REASON_CRASH, "crash");
mService.mAtmInternal.resumeTopActivities(false /* scheduleIdle */);
if (!showBackground) {
return false;
diff --git a/services/core/java/com/android/server/am/AppExitInfoTracker.java b/services/core/java/com/android/server/am/AppExitInfoTracker.java
index cba6b92bf440..028a059c538a 100644
--- a/services/core/java/com/android/server/am/AppExitInfoTracker.java
+++ b/services/core/java/com/android/server/am/AppExitInfoTracker.java
@@ -129,7 +129,7 @@ public final class AppExitInfoTracker {
private final ProcessMap<AppExitInfoContainer> mData;
/** A pool of raw {@link android.app.ApplicationExitInfo} records. */
- @GuardedBy("mService")
+ @GuardedBy("mLock")
private final SynchronizedPool<ApplicationExitInfo> mRawRecordsPool;
/**
@@ -204,8 +204,7 @@ public final class AppExitInfoTracker {
});
}
- @GuardedBy("mService")
- void scheduleNoteProcessDiedLocked(final ProcessRecord app) {
+ void scheduleNoteProcessDied(final ProcessRecord app) {
if (app == null || app.info == null) {
return;
}
@@ -214,11 +213,9 @@ public final class AppExitInfoTracker {
if (!mAppExitInfoLoaded) {
return;
}
+ mKillHandler.obtainMessage(KillHandler.MSG_PROC_DIED, obtainRawRecordLocked(app))
+ .sendToTarget();
}
- // The current thread is holding the global lock, let's extract the info from it
- // and schedule the info note task in the kill handler.
- mKillHandler.obtainMessage(KillHandler.MSG_PROC_DIED, obtainRawRecordLocked(app))
- .sendToTarget();
}
void scheduleNoteAppKill(final ProcessRecord app, final @Reason int reason,
@@ -227,8 +224,6 @@ public final class AppExitInfoTracker {
if (!mAppExitInfoLoaded) {
return;
}
- }
- synchronized (mService) {
if (app == null || app.info == null) {
return;
}
@@ -247,8 +242,6 @@ public final class AppExitInfoTracker {
if (!mAppExitInfoLoaded) {
return;
}
- }
- synchronized (mService) {
ProcessRecord app;
synchronized (mService.mPidsSelfLocked) {
app = mService.mPidsSelfLocked.get(pid);
@@ -348,6 +341,7 @@ public final class AppExitInfoTracker {
} else {
// always override the existing info since we are now more informational.
info.setReason(raw.getReason());
+ info.setSubReason(raw.getSubReason());
info.setStatus(0);
info.setTimestamp(System.currentTimeMillis());
info.setDescription(raw.getDescription());
@@ -511,9 +505,13 @@ public final class AppExitInfoTracker {
@VisibleForTesting
void onPackageRemoved(String packageName, int uid, boolean allUsers) {
if (packageName != null) {
- mAppExitInfoSourceZygote.removeByUid(uid, allUsers);
- mAppExitInfoSourceLmkd.removeByUid(uid, allUsers);
- mIsolatedUidRecords.removeAppUid(uid, allUsers);
+ final boolean removeUid = TextUtils.isEmpty(
+ mService.mPackageManagerInt.getNameForUid(uid));
+ if (removeUid) {
+ mAppExitInfoSourceZygote.removeByUid(uid, allUsers);
+ mAppExitInfoSourceLmkd.removeByUid(uid, allUsers);
+ mIsolatedUidRecords.removeAppUid(uid, allUsers);
+ }
removePackage(packageName, allUsers ? UserHandle.USER_ALL : UserHandle.getUserId(uid));
schedulePersistProcessExitInfo(true);
}
@@ -539,6 +537,11 @@ public final class AppExitInfoTracker {
mService.mContext.registerReceiverForAllUsers(new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
+ boolean replacing = intent.getBooleanExtra(
+ Intent.EXTRA_REPLACING, false);
+ if (replacing) {
+ return;
+ }
int uid = intent.getIntExtra(Intent.EXTRA_UID, UserHandle.USER_NULL);
boolean allUsers = intent.getBooleanExtra(
Intent.EXTRA_REMOVED_FOR_ALL_USERS, false);
@@ -822,7 +825,7 @@ public final class AppExitInfoTracker {
}
@VisibleForTesting
- @GuardedBy("mService")
+ @GuardedBy("mLock")
ApplicationExitInfo obtainRawRecordLocked(ProcessRecord app) {
ApplicationExitInfo info = mRawRecordsPool.acquire();
if (info == null) {
@@ -841,15 +844,15 @@ public final class AppExitInfoTracker {
info.setReason(ApplicationExitInfo.REASON_UNKNOWN);
info.setStatus(0);
info.setImportance(procStateToImportance(app.setProcState));
- info.setPss(app.lastMemInfo == null ? 0 : app.lastMemInfo.getTotalPss());
- info.setRss(app.lastMemInfo == null ? 0 : app.lastMemInfo.getTotalRss());
+ info.setPss(app.lastPss);
+ info.setRss(app.mLastRss);
info.setTimestamp(System.currentTimeMillis());
return info;
}
@VisibleForTesting
- @GuardedBy("mService")
+ @GuardedBy("mLock")
void recycleRawRecordLocked(ApplicationExitInfo info) {
info.setProcessName(null);
info.setDescription(null);
@@ -1134,8 +1137,6 @@ public final class AppExitInfoTracker {
ApplicationExitInfo raw = (ApplicationExitInfo) msg.obj;
synchronized (mLock) {
handleNoteProcessDiedLocked(raw);
- }
- synchronized (mService) {
recycleRawRecordLocked(raw);
}
}
@@ -1144,8 +1145,6 @@ public final class AppExitInfoTracker {
ApplicationExitInfo raw = (ApplicationExitInfo) msg.obj;
synchronized (mLock) {
handleNoteAppKillLocked(raw);
- }
- synchronized (mService) {
recycleRawRecordLocked(raw);
}
}
diff --git a/services/core/java/com/android/server/am/CachedAppOptimizer.java b/services/core/java/com/android/server/am/CachedAppOptimizer.java
index be483747d2cf..3a6065e18ea5 100644
--- a/services/core/java/com/android/server/am/CachedAppOptimizer.java
+++ b/services/core/java/com/android/server/am/CachedAppOptimizer.java
@@ -126,7 +126,7 @@ public final class CachedAppOptimizer {
static final int FREEZE_TIMEOUT_MS = 500;
static final int DO_FREEZE = 1;
- static final int DO_UNFREEZE = 2;
+ static final int REPORT_UNFREEZE = 2;
/**
* This thread must be moved to the system background cpuset.
@@ -613,12 +613,67 @@ public final class CachedAppOptimizer {
FREEZE_TIMEOUT_MS);
}
+ private final class UnfreezeStats {
+ final int mPid;
+ final String mName;
+ final long mFrozenDuration;
+
+ UnfreezeStats(int pid, String name, long frozenDuration) {
+ mPid = pid;
+ mName = name;
+ mFrozenDuration = frozenDuration;
+ }
+
+ public int getPid() {
+ return mPid;
+ }
+
+ public String getName() {
+ return mName;
+ }
+
+ public long getFrozenDuration() {
+ return mFrozenDuration;
+ }
+ }
+
@GuardedBy("mAm")
- void unfreezeAppAsync(ProcessRecord app) {
+ void unfreezeAppLocked(ProcessRecord app) {
mFreezeHandler.removeMessages(SET_FROZEN_PROCESS_MSG, app);
- mFreezeHandler.sendMessage(
- mFreezeHandler.obtainMessage(SET_FROZEN_PROCESS_MSG, DO_UNFREEZE, 0, app));
+ if (!app.frozen) {
+ if (DEBUG_FREEZER) {
+ Slog.d(TAG_AM,
+ "Skipping unfreeze for process " + app.pid + " "
+ + app.processName + " (not frozen)");
+ }
+ return;
+ }
+
+ long freezeTime = app.freezeUnfreezeTime;
+
+ try {
+ Process.setProcessFrozen(app.pid, app.uid, false);
+
+ app.freezeUnfreezeTime = SystemClock.uptimeMillis();
+ app.frozen = false;
+ } catch (Exception e) {
+ Slog.e(TAG_AM, "Unable to unfreeze " + app.pid + " " + app.processName
+ + ". Any related user experience might be hanged.");
+ }
+
+ if (!app.frozen) {
+ if (DEBUG_FREEZER) {
+ Slog.d(TAG_AM, "sync unfroze " + app.pid + " " + app.processName);
+ }
+
+ UnfreezeStats stats = new UnfreezeStats(app.pid, app.processName,
+ app.freezeUnfreezeTime - freezeTime);
+
+ mFreezeHandler.sendMessage(
+ mFreezeHandler.obtainMessage(SET_FROZEN_PROCESS_MSG, REPORT_UNFREEZE, 0,
+ stats));
+ }
}
private static final class LastCompactionStats {
@@ -896,8 +951,8 @@ public final class CachedAppOptimizer {
if (msg.arg1 == DO_FREEZE) {
freezeProcess((ProcessRecord) msg.obj);
- } else if (msg.arg1 == DO_UNFREEZE) {
- unfreezeProcess((ProcessRecord) msg.obj);
+ } else if (msg.arg1 == REPORT_UNFREEZE) {
+ reportUnfreeze((UnfreezeStats) msg.obj);
}
}
@@ -960,61 +1015,18 @@ public final class CachedAppOptimizer {
}
}
- private void unfreezeProcess(ProcessRecord proc) {
- final int pid;
- final String name;
- final long frozenDuration;
- final boolean frozen;
-
- synchronized (mAm) {
- pid = proc.pid;
- name = proc.processName;
-
- if (!proc.frozen) {
- if (DEBUG_FREEZER) {
- Slog.d(TAG_AM,
- "Skipping unfreeze for process " + pid + " "
- + name + " (not frozen)");
- }
- return;
- }
-
- if (pid == 0) {
- // Not a real process, either being launched or killed
- return;
- }
-
- long freezeTime = proc.freezeUnfreezeTime;
-
- try {
- Process.setProcessFrozen(proc.pid, proc.uid, false);
-
- proc.freezeUnfreezeTime = SystemClock.uptimeMillis();
- proc.frozen = false;
- } catch (Exception e) {
- Slog.w(TAG_AM, "Unable to unfreeze " + pid + " " + name);
- }
-
- frozenDuration = proc.freezeUnfreezeTime - freezeTime;
- frozen = proc.frozen;
- }
-
- if (!frozen) {
- if (DEBUG_FREEZER) {
- Slog.d(TAG_AM, "unfroze " + pid + " " + name);
- }
+ private void reportUnfreeze(UnfreezeStats stats) {
- EventLog.writeEvent(EventLogTags.AM_UNFREEZE, pid, name);
+ EventLog.writeEvent(EventLogTags.AM_UNFREEZE, stats.getPid(), stats.getName());
- // See above for why we're not taking mPhenotypeFlagLock here
- if (mRandom.nextFloat() < mFreezerStatsdSampleRate) {
- FrameworkStatsLog.write(
- FrameworkStatsLog.APP_FREEZE_CHANGED,
- FrameworkStatsLog.APP_FREEZE_CHANGED__ACTION__UNFREEZE_APP,
- pid,
- name,
- frozenDuration);
- }
+ // See above for why we're not taking mPhenotypeFlagLock here
+ if (mRandom.nextFloat() < mFreezerStatsdSampleRate) {
+ FrameworkStatsLog.write(
+ FrameworkStatsLog.APP_FREEZE_CHANGED,
+ FrameworkStatsLog.APP_FREEZE_CHANGED__ACTION__UNFREEZE_APP,
+ stats.getPid(),
+ stats.getName(),
+ stats.getFrozenDuration());
}
}
}
diff --git a/services/core/java/com/android/server/am/OWNERS b/services/core/java/com/android/server/am/OWNERS
index 7cc2e8eb2954..1f826b5253bd 100644
--- a/services/core/java/com/android/server/am/OWNERS
+++ b/services/core/java/com/android/server/am/OWNERS
@@ -16,12 +16,6 @@ jji@google.com
# Windows & Activities
ogunwale@google.com
-jjaggi@google.com
-racarr@google.com
-chaviw@google.com
-vishnun@google.com
-akulian@google.com
-roosa@google.com
# Permissions & Packages
svetoslavganov@google.com
diff --git a/services/core/java/com/android/server/am/OomAdjuster.java b/services/core/java/com/android/server/am/OomAdjuster.java
index 423dd528f5c1..91348aaea9c4 100644
--- a/services/core/java/com/android/server/am/OomAdjuster.java
+++ b/services/core/java/com/android/server/am/OomAdjuster.java
@@ -33,6 +33,8 @@ import static android.app.ActivityManager.PROCESS_STATE_IMPORTANT_BACKGROUND;
import static android.app.ActivityManager.PROCESS_STATE_IMPORTANT_FOREGROUND;
import static android.app.ActivityManager.PROCESS_STATE_LAST_ACTIVITY;
import static android.app.ActivityManager.PROCESS_STATE_NONEXISTENT;
+import static android.app.ActivityManager.PROCESS_STATE_PERSISTENT;
+import static android.app.ActivityManager.PROCESS_STATE_PERSISTENT_UI;
import static android.app.ActivityManager.PROCESS_STATE_SERVICE;
import static android.app.ActivityManager.PROCESS_STATE_TOP;
import static android.app.ActivityManager.PROCESS_STATE_TRANSIENT_BACKGROUND;
@@ -838,7 +840,8 @@ public final class OomAdjuster {
// definition not re-use the same process again, and it is
// good to avoid having whatever code was running in them
// left sitting around after no longer needed.
- app.kill("isolated not needed", ApplicationExitInfo.REASON_OTHER, true);
+ app.kill("isolated not needed", ApplicationExitInfo.REASON_OTHER,
+ ApplicationExitInfo.SUBREASON_ISOLATED_NOT_NEEDED, true);
} else {
// Keeping this process, update its uid.
updateAppUidRecLocked(app);
@@ -1697,13 +1700,13 @@ public final class OomAdjuster {
if (enabled) {
if (cr.hasFlag(Context.BIND_INCLUDE_CAPABILITIES)) {
// TOP process passes all capabilities to the service.
- capability = PROCESS_CAPABILITY_ALL;
+ capability |= PROCESS_CAPABILITY_ALL;
} else {
// TOP process passes no capability to the service.
}
} else {
// TOP process passes all capabilities to the service.
- capability = PROCESS_CAPABILITY_ALL;
+ capability |= PROCESS_CAPABILITY_ALL;
}
} else if (clientProcState
<= PROCESS_STATE_FOREGROUND_SERVICE) {
@@ -2004,17 +2007,9 @@ public final class OomAdjuster {
// apply capability from FGS.
if (app.hasForegroundServices()) {
capability |= capabilityFromFGS;
- } else if (!ActivityManager.isProcStateBackground(procState)) {
- // procState higher than PROCESS_STATE_BOUND_FOREGROUND_SERVICE implicitly has
- // camera/microphone capability
- //TODO: remove this line when enforcing the feature.
- capability |= PROCESS_CAPABILITY_ALL_IMPLICIT;
}
- // TOP process has all capabilities.
- if (procState <= PROCESS_STATE_TOP) {
- capability = PROCESS_CAPABILITY_ALL;
- }
+ capability |= getDefaultCapability(app, procState);
// Do final modification to adj. Everything we do between here and applying
// the final setAdj must be done in this function, because we will also use
@@ -2034,6 +2029,30 @@ public final class OomAdjuster {
|| app.curCapability != prevCapability ;
}
+ private int getDefaultCapability(ProcessRecord app, int procState) {
+ switch (procState) {
+ case PROCESS_STATE_PERSISTENT:
+ case PROCESS_STATE_PERSISTENT_UI:
+ case PROCESS_STATE_TOP:
+ return PROCESS_CAPABILITY_ALL;
+ case PROCESS_STATE_BOUND_TOP:
+ return PROCESS_CAPABILITY_ALL_IMPLICIT;
+ case PROCESS_STATE_FOREGROUND_SERVICE:
+ if (app.hasForegroundServices()) {
+ // Capability from FGS are conditional depending on foreground service type in
+ // manifest file and the mAllowWhileInUsePermissionInFgs flag.
+ return PROCESS_CAPABILITY_NONE;
+ } else {
+ // process has no FGS, the PROCESS_STATE_FOREGROUND_SERVICE is from client.
+ return PROCESS_CAPABILITY_ALL_IMPLICIT;
+ }
+ case PROCESS_STATE_BOUND_FOREGROUND_SERVICE:
+ return PROCESS_CAPABILITY_ALL_IMPLICIT;
+ default:
+ return PROCESS_CAPABILITY_NONE;
+ }
+ }
+
/**
* Checks if for the given app and client, there's a cycle that should skip over the client
* for now or use partial values to evaluate the effect of the client binding.
@@ -2148,7 +2167,8 @@ public final class OomAdjuster {
}
if (app.waitingToKill != null && app.curReceivers.isEmpty()
&& app.setSchedGroup == ProcessList.SCHED_GROUP_BACKGROUND) {
- app.kill(app.waitingToKill, ApplicationExitInfo.REASON_OTHER, true);
+ app.kill(app.waitingToKill, ApplicationExitInfo.REASON_USER_REQUESTED,
+ ApplicationExitInfo.SUBREASON_UNKNOWN, true);
success = false;
} else {
int processGroup;
@@ -2568,11 +2588,16 @@ public final class OomAdjuster {
return;
}
+ // if an app is already frozen and shouldNotFreeze becomes true, immediately unfreeze
+ if (app.frozen && app.shouldNotFreeze) {
+ mCachedAppOptimizer.unfreezeAppLocked(app);
+ }
+
// Use current adjustment when freezing, set adjustment when unfreezing.
- if (app.curAdj >= ProcessList.CACHED_APP_MIN_ADJ && !app.frozen) {
+ if (app.curAdj >= ProcessList.CACHED_APP_MIN_ADJ && !app.frozen && !app.shouldNotFreeze) {
mCachedAppOptimizer.freezeAppAsync(app);
} else if (app.setAdj < ProcessList.CACHED_APP_MIN_ADJ && app.frozen) {
- mCachedAppOptimizer.unfreezeAppAsync(app);
+ mCachedAppOptimizer.unfreezeAppLocked(app);
}
}
}
diff --git a/services/core/java/com/android/server/am/ProcessList.java b/services/core/java/com/android/server/am/ProcessList.java
index 5d1b0e3924ea..6b165139aefd 100644
--- a/services/core/java/com/android/server/am/ProcessList.java
+++ b/services/core/java/com/android/server/am/ProcessList.java
@@ -2378,7 +2378,7 @@ public final class ProcessList {
killProcessQuiet(pid);
Process.killProcessGroup(app.uid, app.pid);
noteAppKill(app, ApplicationExitInfo.REASON_OTHER,
- ApplicationExitInfo.SUBREASON_UNKNOWN, reason);
+ ApplicationExitInfo.SUBREASON_INVALID_START, reason);
return false;
}
mService.mBatteryStatsService.noteProcessStart(app.processName, app.info.uid);
@@ -2396,9 +2396,7 @@ public final class ProcessList {
// Ignore
}
- if (app.isPersistent()) {
- Watchdog.getInstance().processStarted(app.processName, pid);
- }
+ Watchdog.getInstance().processStarted(app.processName, pid);
checkSlow(app.startTime, "startProcess: building log message");
StringBuilder buf = mStringBuilder;
@@ -2465,7 +2463,7 @@ public final class ProcessList {
killProcessQuiet(app.pid);
ProcessList.killProcessGroup(app.uid, app.pid);
noteAppKill(app, ApplicationExitInfo.REASON_OTHER,
- ApplicationExitInfo.SUBREASON_UNKNOWN, "hasn't been killed");
+ ApplicationExitInfo.SUBREASON_REMOVE_LRU, "hasn't been killed");
} else {
app.pendingStart = false;
}
@@ -2483,10 +2481,11 @@ public final class ProcessList {
@GuardedBy("mService")
boolean killPackageProcessesLocked(String packageName, int appId, int userId, int minOomAdj,
- String reason) {
+ int reasonCode, int subReason, String reason) {
return killPackageProcessesLocked(packageName, appId, userId, minOomAdj,
false /* callerWillRestart */, true /* allowRestart */, true /* doit */,
- false /* evenPersistent */, false /* setRemoved */, reason);
+ false /* evenPersistent */, false /* setRemoved */, reasonCode,
+ subReason, reason);
}
@GuardedBy("mService")
@@ -2519,7 +2518,8 @@ public final class ProcessList {
@GuardedBy("mService")
final boolean killPackageProcessesLocked(String packageName, int appId,
int userId, int minOomAdj, boolean callerWillRestart, boolean allowRestart,
- boolean doit, boolean evenPersistent, boolean setRemoved, String reason) {
+ boolean doit, boolean evenPersistent, boolean setRemoved, int reasonCode,
+ int subReason, String reason) {
ArrayList<ProcessRecord> procs = new ArrayList<>();
// Remove all processes this package may have touched: all with the
@@ -2591,7 +2591,8 @@ public final class ProcessList {
int N = procs.size();
for (int i=0; i<N; i++) {
- removeProcessLocked(procs.get(i), callerWillRestart, allowRestart, reason);
+ removeProcessLocked(procs.get(i), callerWillRestart, allowRestart,
+ reasonCode, subReason, reason);
}
killAppZygotesLocked(packageName, appId, userId, false /* force */);
mService.updateOomAdjLocked(OomAdjuster.OOM_ADJ_REASON_PROCESS_END);
@@ -2600,13 +2601,14 @@ public final class ProcessList {
@GuardedBy("mService")
boolean removeProcessLocked(ProcessRecord app,
- boolean callerWillRestart, boolean allowRestart, String reason) {
- return removeProcessLocked(app, callerWillRestart, allowRestart, reason,
- ApplicationExitInfo.REASON_OTHER);
+ boolean callerWillRestart, boolean allowRestart, int reasonCode, String reason) {
+ return removeProcessLocked(app, callerWillRestart, allowRestart, reasonCode,
+ ApplicationExitInfo.SUBREASON_UNKNOWN, reason);
}
- boolean removeProcessLocked(ProcessRecord app,
- boolean callerWillRestart, boolean allowRestart, String reason, int reasonCode) {
+ @GuardedBy("mService")
+ boolean removeProcessLocked(ProcessRecord app, boolean callerWillRestart,
+ boolean allowRestart, int reasonCode, int subReason, String reason) {
final String name = app.processName;
final int uid = app.uid;
if (DEBUG_PROCESSES) Slog.d(TAG_PROCESSES,
@@ -2642,7 +2644,7 @@ public final class ProcessList {
needRestart = true;
}
}
- app.kill(reason, reasonCode, true);
+ app.kill(reason, reasonCode, subReason, true);
mService.handleAppDiedLocked(app, willRestart, allowRestart);
if (willRestart) {
removeLruProcessLocked(app);
@@ -2840,7 +2842,8 @@ public final class ProcessList {
final int N = procs.size();
for (int i = 0; i < N; i++) {
- removeProcessLocked(procs.get(i), false, true, "kill all background except");
+ removeProcessLocked(procs.get(i), false, true, ApplicationExitInfo.REASON_OTHER,
+ ApplicationExitInfo.SUBREASON_KILL_ALL_BG_EXCEPT, "kill all background except");
}
}
@@ -3769,7 +3772,8 @@ public final class ProcessList {
Slog.i(TAG, "note: " + app + " died, saving the exit info");
}
- mAppExitInfoTracker.scheduleNoteProcessDiedLocked(app);
+ Watchdog.getInstance().processDied(app.processName, app.pid);
+ mAppExitInfoTracker.scheduleNoteProcessDied(app);
}
/**
@@ -4005,7 +4009,8 @@ public final class ProcessList {
return false;
}
- app.kill(reason, ApplicationExitInfo.REASON_OTHER, true);
+ app.kill(reason, ApplicationExitInfo.REASON_OTHER,
+ ApplicationExitInfo.SUBREASON_IMPERCEPTIBLE, true);
if (!app.isolated) {
mLastProcessKillTimes.put(app.processName, app.uid, SystemClock.uptimeMillis());
diff --git a/services/core/java/com/android/server/am/ProcessRecord.java b/services/core/java/com/android/server/am/ProcessRecord.java
index f2ca1daec306..c0298110580e 100644
--- a/services/core/java/com/android/server/am/ProcessRecord.java
+++ b/services/core/java/com/android/server/am/ProcessRecord.java
@@ -323,6 +323,8 @@ class ProcessRecord implements WindowProcessListener {
// set of disabled compat changes for the process (all others are enabled)
long[] mDisabledCompatChanges;
+ long mLastRss; // Last computed memory rss.
+
// The precede instance of the process, which would exist when the previous process is killed
// but not fully dead yet; in this case, the new instance of the process should be held until
// this precede instance is fully dead.
@@ -431,6 +433,7 @@ class ProcessRecord implements WindowProcessListener {
pw.print(" lastSwapPss="); DebugUtils.printSizeValue(pw, lastSwapPss*1024);
pw.print(" lastCachedPss="); DebugUtils.printSizeValue(pw, lastCachedPss*1024);
pw.print(" lastCachedSwapPss="); DebugUtils.printSizeValue(pw, lastCachedSwapPss*1024);
+ pw.print(" lastRss="); DebugUtils.printSizeValue(pw, mLastRss * 1024);
pw.println();
pw.print(prefix); pw.print("procStateMemTracker: ");
procStateMemTracker.dumpLine(pw);
diff --git a/services/core/java/com/android/server/appop/AppOpsService.java b/services/core/java/com/android/server/appop/AppOpsService.java
index f1bc6822aa4d..7774633fa1be 100644
--- a/services/core/java/com/android/server/appop/AppOpsService.java
+++ b/services/core/java/com/android/server/appop/AppOpsService.java
@@ -29,6 +29,8 @@ import static android.app.AppOpsManager.KEY_BG_STATE_SETTLE_TIME;
import static android.app.AppOpsManager.KEY_FG_SERVICE_STATE_SETTLE_TIME;
import static android.app.AppOpsManager.KEY_TOP_STATE_SETTLE_TIME;
import static android.app.AppOpsManager.MODE_ALLOWED;
+import static android.app.AppOpsManager.MODE_FOREGROUND;
+import static android.app.AppOpsManager.MODE_IGNORED;
import static android.app.AppOpsManager.NoteOpEvent;
import static android.app.AppOpsManager.OP_CAMERA;
import static android.app.AppOpsManager.OP_FLAGS_ALL;
@@ -38,6 +40,8 @@ import static android.app.AppOpsManager.OP_NONE;
import static android.app.AppOpsManager.OP_PLAY_AUDIO;
import static android.app.AppOpsManager.OP_RECORD_AUDIO;
import static android.app.AppOpsManager.OpEventProxyInfo;
+import static android.app.AppOpsManager.SAMPLING_STRATEGY_RARELY_USED;
+import static android.app.AppOpsManager.SAMPLING_STRATEGY_UNIFORM;
import static android.app.AppOpsManager.UID_STATE_BACKGROUND;
import static android.app.AppOpsManager.UID_STATE_CACHED;
import static android.app.AppOpsManager.UID_STATE_FOREGROUND;
@@ -58,8 +62,6 @@ import static android.content.Intent.ACTION_PACKAGE_REMOVED;
import static android.content.Intent.EXTRA_REPLACING;
import static android.content.pm.PermissionInfo.PROTECTION_DANGEROUS;
import static android.content.pm.PermissionInfo.PROTECTION_FLAG_APPOP;
-import static android.util.StatsLogInternal.RUNTIME_APP_OP_ACCESS__SAMPLING_STRATEGY__RARELY_USED;
-import static android.util.StatsLogInternal.RUNTIME_APP_OP_ACCESS__SAMPLING_STRATEGY__UNIFORM;
import static com.android.server.appop.AppOpsService.ModeCallback.ALL_OPS;
@@ -136,6 +138,7 @@ import android.util.TimeUtils;
import android.util.Xml;
import com.android.internal.annotations.GuardedBy;
+import com.android.internal.annotations.Immutable;
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.app.IAppOpsActiveCallback;
import com.android.internal.app.IAppOpsAsyncNotedCallback;
@@ -153,11 +156,14 @@ import com.android.internal.util.function.pooled.PooledLambda;
import com.android.server.LocalServices;
import com.android.server.LockGuard;
import com.android.server.SystemServerInitThreadPool;
+import com.android.server.SystemServiceManager;
import com.android.server.pm.PackageList;
import com.android.server.pm.parsing.pkg.AndroidPackage;
import libcore.util.EmptyArray;
+import org.json.JSONException;
+import org.json.JSONObject;
import org.xmlpull.v1.XmlPullParser;
import org.xmlpull.v1.XmlPullParserException;
import org.xmlpull.v1.XmlSerializer;
@@ -167,6 +173,7 @@ import java.io.FileDescriptor;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
+import java.io.FileWriter;
import java.io.IOException;
import java.io.PrintWriter;
import java.nio.charset.StandardCharsets;
@@ -182,6 +189,7 @@ import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Objects;
+import java.util.Scanner;
import java.util.concurrent.ThreadLocalRandom;
import java.util.function.Consumer;
@@ -189,6 +197,11 @@ public class AppOpsService extends IAppOpsService.Stub {
static final String TAG = "AppOps";
static final boolean DEBUG = false;
+ /**
+ * Used for data access validation collection, we wish to only log a specific access once
+ */
+ private final ArraySet<NoteOpTrace> mNoteOpCallerStacktraces = new ArraySet<>();
+
private static final int NO_VERSION = -1;
/** Increment by one every time and add the corresponding upgrade logic in
* {@link #upgradeLocked(int)} below. The first version was 1 */
@@ -239,6 +252,7 @@ public class AppOpsService extends IAppOpsService.Stub {
final Context mContext;
final AtomicFile mFile;
+ private final @Nullable File mNoteOpCallerStacktracesFile;
final Handler mHandler;
/** Pool for {@link OpEventProxyInfoPool} to avoid to constantly reallocate new objects */
@@ -276,6 +290,8 @@ public class AppOpsService extends IAppOpsService.Stub {
private final ArrayMap<Pair<String, Integer>, ArrayList<AsyncNotedAppOp>>
mUnforwardedAsyncNotedOps = new ArrayMap<>();
+ boolean mWriteNoteOpsScheduled;
+
boolean mWriteScheduled;
boolean mFastWriteScheduled;
final Runnable mWriteRunner = new Runnable() {
@@ -515,12 +531,12 @@ public class AppOpsService extends IAppOpsService.Stub {
}
int evalMode(int op, int mode) {
- if (mode == AppOpsManager.MODE_FOREGROUND) {
+ if (mode == MODE_FOREGROUND) {
if (appWidgetVisible) {
return MODE_ALLOWED;
} else if (state <= UID_STATE_TOP) {
- // process is in foreground.
- return AppOpsManager.MODE_ALLOWED;
+ // process is in TOP.
+ return MODE_ALLOWED;
} else if (state <= AppOpsManager.resolveFirstUnrestrictedUidState(op)) {
// process is in foreground, check its capability.
switch (op) {
@@ -529,53 +545,53 @@ public class AppOpsService extends IAppOpsService.Stub {
case AppOpsManager.OP_MONITOR_LOCATION:
case AppOpsManager.OP_MONITOR_HIGH_POWER_LOCATION:
if ((capability & PROCESS_CAPABILITY_FOREGROUND_LOCATION) != 0) {
- return AppOpsManager.MODE_ALLOWED;
+ return MODE_ALLOWED;
} else if ((capability
& TEMP_PROCESS_CAPABILITY_FOREGROUND_LOCATION) != 0) {
// The FGS has the location capability, but due to FGS BG start
// restriction it lost the capability, use temp location capability
// to mark this case.
maybeShowWhileInUseDebugToast(op, mode);
- return AppOpsManager.MODE_IGNORED;
+ return MODE_IGNORED;
} else {
- return AppOpsManager.MODE_IGNORED;
+ return MODE_IGNORED;
}
case OP_CAMERA:
if ((capability & PROCESS_CAPABILITY_FOREGROUND_CAMERA) != 0) {
- return AppOpsManager.MODE_ALLOWED;
+ return MODE_ALLOWED;
} else {
maybeShowWhileInUseDebugToast(op, mode);
- return AppOpsManager.MODE_IGNORED;
+ return MODE_IGNORED;
}
case OP_RECORD_AUDIO:
if ((capability & PROCESS_CAPABILITY_FOREGROUND_MICROPHONE) != 0) {
- return AppOpsManager.MODE_ALLOWED;
+ return MODE_ALLOWED;
} else {
maybeShowWhileInUseDebugToast(op, mode);
- return AppOpsManager.MODE_IGNORED;
+ return MODE_IGNORED;
}
default:
- return AppOpsManager.MODE_ALLOWED;
+ return MODE_ALLOWED;
}
} else {
// process is not in foreground.
- return AppOpsManager.MODE_IGNORED;
+ return MODE_IGNORED;
}
- } else if (mode == AppOpsManager.MODE_ALLOWED) {
+ } else if (mode == MODE_ALLOWED) {
switch (op) {
case OP_CAMERA:
if ((capability & PROCESS_CAPABILITY_FOREGROUND_CAMERA) != 0) {
- return AppOpsManager.MODE_ALLOWED;
+ return MODE_ALLOWED;
} else {
maybeShowWhileInUseDebugToast(op, mode);
- return AppOpsManager.MODE_IGNORED;
+ return MODE_IGNORED;
}
case OP_RECORD_AUDIO:
if ((capability & PROCESS_CAPABILITY_FOREGROUND_MICROPHONE) != 0) {
- return AppOpsManager.MODE_ALLOWED;
+ return MODE_ALLOWED;
} else {
maybeShowWhileInUseDebugToast(op, mode);
- return AppOpsManager.MODE_IGNORED;
+ return MODE_IGNORED;
}
default:
return MODE_ALLOWED;
@@ -1395,11 +1411,42 @@ public class AppOpsService extends IAppOpsService.Stub {
featureOp.onClientDeath(clientId);
}
+
+ /**
+ * Loads the OpsValidation file results into a hashmap {@link #mNoteOpCallerStacktraces}
+ * so that we do not log the same operation twice between instances
+ */
+ private void readNoteOpCallerStackTraces() {
+ try {
+ if (!mNoteOpCallerStacktracesFile.exists()) {
+ mNoteOpCallerStacktracesFile.createNewFile();
+ return;
+ }
+
+ try (Scanner read = new Scanner(mNoteOpCallerStacktracesFile)) {
+ read.useDelimiter("\\},");
+ while (read.hasNext()) {
+ String jsonOps = read.next();
+ mNoteOpCallerStacktraces.add(NoteOpTrace.fromJson(jsonOps));
+ }
+ }
+ } catch (Exception e) {
+ Slog.e(TAG, "Cannot parse traces noteOps", e);
+ }
+ }
+
public AppOpsService(File storagePath, Handler handler, Context context) {
mContext = context;
LockGuard.installLock(this, LockGuard.INDEX_APP_OPS);
mFile = new AtomicFile(storagePath, "appops");
+ if (AppOpsManager.NOTE_OP_COLLECTION_ENABLED) {
+ mNoteOpCallerStacktracesFile = new File(SystemServiceManager.ensureSystemDir(),
+ "noteOpStackTraces.json");
+ readNoteOpCallerStackTraces();
+ } else {
+ mNoteOpCallerStacktracesFile = null;
+ }
mHandler = handler;
mConstants = new Constants(mHandler);
readState();
@@ -1800,6 +1847,9 @@ public class AppOpsService extends IAppOpsService.Stub {
if (doWrite) {
writeState();
}
+ if (AppOpsManager.NOTE_OP_COLLECTION_ENABLED && mWriteNoteOpsScheduled) {
+ writeNoteOps();
+ }
}
private ArrayList<AppOpsManager.OpEntry> collectOps(Ops pkgOps, int[] ops) {
@@ -5681,7 +5731,7 @@ public class AppOpsService extends IAppOpsService.Stub {
if (mRarelyUsedPackages.contains(packageName)) {
mRarelyUsedPackages.remove(packageName);
if (ThreadLocalRandom.current().nextFloat() < 0.5f) {
- mSamplingStrategy = RUNTIME_APP_OP_ACCESS__SAMPLING_STRATEGY__RARELY_USED;
+ mSamplingStrategy = SAMPLING_STRATEGY_RARELY_USED;
resampleAppOpForPackageLocked(packageName);
}
}
@@ -5690,7 +5740,7 @@ public class AppOpsService extends IAppOpsService.Stub {
/** Resamples package and appop to watch from the list provided. */
private void resamplePackageAndAppOpLocked(@NonNull List<String> packageNames) {
if (!packageNames.isEmpty()) {
- mSamplingStrategy = RUNTIME_APP_OP_ACCESS__SAMPLING_STRATEGY__UNIFORM;
+ mSamplingStrategy = SAMPLING_STRATEGY_UNIFORM;
resampleAppOpForPackageLocked(packageNames.get(
ThreadLocalRandom.current().nextInt(packageNames.size())));
}
@@ -6049,4 +6099,142 @@ public class AppOpsService extends IAppOpsService.Stub {
setMode(code, uid, packageName, mode, callback);
}
}
+
+
+ /**
+ * Async task for writing note op stack trace, op code, package name and version to file
+ * More specifically, writes all the collected ops from {@link #mNoteOpCallerStacktraces}
+ */
+ private void writeNoteOps() {
+ synchronized (this) {
+ mWriteNoteOpsScheduled = false;
+ }
+ synchronized (mNoteOpCallerStacktracesFile) {
+ try (FileWriter writer = new FileWriter(mNoteOpCallerStacktracesFile)) {
+ int numTraces = mNoteOpCallerStacktraces.size();
+ for (int i = 0; i < numTraces; i++) {
+ // Writing json formatted string into file
+ writer.write(mNoteOpCallerStacktraces.valueAt(i).asJson());
+ // Comma separation, so we can wrap the entire log as a JSON object
+ // when all results are collected
+ writer.write(",");
+ }
+ } catch (IOException e) {
+ Slog.w(TAG, "Failed to load opsValidation file for FileWriter", e);
+ }
+ }
+ }
+
+ /**
+ * This class represents a NoteOp Trace object amd contains the necessary fields that will
+ * be written to file to use for permissions data validation in JSON format
+ */
+ @Immutable
+ static class NoteOpTrace {
+ static final String STACKTRACE = "stackTrace";
+ static final String OP = "op";
+ static final String PACKAGENAME = "packageName";
+ static final String VERSION = "version";
+
+ private final @NonNull String mStackTrace;
+ private final int mOp;
+ private final @Nullable String mPackageName;
+ private final long mVersion;
+
+ /**
+ * Initialize a NoteOp object using a JSON object containing the necessary fields
+ *
+ * @param jsonTrace JSON object represented as a string
+ *
+ * @return NoteOpTrace object initialized with JSON fields
+ */
+ static NoteOpTrace fromJson(String jsonTrace) {
+ try {
+ // Re-add closing bracket which acted as a delimiter by the reader
+ JSONObject obj = new JSONObject(jsonTrace.concat("}"));
+ return new NoteOpTrace(obj.getString(STACKTRACE), obj.getInt(OP),
+ obj.getString(PACKAGENAME), obj.getLong(VERSION));
+ } catch (JSONException e) {
+ // Swallow error, only meant for logging ops, should not affect flow of the code
+ Slog.e(TAG, "Error constructing NoteOpTrace object "
+ + "JSON trace format incorrect", e);
+ return null;
+ }
+ }
+
+ NoteOpTrace(String stackTrace, int op, String packageName, long version) {
+ mStackTrace = stackTrace;
+ mOp = op;
+ mPackageName = packageName;
+ mVersion = version;
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (this == o) return true;
+ if (o == null || getClass() != o.getClass()) return false;
+ NoteOpTrace that = (NoteOpTrace) o;
+ return mOp == that.mOp
+ && mVersion == that.mVersion
+ && mStackTrace.equals(that.mStackTrace)
+ && Objects.equals(mPackageName, that.mPackageName);
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(mStackTrace, mOp, mPackageName, mVersion);
+ }
+
+ /**
+ * The object is formatted as a JSON object and returned as a String
+ *
+ * @return JSON formatted string
+ */
+ public String asJson() {
+ return "{"
+ + "\"" + STACKTRACE + "\":\"" + mStackTrace.replace("\n", "\\n")
+ + '\"' + ",\"" + OP + "\":" + mOp
+ + ",\"" + PACKAGENAME + "\":\"" + mPackageName + '\"'
+ + ",\"" + VERSION + "\":" + mVersion
+ + '}';
+ }
+ }
+
+ /**
+ * Collects noteOps, noteProxyOps and startOps from AppOpsManager and writes it into a file
+ * which will be used for permissions data validation, the given parameters to this method
+ * will be logged in json format
+ *
+ * @param stackTrace stacktrace from the most recent call in AppOpsManager
+ * @param op op code
+ * @param packageName package making call
+ * @param version android version for this call
+ */
+ @Override
+ public void collectNoteOpCallsForValidation(String stackTrace, int op, String packageName,
+ long version) {
+ if (!AppOpsManager.NOTE_OP_COLLECTION_ENABLED) {
+ return;
+ }
+
+ Objects.requireNonNull(stackTrace);
+ Preconditions.checkArgument(op >= 0);
+ Preconditions.checkArgument(op < AppOpsManager._NUM_OP);
+ Objects.requireNonNull(version);
+
+ NoteOpTrace noteOpTrace = new NoteOpTrace(stackTrace, op, packageName, version);
+
+ boolean noteOpSetWasChanged;
+ synchronized (this) {
+ noteOpSetWasChanged = mNoteOpCallerStacktraces.add(noteOpTrace);
+ if (noteOpSetWasChanged && !mWriteNoteOpsScheduled) {
+ mWriteNoteOpsScheduled = true;
+ mHandler.postDelayed(PooledLambda.obtainRunnable((that) -> {
+ AsyncTask.execute(() -> {
+ that.writeNoteOps();
+ });
+ }, this), 2500);
+ }
+ }
+ }
}
diff --git a/services/core/java/com/android/server/biometrics/BiometricService.java b/services/core/java/com/android/server/biometrics/BiometricService.java
index 858c157d3ee1..ecdafb0a7a79 100644
--- a/services/core/java/com/android/server/biometrics/BiometricService.java
+++ b/services/core/java/com/android/server/biometrics/BiometricService.java
@@ -1138,9 +1138,10 @@ public class BiometricService extends SystemService {
biometricStatus = result.second;
- Slog.d(TAG, "Authenticator ID: " + authenticator.id
+ Slog.d(TAG, "Package: " + opPackageName
+ + " Authenticator ID: " + authenticator.id
+ " Modality: " + authenticator.modality
- + " ReportedModality: " + result.first
+ + " Reported Modality: " + result.first
+ " Status: " + biometricStatus);
if (firstBiometricModality == TYPE_NONE) {
diff --git a/services/core/java/com/android/server/compat/CompatChange.java b/services/core/java/com/android/server/compat/CompatChange.java
index 8687f35d745e..7bdeb5969f1f 100644
--- a/services/core/java/com/android/server/compat/CompatChange.java
+++ b/services/core/java/com/android/server/compat/CompatChange.java
@@ -63,7 +63,7 @@ public final class CompatChange extends CompatibilityChangeInfo {
private Map<String, Boolean> mPackageOverrides;
public CompatChange(long changeId) {
- this(changeId, null, -1, false, null);
+ this(changeId, null, -1, false, false, null);
}
/**
@@ -74,8 +74,8 @@ public final class CompatChange extends CompatibilityChangeInfo {
* @param disabled If {@code true}, overrides any {@code enableAfterTargetSdk} set.
*/
public CompatChange(long changeId, @Nullable String name, int enableAfterTargetSdk,
- boolean disabled, String description) {
- super(changeId, name, enableAfterTargetSdk, disabled, description);
+ boolean disabled, boolean loggingOnly, String description) {
+ super(changeId, name, enableAfterTargetSdk, disabled, loggingOnly, description);
}
/**
@@ -83,7 +83,7 @@ public final class CompatChange extends CompatibilityChangeInfo {
*/
public CompatChange(Change change) {
super(change.getId(), change.getName(), change.getEnableAfterTargetSdk(),
- change.getDisabled(), change.getDescription());
+ change.getDisabled(), change.getLoggingOnly(), change.getDescription());
}
void registerListener(ChangeListener listener) {
@@ -105,6 +105,10 @@ public final class CompatChange extends CompatibilityChangeInfo {
* @param enabled Whether or not to enable the change.
*/
void addPackageOverride(String pname, boolean enabled) {
+ if (getLoggingOnly()) {
+ throw new IllegalArgumentException(
+ "Can't add overrides for a logging only change " + toString());
+ }
if (mPackageOverrides == null) {
mPackageOverrides = new HashMap<>();
}
@@ -160,6 +164,9 @@ public final class CompatChange extends CompatibilityChangeInfo {
if (getDisabled()) {
sb.append("; disabled");
}
+ if (getLoggingOnly()) {
+ sb.append("; loggingOnly");
+ }
if (mPackageOverrides != null && mPackageOverrides.size() > 0) {
sb.append("; packageOverrides=").append(mPackageOverrides);
}
diff --git a/services/core/java/com/android/server/compat/CompatConfig.java b/services/core/java/com/android/server/compat/CompatConfig.java
index 441d9d9f380e..61bede987bae 100644
--- a/services/core/java/com/android/server/compat/CompatConfig.java
+++ b/services/core/java/com/android/server/compat/CompatConfig.java
@@ -206,6 +206,32 @@ final class CompatConfig {
}
/**
+ * Returns whether the change is marked as logging only.
+ */
+ boolean isLoggingOnly(long changeId) {
+ synchronized (mChanges) {
+ CompatChange c = mChanges.get(changeId);
+ if (c == null) {
+ return false;
+ }
+ return c.getLoggingOnly();
+ }
+ }
+
+ /**
+ * Returns whether the change is marked as disabled.
+ */
+ boolean isDisabled(long changeId) {
+ synchronized (mChanges) {
+ CompatChange c = mChanges.get(changeId);
+ if (c == null) {
+ return false;
+ }
+ return c.getDisabled();
+ }
+ }
+
+ /**
* Removes an override previously added via {@link #addOverride(long, String, boolean)}. This
* restores the default behaviour for the given change and app, once any app processes have been
* restarted.
@@ -365,6 +391,7 @@ final class CompatConfig {
change.getName(),
change.getEnableAfterTargetSdk(),
change.getDisabled(),
+ change.getLoggingOnly(),
change.getDescription());
}
return changeInfos;
diff --git a/services/core/java/com/android/server/compat/OverrideValidatorImpl.java b/services/core/java/com/android/server/compat/OverrideValidatorImpl.java
index 4bf606e801f9..f5d6e5ac46e5 100644
--- a/services/core/java/com/android/server/compat/OverrideValidatorImpl.java
+++ b/services/core/java/com/android/server/compat/OverrideValidatorImpl.java
@@ -20,6 +20,7 @@ import static com.android.internal.compat.OverrideAllowedState.ALLOWED;
import static com.android.internal.compat.OverrideAllowedState.DISABLED_NON_TARGET_SDK;
import static com.android.internal.compat.OverrideAllowedState.DISABLED_NOT_DEBUGGABLE;
import static com.android.internal.compat.OverrideAllowedState.DISABLED_TARGET_SDK_TOO_HIGH;
+import static com.android.internal.compat.OverrideAllowedState.LOGGING_ONLY_CHANGE;
import static com.android.internal.compat.OverrideAllowedState.PACKAGE_DOES_NOT_EXIST;
import android.content.Context;
@@ -51,12 +52,14 @@ public class OverrideValidatorImpl extends IOverrideValidator.Stub {
@Override
public OverrideAllowedState getOverrideAllowedState(long changeId, String packageName) {
- boolean debuggableBuild = false;
- boolean finalBuild = false;
- int minTargetSdk = mCompatConfig.minTargetSdkForChangeId(changeId);
+ if (mCompatConfig.isLoggingOnly(changeId)) {
+ return new OverrideAllowedState(LOGGING_ONLY_CHANGE, -1, -1);
+ }
- debuggableBuild = mAndroidBuildClassifier.isDebuggableBuild();
- finalBuild = mAndroidBuildClassifier.isFinalBuild();
+ boolean debuggableBuild = mAndroidBuildClassifier.isDebuggableBuild();
+ boolean finalBuild = mAndroidBuildClassifier.isFinalBuild();
+ int minTargetSdk = mCompatConfig.minTargetSdkForChangeId(changeId);
+ boolean disabled = mCompatConfig.isDisabled(changeId);
// Allow any override for userdebug or eng builds.
if (debuggableBuild) {
@@ -81,12 +84,12 @@ public class OverrideValidatorImpl extends IOverrideValidator.Stub {
if (!finalBuild) {
return new OverrideAllowedState(ALLOWED, appTargetSdk, minTargetSdk);
}
- // Do not allow overriding non-target sdk gated changes on user builds
- if (minTargetSdk == -1) {
+ // Do not allow overriding default enabled changes on user builds
+ if (minTargetSdk == -1 && !disabled) {
return new OverrideAllowedState(DISABLED_NON_TARGET_SDK, appTargetSdk, minTargetSdk);
}
// Only allow to opt-in for a targetSdk gated change.
- if (applicationInfo.targetSdkVersion < minTargetSdk) {
+ if (disabled || applicationInfo.targetSdkVersion < minTargetSdk) {
return new OverrideAllowedState(ALLOWED, appTargetSdk, minTargetSdk);
}
return new OverrideAllowedState(DISABLED_TARGET_SDK_TOO_HIGH, appTargetSdk, minTargetSdk);
diff --git a/services/core/java/com/android/server/connectivity/NetworkAgentInfo.java b/services/core/java/com/android/server/connectivity/NetworkAgentInfo.java
index 58b5cba477da..2f047157d4aa 100644
--- a/services/core/java/com/android/server/connectivity/NetworkAgentInfo.java
+++ b/services/core/java/com/android/server/connectivity/NetworkAgentInfo.java
@@ -32,7 +32,6 @@ import android.net.NetworkCapabilities;
import android.net.NetworkInfo;
import android.net.NetworkMonitorManager;
import android.net.NetworkRequest;
-import android.net.NetworkScore;
import android.net.NetworkState;
import android.os.Handler;
import android.os.INetworkManagementService;
@@ -161,10 +160,6 @@ public class NetworkAgentInfo implements Comparable<NetworkAgentInfo> {
// Whether a captive portal was found during the last network validation attempt.
public boolean lastCaptivePortalDetected;
- // Indicates the captive portal app was opened to show a login UI to the user, but the network
- // has not validated yet.
- public volatile boolean captivePortalValidationPending;
-
// Set to true when partial connectivity was detected.
public boolean partialConnectivity;
@@ -236,10 +231,8 @@ public class NetworkAgentInfo implements Comparable<NetworkAgentInfo> {
// validated).
private boolean mLingering;
- // This represents the characteristics of a network that affects how good the network is
- // considered for a particular use.
- @NonNull
- private NetworkScore mNetworkScore;
+ // This represents the quality of the network with no clear scale.
+ private int mScore;
// The list of NetworkRequests being satisfied by this Network.
private final SparseArray<NetworkRequest> mNetworkRequests = new SparseArray<>();
@@ -268,7 +261,7 @@ public class NetworkAgentInfo implements Comparable<NetworkAgentInfo> {
private final Handler mHandler;
public NetworkAgentInfo(Messenger messenger, AsyncChannel ac, Network net, NetworkInfo info,
- LinkProperties lp, NetworkCapabilities nc, @NonNull NetworkScore ns, Context context,
+ LinkProperties lp, NetworkCapabilities nc, int score, Context context,
Handler handler, NetworkAgentConfig config, ConnectivityService connService, INetd netd,
IDnsResolver dnsResolver, INetworkManagementService nms, int factorySerialNumber) {
this.messenger = messenger;
@@ -277,7 +270,7 @@ public class NetworkAgentInfo implements Comparable<NetworkAgentInfo> {
networkInfo = info;
linkProperties = lp;
networkCapabilities = nc;
- mNetworkScore = ns;
+ mScore = score;
clatd = new Nat464Xlat(this, netd, dnsResolver, nms);
mConnService = connService;
mContext = context;
@@ -491,7 +484,7 @@ public class NetworkAgentInfo implements Comparable<NetworkAgentInfo> {
return ConnectivityConstants.EXPLICITLY_SELECTED_NETWORK_SCORE;
}
- int score = mNetworkScore.getIntExtension(NetworkScore.LEGACY_SCORE);
+ int score = mScore;
if (!lastValidated && !pretendValidated && !ignoreWifiUnvalidationPenalty() && !isVPN()) {
score -= ConnectivityConstants.UNVALIDATED_SCORE_PENALTY;
}
@@ -520,13 +513,8 @@ public class NetworkAgentInfo implements Comparable<NetworkAgentInfo> {
return getCurrentScore(true);
}
- public void setNetworkScore(@NonNull NetworkScore ns) {
- mNetworkScore = ns;
- }
-
- @NonNull
- public NetworkScore getNetworkScore() {
- return mNetworkScore;
+ public void setScore(final int score) {
+ mScore = score;
}
public NetworkState getNetworkState() {
@@ -646,7 +634,6 @@ public class NetworkAgentInfo implements Comparable<NetworkAgentInfo> {
+ "acceptUnvalidated{" + networkAgentConfig.acceptUnvalidated + "} "
+ "everCaptivePortalDetected{" + everCaptivePortalDetected + "} "
+ "lastCaptivePortalDetected{" + lastCaptivePortalDetected + "} "
- + "captivePortalValidationPending{" + captivePortalValidationPending + "} "
+ "partialConnectivity{" + partialConnectivity + "} "
+ "acceptPartialConnectivity{" + networkAgentConfig.acceptPartialConnectivity + "} "
+ "clat{" + clatd + "} "
diff --git a/services/core/java/com/android/server/connectivity/NetworkNotificationManager.java b/services/core/java/com/android/server/connectivity/NetworkNotificationManager.java
index 25c761ab80ec..0925de8f9577 100644
--- a/services/core/java/com/android/server/connectivity/NetworkNotificationManager.java
+++ b/services/core/java/com/android/server/connectivity/NetworkNotificationManager.java
@@ -51,7 +51,6 @@ public class NetworkNotificationManager {
LOST_INTERNET(SystemMessage.NOTE_NETWORK_LOST_INTERNET),
NETWORK_SWITCH(SystemMessage.NOTE_NETWORK_SWITCH),
NO_INTERNET(SystemMessage.NOTE_NETWORK_NO_INTERNET),
- LOGGED_IN(SystemMessage.NOTE_NETWORK_LOGGED_IN),
PARTIAL_CONNECTIVITY(SystemMessage.NOTE_NETWORK_PARTIAL_CONNECTIVITY),
SIGN_IN(SystemMessage.NOTE_NETWORK_SIGN_IN),
PRIVATE_DNS_BROKEN(SystemMessage.NOTE_NETWORK_PRIVATE_DNS_BROKEN);
@@ -114,14 +113,10 @@ public class NetworkNotificationManager {
}
}
- private static int getIcon(int transportType, NotificationType notifyType) {
- if (transportType != TRANSPORT_WIFI) {
- return R.drawable.stat_notify_rssi_in_range;
- }
-
- return notifyType == NotificationType.LOGGED_IN
- ? R.drawable.ic_wifi_signal_4
- : R.drawable.stat_notify_wifi_in_range; // TODO: Distinguish ! from ?.
+ private static int getIcon(int transportType) {
+ return (transportType == TRANSPORT_WIFI)
+ ? R.drawable.stat_notify_wifi_in_range : // TODO: Distinguish ! from ?.
+ R.drawable.stat_notify_rssi_in_range;
}
/**
@@ -185,7 +180,7 @@ public class NetworkNotificationManager {
Resources r = mContext.getResources();
final CharSequence title;
final CharSequence details;
- int icon = getIcon(transportType, notifyType);
+ int icon = getIcon(transportType);
if (notifyType == NotificationType.NO_INTERNET && transportType == TRANSPORT_WIFI) {
title = r.getString(R.string.wifi_no_internet,
WifiInfo.sanitizeSsid(nai.networkCapabilities.getSSID()));
@@ -235,9 +230,6 @@ public class NetworkNotificationManager {
details = r.getString(R.string.network_available_sign_in_detailed, name);
break;
}
- } else if (notifyType == NotificationType.LOGGED_IN) {
- title = WifiInfo.sanitizeSsid(nai.networkCapabilities.getSSID());
- details = r.getString(R.string.captive_portal_logged_in_detailed);
} else if (notifyType == NotificationType.NETWORK_SWITCH) {
String fromTransport = getTransportName(transportType);
String toTransport = getTransportName(approximateTransportType(switchToNai));
@@ -379,7 +371,6 @@ public class NetworkNotificationManager {
case NETWORK_SWITCH:
return 2;
case LOST_INTERNET:
- case LOGGED_IN:
return 1;
default:
return 0;
diff --git a/services/core/java/com/android/server/connectivity/Vpn.java b/services/core/java/com/android/server/connectivity/Vpn.java
index e484ca0a2487..7c3cab17704f 100644
--- a/services/core/java/com/android/server/connectivity/Vpn.java
+++ b/services/core/java/com/android/server/connectivity/Vpn.java
@@ -52,7 +52,6 @@ import android.net.Ikev2VpnProfile;
import android.net.IpPrefix;
import android.net.IpSecManager;
import android.net.IpSecManager.IpSecTunnelInterface;
-import android.net.IpSecManager.UdpEncapsulationSocket;
import android.net.IpSecTransform;
import android.net.LinkAddress;
import android.net.LinkProperties;
@@ -952,18 +951,18 @@ public class Vpn {
|| isVpnServicePreConsented(context, packageName);
}
- private int getAppUid(String app, int userHandle) {
+ private int getAppUid(final String app, final int userHandle) {
if (VpnConfig.LEGACY_VPN.equals(app)) {
return Process.myUid();
}
PackageManager pm = mContext.getPackageManager();
- int result;
- try {
- result = pm.getPackageUidAsUser(app, userHandle);
- } catch (NameNotFoundException e) {
- result = -1;
- }
- return result;
+ return Binder.withCleanCallingIdentity(() -> {
+ try {
+ return pm.getPackageUidAsUser(app, userHandle);
+ } catch (NameNotFoundException e) {
+ return -1;
+ }
+ });
}
private boolean doesPackageTargetAtLeastQ(String packageName) {
@@ -2201,7 +2200,6 @@ public class Vpn {
/** Signal to ensure shutdown is honored even if a new Network is connected. */
private boolean mIsRunning = true;
- @Nullable private UdpEncapsulationSocket mEncapSocket;
@Nullable private IpSecTunnelInterface mTunnelIface;
@Nullable private IkeSession mSession;
@Nullable private Network mActiveNetwork;
@@ -2352,29 +2350,21 @@ public class Vpn {
resetIkeState();
mActiveNetwork = network;
- // TODO(b/149356682): Update this based on new IKE API
- mEncapSocket = mIpSecManager.openUdpEncapsulationSocket();
-
- // TODO(b/149356682): Update this based on new IKE API
final IkeSessionParams ikeSessionParams =
- VpnIkev2Utils.buildIkeSessionParams(mProfile, mEncapSocket);
+ VpnIkev2Utils.buildIkeSessionParams(mContext, mProfile, network);
final ChildSessionParams childSessionParams =
VpnIkev2Utils.buildChildSessionParams();
// TODO: Remove the need for adding two unused addresses with
// IPsec tunnels.
+ final InetAddress address = InetAddress.getLocalHost();
mTunnelIface =
mIpSecManager.createIpSecTunnelInterface(
- ikeSessionParams.getServerAddress() /* unused */,
- ikeSessionParams.getServerAddress() /* unused */,
+ address /* unused */,
+ address /* unused */,
network);
mNetd.setInterfaceUp(mTunnelIface.getInterfaceName());
- // Socket must be bound to prevent network switches from causing
- // the IKE teardown to fail/timeout.
- // TODO(b/149356682): Update this based on new IKE API
- network.bindSocket(mEncapSocket.getFileDescriptor());
-
mSession = mIkev2SessionCreator.createIkeSession(
mContext,
ikeSessionParams,
@@ -2459,16 +2449,6 @@ public class Vpn {
mSession.kill(); // Kill here to make sure all resources are released immediately
mSession = null;
}
-
- // TODO(b/149356682): Update this based on new IKE API
- if (mEncapSocket != null) {
- try {
- mEncapSocket.close();
- } catch (IOException e) {
- Log.e(TAG, "Failed to close encap socket", e);
- }
- mEncapSocket = null;
- }
}
/**
diff --git a/services/core/java/com/android/server/connectivity/VpnIkev2Utils.java b/services/core/java/com/android/server/connectivity/VpnIkev2Utils.java
index 33fc32b78df7..3da304c07910 100644
--- a/services/core/java/com/android/server/connectivity/VpnIkev2Utils.java
+++ b/services/core/java/com/android/server/connectivity/VpnIkev2Utils.java
@@ -35,10 +35,10 @@ import static android.net.ipsec.ike.SaProposal.PSEUDORANDOM_FUNCTION_AES128_XCBC
import static android.net.ipsec.ike.SaProposal.PSEUDORANDOM_FUNCTION_HMAC_SHA1;
import android.annotation.NonNull;
+import android.content.Context;
import android.net.Ikev2VpnProfile;
import android.net.InetAddresses;
import android.net.IpPrefix;
-import android.net.IpSecManager.UdpEncapsulationSocket;
import android.net.IpSecTransform;
import android.net.Network;
import android.net.RouteInfo;
@@ -84,18 +84,14 @@ import java.util.List;
*/
public class VpnIkev2Utils {
static IkeSessionParams buildIkeSessionParams(
- @NonNull Ikev2VpnProfile profile, @NonNull UdpEncapsulationSocket socket) {
- // TODO(b/149356682): Update this based on new IKE API. Only numeric addresses supported
- // until then. All others throw IAE (caught by caller).
- final InetAddress serverAddr = InetAddresses.parseNumericAddress(profile.getServerAddr());
+ @NonNull Context context, @NonNull Ikev2VpnProfile profile, @NonNull Network network) {
final IkeIdentification localId = parseIkeIdentification(profile.getUserIdentity());
final IkeIdentification remoteId = parseIkeIdentification(profile.getServerAddr());
- // TODO(b/149356682): Update this based on new IKE API.
final IkeSessionParams.Builder ikeOptionsBuilder =
- new IkeSessionParams.Builder()
- .setServerAddress(serverAddr)
- .setUdpEncapsulationSocket(socket)
+ new IkeSessionParams.Builder(context)
+ .setServerHostname(profile.getServerAddr())
+ .setNetwork(network)
.setLocalIdentification(localId)
.setRemoteIdentification(remoteId);
setIkeAuth(profile, ikeOptionsBuilder);
diff --git a/services/core/java/com/android/server/content/ContentService.java b/services/core/java/com/android/server/content/ContentService.java
index 74c1e63172fa..61b18eedfc6e 100644
--- a/services/core/java/com/android/server/content/ContentService.java
+++ b/services/core/java/com/android/server/content/ContentService.java
@@ -83,6 +83,7 @@ import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;
+import java.util.Objects;
/**
* {@hide}
@@ -399,15 +400,22 @@ public final class ContentService extends IContentService.Stub {
public void notifyChange(Uri[] uris, IContentObserver observer,
boolean observerWantsSelfNotifications, int flags, int userHandle,
int targetSdkVersion, String callingPackage) {
+ final ObserverCollector collector = new ObserverCollector();
for (Uri uri : uris) {
notifyChange(uri, observer, observerWantsSelfNotifications, flags, userHandle,
- targetSdkVersion, callingPackage);
+ targetSdkVersion, callingPackage, collector);
+ }
+ final long token = clearCallingIdentity();
+ try {
+ collector.dispatch();
+ } finally {
+ Binder.restoreCallingIdentity(token);
}
}
public void notifyChange(Uri uri, IContentObserver observer,
boolean observerWantsSelfNotifications, int flags, int userHandle,
- int targetSdkVersion, String callingPackage) {
+ int targetSdkVersion, String callingPackage, ObserverCollector collector) {
if (DEBUG) Slog.d(TAG, "Notifying update of " + uri + " for user " + userHandle
+ " from observer " + observer + ", flags " + Integer.toHexString(flags));
@@ -442,22 +450,9 @@ public final class ContentService extends IContentService.Stub {
// process rather than the caller's process. We will restore this before returning.
long identityToken = clearCallingIdentity();
try {
- ArrayList<ObserverCall> calls = new ArrayList<ObserverCall>();
synchronized (mRootNode) {
mRootNode.collectObserversLocked(uri, 0, observer, observerWantsSelfNotifications,
- flags, userHandle, calls);
- }
- final int numCalls = calls.size();
- for (int i = 0; i < numCalls; i++) {
- // Immediately dispatch notifications to foreground apps that
- // are important to the user; all other background observers are
- // delayed to avoid stampeding
- final ObserverCall oc = calls.get(i);
- if (oc.mProcState <= ActivityManager.PROCESS_STATE_IMPORTANT_FOREGROUND) {
- oc.run();
- } else {
- BackgroundThread.getHandler().postDelayed(oc, BACKGROUND_OBSERVER_DELAY);
- }
+ flags, userHandle, collector);
}
if ((flags&ContentResolver.NOTIFY_SYNC_TO_NETWORK) != 0) {
SyncManager syncManager = getSyncManager();
@@ -487,40 +482,84 @@ public final class ContentService extends IContentService.Stub {
}
}
- public void notifyChange(Uri uri, IContentObserver observer,
- boolean observerWantsSelfNotifications, boolean syncToNetwork,
- String callingPackage) {
- notifyChange(uri, observer, observerWantsSelfNotifications,
- syncToNetwork ? ContentResolver.NOTIFY_SYNC_TO_NETWORK : 0,
- UserHandle.getCallingUserId(), Build.VERSION_CODES.CUR_DEVELOPMENT, callingPackage);
- }
-
- /** {@hide} */
+ /**
+ * Collection of detected change notifications that should be delivered.
+ * <p>
+ * To help reduce Binder transaction overhead, this class clusters together
+ * multiple {@link Uri} where all other arguments are identical.
+ */
@VisibleForTesting
- public static final class ObserverCall implements Runnable {
- final IContentObserver mObserver;
- final boolean mSelfChange;
- final Uri mUri;
- final int mUserId;
- final int mProcState;
-
- ObserverCall(IContentObserver observer, boolean selfChange, Uri uri, int userId,
- int procState) {
- mObserver = observer;
- mSelfChange = selfChange;
- mUri = uri;
- mUserId = userId;
- mProcState = procState;
+ public static class ObserverCollector {
+ private final ArrayMap<Key, List<Uri>> collected = new ArrayMap<>();
+
+ private static class Key {
+ final IContentObserver observer;
+ final int uid;
+ final boolean selfChange;
+ final int flags;
+ final int userId;
+
+ Key(IContentObserver observer, int uid, boolean selfChange, int flags, int userId) {
+ this.observer = observer;
+ this.uid = uid;
+ this.selfChange = selfChange;
+ this.flags = flags;
+ this.userId = userId;
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (!(o instanceof Key)) {
+ return false;
+ }
+ final Key other = (Key) o;
+ return Objects.equals(observer, other.observer)
+ && (uid == other.uid)
+ && (selfChange == other.selfChange)
+ && (flags == other.flags)
+ && (userId == other.userId);
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(observer, uid, selfChange, flags, userId);
+ }
}
- @Override
- public void run() {
- try {
- mObserver.onChange(mSelfChange, mUri, mUserId);
- if (DEBUG) Slog.d(TAG, "Notified " + mObserver + " of update at " + mUri);
- } catch (RemoteException ignored) {
- // We already have a death observer that will clean up if the
- // remote process dies
+ public void collect(IContentObserver observer, int uid, boolean selfChange, Uri uri,
+ int flags, int userId) {
+ final Key key = new Key(observer, uid, selfChange, flags, userId);
+ List<Uri> value = collected.get(key);
+ if (value == null) {
+ value = new ArrayList<>();
+ collected.put(key, value);
+ }
+ value.add(uri);
+ }
+
+ public void dispatch() {
+ for (int i = 0; i < collected.size(); i++) {
+ final Key key = collected.keyAt(i);
+ final List<Uri> value = collected.valueAt(i);
+
+ final Runnable task = () -> {
+ try {
+ key.observer.onChangeEtc(key.selfChange,
+ value.toArray(new Uri[value.size()]), key.flags, key.userId);
+ } catch (RemoteException ignored) {
+ }
+ };
+
+ // Immediately dispatch notifications to foreground apps that
+ // are important to the user; all other background observers are
+ // delayed to avoid stampeding
+ final int procState = LocalServices.getService(ActivityManagerInternal.class)
+ .getUidProcessState(key.uid);
+ if (procState <= ActivityManager.PROCESS_STATE_IMPORTANT_FOREGROUND) {
+ task.run();
+ } else {
+ BackgroundThread.getHandler().postDelayed(task, BACKGROUND_OBSERVER_DELAY);
+ }
}
}
}
@@ -1455,10 +1494,6 @@ public final class ContentService extends IContentService.Stub {
}
}
- public static final int INSERT_TYPE = 0;
- public static final int UPDATE_TYPE = 1;
- public static final int DELETE_TYPE = 2;
-
private String mName;
private ArrayList<ObserverNode> mChildren = new ArrayList<ObserverNode>();
private ArrayList<ObserverEntry> mObservers = new ArrayList<ObserverEntry>();
@@ -1588,7 +1623,7 @@ public final class ContentService extends IContentService.Stub {
private void collectMyObserversLocked(Uri uri, boolean leaf, IContentObserver observer,
boolean observerWantsSelfNotifications, int flags,
- int targetUserHandle, ArrayList<ObserverCall> calls) {
+ int targetUserHandle, ObserverCollector collector) {
int N = mObservers.size();
IBinder observerBinder = observer == null ? null : observer.asBinder();
for (int i = 0; i < N; i++) {
@@ -1628,10 +1663,8 @@ public final class ContentService extends IContentService.Stub {
if (DEBUG) Slog.d(TAG, "Reporting to " + entry.observer + ": leaf=" + leaf
+ " flags=" + Integer.toHexString(flags)
+ " desc=" + entry.notifyForDescendants);
- final int procState = LocalServices.getService(ActivityManagerInternal.class)
- .getUidProcessState(entry.uid);
- calls.add(new ObserverCall(entry.observer, selfChange, uri,
- targetUserHandle, procState));
+ collector.collect(entry.observer, entry.uid, selfChange, uri, flags,
+ targetUserHandle);
}
}
}
@@ -1641,21 +1674,21 @@ public final class ContentService extends IContentService.Stub {
*/
public void collectObserversLocked(Uri uri, int index, IContentObserver observer,
boolean observerWantsSelfNotifications, int flags,
- int targetUserHandle, ArrayList<ObserverCall> calls) {
+ int targetUserHandle, ObserverCollector collector) {
String segment = null;
int segmentCount = countUriSegments(uri);
if (index >= segmentCount) {
// This is the leaf node, notify all observers
if (DEBUG) Slog.d(TAG, "Collecting leaf observers @ #" + index + ", node " + mName);
collectMyObserversLocked(uri, true, observer, observerWantsSelfNotifications,
- flags, targetUserHandle, calls);
+ flags, targetUserHandle, collector);
} else if (index < segmentCount){
segment = getUriSegment(uri, index);
if (DEBUG) Slog.d(TAG, "Collecting non-leaf observers @ #" + index + " / "
+ segment);
// Notify any observers at this level who are interested in descendants
collectMyObserversLocked(uri, false, observer, observerWantsSelfNotifications,
- flags, targetUserHandle, calls);
+ flags, targetUserHandle, collector);
}
int N = mChildren.size();
@@ -1664,7 +1697,7 @@ public final class ContentService extends IContentService.Stub {
if (segment == null || node.mName.equals(segment)) {
// We found the child,
node.collectObserversLocked(uri, index + 1, observer,
- observerWantsSelfNotifications, flags, targetUserHandle, calls);
+ observerWantsSelfNotifications, flags, targetUserHandle, collector);
if (segment != null) {
break;
}
diff --git a/services/core/java/com/android/server/content/SyncStorageEngine.java b/services/core/java/com/android/server/content/SyncStorageEngine.java
index 8c510b735ccd..e9c4b510039d 100644
--- a/services/core/java/com/android/server/content/SyncStorageEngine.java
+++ b/services/core/java/com/android/server/content/SyncStorageEngine.java
@@ -472,8 +472,7 @@ public class SyncStorageEngine {
private int mSyncRandomOffset;
- // STOPSHIP: b/143656271 this should be true on launch
- private static final boolean DELETE_LEGACY_PARCEL_FILES = false;
+ private static final boolean DELETE_LEGACY_PARCEL_FILES = true;
private static final String LEGACY_STATUS_FILE_NAME = "status.bin";
private static final String LEGACY_STATISTICS_FILE_NAME = "stats.bin";
@@ -2076,7 +2075,7 @@ public class SyncStorageEngine {
}
// if upgrade to proto was successful, delete parcel file
- if (DELETE_LEGACY_PARCEL_FILES && mStatusFile.exists()) {
+ if (DELETE_LEGACY_PARCEL_FILES && parcelStatus.exists() && mStatusFile.exists()) {
parcelStatus.delete();
}
}
@@ -2475,7 +2474,7 @@ public class SyncStorageEngine {
}
// if upgrade to proto was successful, delete parcel file
- if (DELETE_LEGACY_PARCEL_FILES && mStatisticsFile.exists()) {
+ if (DELETE_LEGACY_PARCEL_FILES && parcelStats.exists() && mStatisticsFile.exists()) {
parcelStats.delete();
}
}
diff --git a/services/core/java/com/android/server/incremental/IncrementalManagerService.java b/services/core/java/com/android/server/incremental/IncrementalManagerService.java
deleted file mode 100644
index cadb9d027d0f..000000000000
--- a/services/core/java/com/android/server/incremental/IncrementalManagerService.java
+++ /dev/null
@@ -1,146 +0,0 @@
-/*
- * Copyright (C) 2019 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.server.incremental;
-
-import android.annotation.NonNull;
-import android.content.Context;
-import android.content.pm.DataLoaderManager;
-import android.content.pm.DataLoaderParamsParcel;
-import android.content.pm.FileSystemControlParcel;
-import android.content.pm.IDataLoader;
-import android.content.pm.IDataLoaderStatusListener;
-import android.os.RemoteException;
-import android.os.ServiceManager;
-import android.os.incremental.IIncrementalManager;
-import android.util.Slog;
-
-import com.android.internal.util.DumpUtils;
-
-import java.io.FileDescriptor;
-import java.io.PrintWriter;
-
-/**
- * This service has the following purposes:
- * 1) Starts the IIncrementalManager binder service.
- * 1) Starts the native IIncrementalManagerService binder service.
- * 2) Handles shell commands for "incremental" service.
- * 3) Handles binder calls from the native IIncrementalManagerService binder service and pass
- * them to a data loader binder service.
- */
-
-public class IncrementalManagerService extends IIncrementalManager.Stub {
- private static final String TAG = "IncrementalManagerService";
- private static final String BINDER_SERVICE_NAME = "incremental";
- // DataLoaderManagerService should have been started before us
- private @NonNull DataLoaderManager mDataLoaderManager;
- private long mNativeInstance;
- private final @NonNull Context mContext;
-
- /**
- * Starts IIncrementalManager binder service and register to Service Manager.
- * Starts the native IIncrementalManagerNative binder service.
- */
- public static IncrementalManagerService start(Context context) {
- IncrementalManagerService self = new IncrementalManagerService(context);
- if (self.mNativeInstance == 0) {
- return null;
- }
- return self;
- }
-
- private IncrementalManagerService(Context context) {
- mContext = context;
- mDataLoaderManager = mContext.getSystemService(DataLoaderManager.class);
- ServiceManager.addService(BINDER_SERVICE_NAME, this);
- // Starts and register IIncrementalManagerNative service
- mNativeInstance = nativeStartService();
- }
-
- @SuppressWarnings("resource")
- @Override
- protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
- if (!DumpUtils.checkDumpAndUsageStatsPermission(mContext, TAG, pw)) return;
- nativeDump(mNativeInstance, fd.getInt$());
- }
-
- /**
- * Notifies native IIncrementalManager service that system is ready.
- */
- public void systemReady() {
- nativeSystemReady(mNativeInstance);
- }
-
- /**
- * Finds data loader service provider and binds to it. This requires PackageManager.
- */
- @Override
- public boolean prepareDataLoader(int mountId, FileSystemControlParcel control,
- DataLoaderParamsParcel params,
- IDataLoaderStatusListener listener) {
- DataLoaderManager dataLoaderManager = mContext.getSystemService(DataLoaderManager.class);
- if (dataLoaderManager == null) {
- Slog.e(TAG, "Failed to find data loader manager service");
- return false;
- }
- if (!dataLoaderManager.initializeDataLoader(mountId, params, control, listener)) {
- Slog.e(TAG, "Failed to initialize data loader");
- return false;
- }
- return true;
- }
-
-
- @Override
- public boolean startDataLoader(int mountId) {
- IDataLoader dataLoader = mDataLoaderManager.getDataLoader(mountId);
- if (dataLoader == null) {
- Slog.e(TAG, "Start failed to retrieve data loader for ID=" + mountId);
- return false;
- }
- try {
- dataLoader.start();
- return true;
- } catch (RemoteException ex) {
- return false;
- }
- }
-
- @Override
- public void destroyDataLoader(int mountId) {
- IDataLoader dataLoader = mDataLoaderManager.getDataLoader(mountId);
- if (dataLoader == null) {
- Slog.e(TAG, "Destroy failed to retrieve data loader for ID=" + mountId);
- return;
- }
- try {
- dataLoader.destroy();
- } catch (RemoteException ex) {
- return;
- }
- }
-
- @Override
- public void showHealthBlockedUI(int mountId) {
- // TODO(b/136132412): implement this
- }
-
- private static native long nativeStartService();
-
- private static native void nativeSystemReady(long nativeInstance);
-
- private static native void nativeDump(long nativeInstance, int fd);
-}
diff --git a/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java b/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java
index 571f582ced33..1869a46ff9f7 100644
--- a/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java
+++ b/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java
@@ -2480,6 +2480,11 @@ public class InputMethodManagerService extends IInputMethodManager.Stub
void onSessionCreated(IInputMethod method, IInputMethodSession session,
InputChannel channel) {
synchronized (mMethodMap) {
+ if (mUserSwitchHandlerTask != null) {
+ // We have a pending user-switching task so it's better to just ignore this session.
+ channel.dispose();
+ return;
+ }
if (mCurMethod != null && method != null
&& mCurMethod.asBinder() == method.asBinder()) {
if (mCurClient != null) {
diff --git a/services/core/java/com/android/server/integrity/AppIntegrityManagerServiceImpl.java b/services/core/java/com/android/server/integrity/AppIntegrityManagerServiceImpl.java
index f773825a7ff8..6da0de13f623 100644
--- a/services/core/java/com/android/server/integrity/AppIntegrityManagerServiceImpl.java
+++ b/services/core/java/com/android/server/integrity/AppIntegrityManagerServiceImpl.java
@@ -52,7 +52,6 @@ import android.os.Handler;
import android.os.HandlerThread;
import android.os.UserHandle;
import android.provider.Settings;
-import android.security.FileIntegrityManager;
import android.util.Slog;
import android.util.apk.SourceStampVerificationResult;
import android.util.apk.SourceStampVerifier;
@@ -122,7 +121,6 @@ public class AppIntegrityManagerServiceImpl extends IAppIntegrityManager.Stub {
private final PackageManagerInternal mPackageManagerInternal;
private final RuleEvaluationEngine mEvaluationEngine;
private final IntegrityFileManager mIntegrityFileManager;
- private final FileIntegrityManager mFileIntegrityManager;
/** Create an instance of {@link AppIntegrityManagerServiceImpl}. */
public static AppIntegrityManagerServiceImpl create(Context context) {
@@ -134,7 +132,6 @@ public class AppIntegrityManagerServiceImpl extends IAppIntegrityManager.Stub {
LocalServices.getService(PackageManagerInternal.class),
RuleEvaluationEngine.getRuleEvaluationEngine(),
IntegrityFileManager.getInstance(),
- (FileIntegrityManager) context.getSystemService(Context.FILE_INTEGRITY_SERVICE),
handlerThread.getThreadHandler());
}
@@ -144,13 +141,11 @@ public class AppIntegrityManagerServiceImpl extends IAppIntegrityManager.Stub {
PackageManagerInternal packageManagerInternal,
RuleEvaluationEngine evaluationEngine,
IntegrityFileManager integrityFileManager,
- FileIntegrityManager fileIntegrityManager,
Handler handler) {
mContext = context;
mPackageManagerInternal = packageManagerInternal;
mEvaluationEngine = evaluationEngine;
mIntegrityFileManager = integrityFileManager;
- mFileIntegrityManager = fileIntegrityManager;
mHandler = handler;
IntentFilter integrityVerificationFilter = new IntentFilter();
@@ -476,6 +471,8 @@ public class AppIntegrityManagerServiceImpl extends IAppIntegrityManager.Stub {
SourceStampVerifier.verify(installationPath.getAbsolutePath());
appInstallMetadata.setIsStampPresent(sourceStampVerificationResult.isPresent());
appInstallMetadata.setIsStampVerified(sourceStampVerificationResult.isVerified());
+ // A verified stamp is set to be trusted.
+ appInstallMetadata.setIsStampTrusted(sourceStampVerificationResult.isVerified());
if (sourceStampVerificationResult.isVerified()) {
X509Certificate sourceStampCertificate =
(X509Certificate) sourceStampVerificationResult.getCertificate();
@@ -488,16 +485,6 @@ public class AppIntegrityManagerServiceImpl extends IAppIntegrityManager.Stub {
throw new IllegalArgumentException(
"Error computing source stamp certificate digest", e);
}
- // Checks if the source stamp certificate is trusted.
- try {
- appInstallMetadata.setIsStampTrusted(
- mFileIntegrityManager.isApkVeritySupported()
- && mFileIntegrityManager.isAppSourceCertificateTrusted(
- sourceStampCertificate));
- } catch (CertificateEncodingException e) {
- throw new IllegalArgumentException(
- "Error checking if source stamp certificate is trusted", e);
- }
}
}
diff --git a/services/core/java/com/android/server/integrity/TEST_MAPPING b/services/core/java/com/android/server/integrity/TEST_MAPPING
index ca7f396e23e4..495920454fd7 100644
--- a/services/core/java/com/android/server/integrity/TEST_MAPPING
+++ b/services/core/java/com/android/server/integrity/TEST_MAPPING
@@ -7,6 +7,14 @@
"include-filter": "com.android.server.integrity."
}
]
+ },
+ {
+ "name": "GtsSecurityHostTestCases",
+ "options": [
+ {
+ "include-filter": "com.google.android.security.gts.AppIntegrityManagerTest"
+ }
+ ]
}
]
}
diff --git a/services/core/java/com/android/server/locksettings/LockSettingsService.java b/services/core/java/com/android/server/locksettings/LockSettingsService.java
index 6faf67486ff3..c1c37603b9c3 100644
--- a/services/core/java/com/android/server/locksettings/LockSettingsService.java
+++ b/services/core/java/com/android/server/locksettings/LockSettingsService.java
@@ -1572,6 +1572,24 @@ public class LockSettingsService extends ILockSettings.Stub {
"This operation requires secure lock screen feature");
}
checkWritePermission(userId);
+
+ // When changing credential for profiles with unified challenge, some callers
+ // will pass in empty credential while others will pass in the credential of
+ // the parent user. setLockCredentialInternal() handles the formal case (empty
+ // credential) correctly but not the latter. As a stopgap fix, convert the latter
+ // case to the formal. The long-term fix would be fixing LSS such that it should
+ // accept only the parent user credential on its public API interfaces, swap it
+ // with the profile's random credential at that API boundary (i.e. here) and make
+ // sure LSS internally does not special case profile with unififed challenge: b/80170828.
+ if (!savedCredential.isNone() && isManagedProfileWithUnifiedLock(userId)) {
+ // Verify the parent credential again, to make sure we have a fresh enough
+ // auth token such that getDecryptedPasswordForTiedProfile() inside
+ // setLockCredentialInternal() can function correctly.
+ verifyCredential(savedCredential, /* challenge */ 0,
+ mUserManager.getProfileParent(userId).id);
+ savedCredential.zeroize();
+ savedCredential = LockscreenCredential.createNone();
+ }
synchronized (mSeparateChallengeLock) {
if (!setLockCredentialInternal(credential, savedCredential,
userId, /* isLockTiedToParent= */ false)) {
@@ -1627,6 +1645,7 @@ public class LockSettingsService extends ILockSettings.Stub {
// get credential from keystore when managed profile has unified lock
if (savedCredential.isNone()) {
try {
+ //TODO: remove as part of b/80170828
savedCredential = getDecryptedPasswordForTiedProfile(userId);
} catch (FileNotFoundException e) {
Slog.i(TAG, "Child profile key not found");
@@ -2876,6 +2895,7 @@ public class LockSettingsService extends ILockSettings.Stub {
if (savedCredential.isNone() && isManagedProfileWithUnifiedLock(userId)) {
// get credential from keystore when managed profile has unified lock
try {
+ //TODO: remove as part of b/80170828
savedCredential = getDecryptedPasswordForTiedProfile(userId);
} catch (FileNotFoundException e) {
Slog.i(TAG, "Child profile key not found");
diff --git a/services/core/java/com/android/server/media/MediaKeyDispatcher.java b/services/core/java/com/android/server/media/MediaKeyDispatcher.java
index 16b9eb910ec1..e0efd8a75972 100644
--- a/services/core/java/com/android/server/media/MediaKeyDispatcher.java
+++ b/services/core/java/com/android/server/media/MediaKeyDispatcher.java
@@ -18,22 +18,35 @@ package com.android.server.media;
import android.annotation.NonNull;
import android.annotation.Nullable;
+import android.media.session.ISessionManager;
import android.media.session.MediaSession;
+import android.os.Binder;
import android.view.KeyEvent;
/**
* Provides a way to customize behavior for media key events.
+ *
+ * Note: When instantiating this class, {@link MediaSessionService} will only use the constructor
+ * without any parameters.
*/
-public interface MediaKeyDispatcher {
+public abstract class MediaKeyDispatcher {
+ public MediaKeyDispatcher() {
+ // Constructor used for reflection
+ }
+
/**
* Implement this to customize the logic for which MediaSession should consume which key event.
*
* @param keyEvent a non-null KeyEvent whose key code is one of the supported media buttons.
+ * @param uid the uid value retrieved by calling {@link Binder#getCallingUid()} from
+ * {@link ISessionManager#dispatchMediaKeyEvent(String, boolean, KeyEvent, boolean)}
* @param asSystemService {@code true} if the event came from the system service via hardware
* devices. {@code false} if the event came from the app process through key injection.
* @return a {@link MediaSession.Token} instance that should consume the given key event.
*/
@Nullable
- MediaSession.Token getSessionForKeyEvent(@NonNull KeyEvent keyEvent,
- boolean asSystemService);
+ MediaSession.Token getSessionForKeyEvent(@NonNull KeyEvent keyEvent, int uid,
+ boolean asSystemService) {
+ return null;
+ }
}
diff --git a/services/core/java/com/android/server/media/MediaRoute2Provider.java b/services/core/java/com/android/server/media/MediaRoute2Provider.java
index f144405436f9..27216783d0d2 100644
--- a/services/core/java/com/android/server/media/MediaRoute2Provider.java
+++ b/services/core/java/com/android/server/media/MediaRoute2Provider.java
@@ -51,17 +51,17 @@ abstract class MediaRoute2Provider {
mCallback = callback;
}
- public abstract void requestCreateSession(String packageName, String routeId, long requestId,
+ public abstract void requestCreateSession(long requestId, String packageName, String routeId,
@Nullable Bundle sessionHints);
- public abstract void releaseSession(String sessionId, long requestId);
+ public abstract void releaseSession(long requestId, String sessionId);
public abstract void updateDiscoveryPreference(RouteDiscoveryPreference discoveryPreference);
- public abstract void selectRoute(String sessionId, String routeId, long requestId);
- public abstract void deselectRoute(String sessionId, String routeId, long requestId);
- public abstract void transferToRoute(String sessionId, String routeId, long requestId);
+ public abstract void selectRoute(long requestId, String sessionId, String routeId);
+ public abstract void deselectRoute(long requestId, String sessionId, String routeId);
+ public abstract void transferToRoute(long requestId, String sessionId, String routeId);
- public abstract void setRouteVolume(String routeId, int volume, long requestId);
- public abstract void setSessionVolume(String sessionId, int volume, long requestId);
+ public abstract void setRouteVolume(long requestId, String routeId, int volume);
+ public abstract void setSessionVolume(long requestId, String sessionId, int volume);
@NonNull
public String getUniqueId() {
@@ -110,8 +110,7 @@ abstract class MediaRoute2Provider {
public interface Callback {
void onProviderStateChanged(@Nullable MediaRoute2Provider provider);
void onSessionCreated(@NonNull MediaRoute2Provider provider,
- @Nullable RoutingSessionInfo sessionInfo, long requestId);
- void onSessionCreationFailed(@NonNull MediaRoute2Provider provider, long requestId);
+ long requestId, @Nullable RoutingSessionInfo sessionInfo);
void onSessionUpdated(@NonNull MediaRoute2Provider provider,
@NonNull RoutingSessionInfo sessionInfo);
void onSessionReleased(@NonNull MediaRoute2Provider provider,
diff --git a/services/core/java/com/android/server/media/MediaRoute2ProviderServiceProxy.java b/services/core/java/com/android/server/media/MediaRoute2ProviderServiceProxy.java
index e64776cc6e35..b456737e9fc1 100644
--- a/services/core/java/com/android/server/media/MediaRoute2ProviderServiceProxy.java
+++ b/services/core/java/com/android/server/media/MediaRoute2ProviderServiceProxy.java
@@ -78,18 +78,18 @@ final class MediaRoute2ProviderServiceProxy extends MediaRoute2Provider
}
@Override
- public void requestCreateSession(String packageName, String routeId, long requestId,
+ public void requestCreateSession(long requestId, String packageName, String routeId,
Bundle sessionHints) {
if (mConnectionReady) {
- mActiveConnection.requestCreateSession(packageName, routeId, requestId, sessionHints);
+ mActiveConnection.requestCreateSession(requestId, packageName, routeId, sessionHints);
updateBinding();
}
}
@Override
- public void releaseSession(String sessionId, long requestId) {
+ public void releaseSession(long requestId, String sessionId) {
if (mConnectionReady) {
- mActiveConnection.releaseSession(sessionId, requestId);
+ mActiveConnection.releaseSession(requestId, sessionId);
updateBinding();
}
}
@@ -103,38 +103,38 @@ final class MediaRoute2ProviderServiceProxy extends MediaRoute2Provider
}
@Override
- public void selectRoute(String sessionId, String routeId, long requestId) {
+ public void selectRoute(long requestId, String sessionId, String routeId) {
if (mConnectionReady) {
- mActiveConnection.selectRoute(sessionId, routeId, requestId);
+ mActiveConnection.selectRoute(requestId, sessionId, routeId);
}
}
@Override
- public void deselectRoute(String sessionId, String routeId, long requestId) {
+ public void deselectRoute(long requestId, String sessionId, String routeId) {
if (mConnectionReady) {
- mActiveConnection.deselectRoute(sessionId, routeId, requestId);
+ mActiveConnection.deselectRoute(requestId, sessionId, routeId);
}
}
@Override
- public void transferToRoute(String sessionId, String routeId, long requestId) {
+ public void transferToRoute(long requestId, String sessionId, String routeId) {
if (mConnectionReady) {
- mActiveConnection.transferToRoute(sessionId, routeId, requestId);
+ mActiveConnection.transferToRoute(requestId, sessionId, routeId);
}
}
@Override
- public void setRouteVolume(String routeId, int volume, long requestId) {
+ public void setRouteVolume(long requestId, String routeId, int volume) {
if (mConnectionReady) {
- mActiveConnection.setRouteVolume(routeId, volume, requestId);
+ mActiveConnection.setRouteVolume(requestId, routeId, volume);
updateBinding();
}
}
@Override
- public void setSessionVolume(String sessionId, int volume, long requestId) {
+ public void setSessionVolume(long requestId, String sessionId, int volume) {
if (mConnectionReady) {
- mActiveConnection.setSessionVolume(sessionId, volume, requestId);
+ mActiveConnection.setSessionVolume(requestId, sessionId, volume);
updateBinding();
}
}
@@ -294,8 +294,8 @@ final class MediaRoute2ProviderServiceProxy extends MediaRoute2Provider
setAndNotifyProviderState(providerInfo);
}
- private void onSessionCreated(Connection connection, RoutingSessionInfo sessionInfo,
- long requestId) {
+ private void onSessionCreated(Connection connection, long requestId,
+ RoutingSessionInfo sessionInfo) {
if (mActiveConnection != connection) {
return;
}
@@ -325,20 +325,7 @@ final class MediaRoute2ProviderServiceProxy extends MediaRoute2Provider
return;
}
- mCallback.onSessionCreated(this, sessionInfo, requestId);
- }
-
- private void onSessionCreationFailed(Connection connection, long requestId) {
- if (mActiveConnection != connection) {
- return;
- }
-
- if (requestId == MediaRoute2ProviderService.REQUEST_ID_NONE) {
- Slog.w(TAG, "onSessionCreationFailed: Ignoring requestId REQUEST_ID_NONE");
- return;
- }
-
- mCallback.onSessionCreationFailed(this, requestId);
+ mCallback.onSessionCreated(this, requestId, sessionInfo);
}
private void onSessionUpdated(Connection connection, RoutingSessionInfo sessionInfo) {
@@ -465,18 +452,18 @@ final class MediaRoute2ProviderServiceProxy extends MediaRoute2Provider
mCallbackStub.dispose();
}
- public void requestCreateSession(String packageName, String routeId, long requestId,
+ public void requestCreateSession(long requestId, String packageName, String routeId,
Bundle sessionHints) {
try {
- mService.requestCreateSession(packageName, routeId, requestId, sessionHints);
+ mService.requestCreateSession(requestId, packageName, routeId, sessionHints);
} catch (RemoteException ex) {
Slog.e(TAG, "requestCreateSession: Failed to deliver request.");
}
}
- public void releaseSession(String sessionId, long requestId) {
+ public void releaseSession(long requestId, String sessionId) {
try {
- mService.releaseSession(sessionId, requestId);
+ mService.releaseSession(requestId, sessionId);
} catch (RemoteException ex) {
Slog.e(TAG, "releaseSession: Failed to deliver request.");
}
@@ -490,41 +477,41 @@ final class MediaRoute2ProviderServiceProxy extends MediaRoute2Provider
}
}
- public void selectRoute(String sessionId, String routeId, long requestId) {
+ public void selectRoute(long requestId, String sessionId, String routeId) {
try {
- mService.selectRoute(sessionId, routeId, requestId);
+ mService.selectRoute(requestId, sessionId, routeId);
} catch (RemoteException ex) {
Slog.e(TAG, "selectRoute: Failed to deliver request.", ex);
}
}
- public void deselectRoute(String sessionId, String routeId, long requestId) {
+ public void deselectRoute(long requestId, String sessionId, String routeId) {
try {
- mService.deselectRoute(sessionId, routeId, requestId);
+ mService.deselectRoute(requestId, sessionId, routeId);
} catch (RemoteException ex) {
Slog.e(TAG, "deselectRoute: Failed to deliver request.", ex);
}
}
- public void transferToRoute(String sessionId, String routeId, long requestId) {
+ public void transferToRoute(long requestId, String sessionId, String routeId) {
try {
- mService.transferToRoute(sessionId, routeId, requestId);
+ mService.transferToRoute(requestId, sessionId, routeId);
} catch (RemoteException ex) {
Slog.e(TAG, "transferToRoute: Failed to deliver request.", ex);
}
}
- public void setRouteVolume(String routeId, int volume, long requestId) {
+ public void setRouteVolume(long requestId, String routeId, int volume) {
try {
- mService.setRouteVolume(routeId, volume, requestId);
+ mService.setRouteVolume(requestId, routeId, volume);
} catch (RemoteException ex) {
Slog.e(TAG, "setRouteVolume: Failed to deliver request.", ex);
}
}
- public void setSessionVolume(String sessionId, int volume, long requestId) {
+ public void setSessionVolume(long requestId, String sessionId, int volume) {
try {
- mService.setSessionVolume(sessionId, volume, requestId);
+ mService.setSessionVolume(requestId, sessionId, volume);
} catch (RemoteException ex) {
Slog.e(TAG, "setSessionVolume: Failed to deliver request.", ex);
}
@@ -539,12 +526,8 @@ final class MediaRoute2ProviderServiceProxy extends MediaRoute2Provider
mHandler.post(() -> onProviderStateUpdated(Connection.this, providerInfo));
}
- void postSessionCreated(RoutingSessionInfo sessionInfo, long requestId) {
- mHandler.post(() -> onSessionCreated(Connection.this, sessionInfo, requestId));
- }
-
- void postSessionCreationFailed(long requestId) {
- mHandler.post(() -> onSessionCreationFailed(Connection.this, requestId));
+ void postSessionCreated(long requestId, RoutingSessionInfo sessionInfo) {
+ mHandler.post(() -> onSessionCreated(Connection.this, requestId, sessionInfo));
}
void postSessionUpdated(RoutingSessionInfo sessionInfo) {
@@ -555,7 +538,7 @@ final class MediaRoute2ProviderServiceProxy extends MediaRoute2Provider
mHandler.post(() -> onSessionReleased(Connection.this, sessionInfo));
}
- void postSessionReleased(long requestId, int reason) {
+ void postRequestFailed(long requestId, int reason) {
mHandler.post(() -> onRequestFailed(Connection.this, requestId, reason));
}
}
@@ -581,18 +564,10 @@ final class MediaRoute2ProviderServiceProxy extends MediaRoute2Provider
}
@Override
- public void notifySessionCreated(RoutingSessionInfo sessionInfo, long requestId) {
- Connection connection = mConnectionRef.get();
- if (connection != null) {
- connection.postSessionCreated(sessionInfo, requestId);
- }
- }
-
- @Override
- public void notifySessionCreationFailed(long requestId) {
+ public void notifySessionCreated(long requestId, RoutingSessionInfo sessionInfo) {
Connection connection = mConnectionRef.get();
if (connection != null) {
- connection.postSessionCreationFailed(requestId);
+ connection.postSessionCreated(requestId, sessionInfo);
}
}
@@ -616,7 +591,7 @@ final class MediaRoute2ProviderServiceProxy extends MediaRoute2Provider
public void notifyRequestFailed(long requestId, int reason) {
Connection connection = mConnectionRef.get();
if (connection != null) {
- connection.postSessionReleased(requestId, reason);
+ connection.postRequestFailed(requestId, reason);
}
}
}
diff --git a/services/core/java/com/android/server/media/MediaRouter2ServiceImpl.java b/services/core/java/com/android/server/media/MediaRouter2ServiceImpl.java
index e78a35cd88a4..4b925ef7c245 100644
--- a/services/core/java/com/android/server/media/MediaRouter2ServiceImpl.java
+++ b/services/core/java/com/android/server/media/MediaRouter2ServiceImpl.java
@@ -216,15 +216,15 @@ class MediaRouter2ServiceImpl {
}
}
- public void requestCreateSessionWithRouter2(IMediaRouter2 router, MediaRoute2Info route,
- int requestId, Bundle sessionHints) {
+ public void requestCreateSessionWithRouter2(IMediaRouter2 router, int requestId,
+ MediaRoute2Info route, Bundle sessionHints) {
Objects.requireNonNull(router, "router must not be null");
Objects.requireNonNull(route, "route must not be null");
final long token = Binder.clearCallingIdentity();
try {
synchronized (mLock) {
- requestCreateSessionWithRouter2Locked(router, route, requestId, sessionHints);
+ requestCreateSessionWithRouter2Locked(requestId, router, route, sessionHints);
}
} finally {
Binder.restoreCallingIdentity(token);
@@ -370,23 +370,23 @@ class MediaRouter2ServiceImpl {
}
}
- public void setRouteVolumeWithManager(IMediaRouter2Manager manager,
- MediaRoute2Info route, int volume, int requestId) {
+ public void setRouteVolumeWithManager(IMediaRouter2Manager manager, int requestId,
+ MediaRoute2Info route, int volume) {
Objects.requireNonNull(manager, "manager must not be null");
Objects.requireNonNull(route, "route must not be null");
final long token = Binder.clearCallingIdentity();
try {
synchronized (mLock) {
- setRouteVolumeWithManagerLocked(manager, route, volume, requestId);
+ setRouteVolumeWithManagerLocked(requestId, manager, route, volume);
}
} finally {
Binder.restoreCallingIdentity(token);
}
}
- public void requestCreateSessionWithManager(IMediaRouter2Manager manager, String packageName,
- MediaRoute2Info route, int requestId) {
+ public void requestCreateSessionWithManager(IMediaRouter2Manager manager, int requestId,
+ String packageName, MediaRoute2Info route) {
Objects.requireNonNull(manager, "manager must not be null");
if (TextUtils.isEmpty(packageName)) {
throw new IllegalArgumentException("packageName must not be empty");
@@ -395,15 +395,15 @@ class MediaRouter2ServiceImpl {
final long token = Binder.clearCallingIdentity();
try {
synchronized (mLock) {
- requestCreateSessionWithManagerLocked(manager, packageName, route, requestId);
+ requestCreateSessionWithManagerLocked(requestId, manager, packageName, route);
}
} finally {
Binder.restoreCallingIdentity(token);
}
}
- public void selectRouteWithManager(IMediaRouter2Manager manager, String uniqueSessionId,
- MediaRoute2Info route, int requestId) {
+ public void selectRouteWithManager(IMediaRouter2Manager manager, int requestId,
+ String uniqueSessionId, MediaRoute2Info route) {
Objects.requireNonNull(manager, "manager must not be null");
if (TextUtils.isEmpty(uniqueSessionId)) {
throw new IllegalArgumentException("uniqueSessionId must not be empty");
@@ -413,15 +413,15 @@ class MediaRouter2ServiceImpl {
final long token = Binder.clearCallingIdentity();
try {
synchronized (mLock) {
- selectRouteWithManagerLocked(manager, uniqueSessionId, route, requestId);
+ selectRouteWithManagerLocked(requestId, manager, uniqueSessionId, route);
}
} finally {
Binder.restoreCallingIdentity(token);
}
}
- public void deselectRouteWithManager(IMediaRouter2Manager manager, String uniqueSessionId,
- MediaRoute2Info route, int requestId) {
+ public void deselectRouteWithManager(IMediaRouter2Manager manager, int requestId,
+ String uniqueSessionId, MediaRoute2Info route) {
Objects.requireNonNull(manager, "manager must not be null");
if (TextUtils.isEmpty(uniqueSessionId)) {
throw new IllegalArgumentException("uniqueSessionId must not be empty");
@@ -431,15 +431,15 @@ class MediaRouter2ServiceImpl {
final long token = Binder.clearCallingIdentity();
try {
synchronized (mLock) {
- deselectRouteWithManagerLocked(manager, uniqueSessionId, route, requestId);
+ deselectRouteWithManagerLocked(requestId, manager, uniqueSessionId, route);
}
} finally {
Binder.restoreCallingIdentity(token);
}
}
- public void transferToRouteWithManager(IMediaRouter2Manager manager, String uniqueSessionId,
- MediaRoute2Info route, int requestId) {
+ public void transferToRouteWithManager(IMediaRouter2Manager manager, int requestId,
+ String uniqueSessionId, MediaRoute2Info route) {
Objects.requireNonNull(manager, "manager must not be null");
if (TextUtils.isEmpty(uniqueSessionId)) {
throw new IllegalArgumentException("uniqueSessionId must not be empty");
@@ -449,15 +449,15 @@ class MediaRouter2ServiceImpl {
final long token = Binder.clearCallingIdentity();
try {
synchronized (mLock) {
- transferToRouteWithManagerLocked(manager, uniqueSessionId, route, requestId);
+ transferToRouteWithManagerLocked(requestId, manager, uniqueSessionId, route);
}
} finally {
Binder.restoreCallingIdentity(token);
}
}
- public void setSessionVolumeWithManager(IMediaRouter2Manager manager,
- String uniqueSessionId, int volume, int requestId) {
+ public void setSessionVolumeWithManager(IMediaRouter2Manager manager, int requestId,
+ String uniqueSessionId, int volume) {
Objects.requireNonNull(manager, "manager must not be null");
if (TextUtils.isEmpty(uniqueSessionId)) {
throw new IllegalArgumentException("uniqueSessionId must not be empty");
@@ -466,15 +466,15 @@ class MediaRouter2ServiceImpl {
final long token = Binder.clearCallingIdentity();
try {
synchronized (mLock) {
- setSessionVolumeWithManagerLocked(manager, uniqueSessionId, volume, requestId);
+ setSessionVolumeWithManagerLocked(requestId, manager, uniqueSessionId, volume);
}
} finally {
Binder.restoreCallingIdentity(token);
}
}
- public void releaseSessionWithManager(IMediaRouter2Manager manager, String uniqueSessionId,
- int requestId) {
+ public void releaseSessionWithManager(IMediaRouter2Manager manager, int requestId,
+ String uniqueSessionId) {
Objects.requireNonNull(manager, "manager must not be null");
if (TextUtils.isEmpty(uniqueSessionId)) {
throw new IllegalArgumentException("uniqueSessionId must not be empty");
@@ -483,7 +483,7 @@ class MediaRouter2ServiceImpl {
final long token = Binder.clearCallingIdentity();
try {
synchronized (mLock) {
- releaseSessionWithManagerLocked(manager, uniqueSessionId, requestId);
+ releaseSessionWithManagerLocked(requestId, manager, uniqueSessionId);
}
} finally {
Binder.restoreCallingIdentity(token);
@@ -591,12 +591,13 @@ class MediaRouter2ServiceImpl {
if (routerRecord != null) {
routerRecord.mUserRecord.mHandler.sendMessage(
obtainMessage(UserHandler::setRouteVolumeOnHandler,
- routerRecord.mUserRecord.mHandler, route, volume, DUMMY_REQUEST_ID));
+ routerRecord.mUserRecord.mHandler,
+ DUMMY_REQUEST_ID, route, volume));
}
}
- private void requestCreateSessionWithRouter2Locked(@NonNull IMediaRouter2 router,
- @NonNull MediaRoute2Info route, int requestId, @Nullable Bundle sessionHints) {
+ private void requestCreateSessionWithRouter2Locked(int requestId, @NonNull IMediaRouter2 router,
+ @NonNull MediaRoute2Info route, @Nullable Bundle sessionHints) {
final IBinder binder = router.asBinder();
final RouterRecord routerRecord = mAllRouterRecords.get(binder);
@@ -608,7 +609,8 @@ class MediaRouter2ServiceImpl {
routerRecord.mUserRecord.mHandler.sendMessage(
obtainMessage(UserHandler::requestCreateSessionOnHandler,
routerRecord.mUserRecord.mHandler,
- routerRecord, route, uniqueRequestId, sessionHints));
+ uniqueRequestId, routerRecord, /* managerRecord= */ null, route,
+ sessionHints));
}
private void selectRouteWithRouter2Locked(@NonNull IMediaRouter2 router,
@@ -622,8 +624,8 @@ class MediaRouter2ServiceImpl {
routerRecord.mUserRecord.mHandler.sendMessage(
obtainMessage(UserHandler::selectRouteOnHandler,
- routerRecord.mUserRecord.mHandler, routerRecord, uniqueSessionId, route,
- DUMMY_REQUEST_ID));
+ routerRecord.mUserRecord.mHandler,
+ DUMMY_REQUEST_ID, routerRecord, uniqueSessionId, route));
}
private void deselectRouteWithRouter2Locked(@NonNull IMediaRouter2 router,
@@ -637,8 +639,8 @@ class MediaRouter2ServiceImpl {
routerRecord.mUserRecord.mHandler.sendMessage(
obtainMessage(UserHandler::deselectRouteOnHandler,
- routerRecord.mUserRecord.mHandler, routerRecord, uniqueSessionId, route,
- DUMMY_REQUEST_ID));
+ routerRecord.mUserRecord.mHandler,
+ DUMMY_REQUEST_ID, routerRecord, uniqueSessionId, route));
}
private void transferToRouteWithRouter2Locked(@NonNull IMediaRouter2 router,
@@ -652,8 +654,8 @@ class MediaRouter2ServiceImpl {
routerRecord.mUserRecord.mHandler.sendMessage(
obtainMessage(UserHandler::transferToRouteOnHandler,
- routerRecord.mUserRecord.mHandler, routerRecord, uniqueSessionId, route,
- DUMMY_REQUEST_ID));
+ routerRecord.mUserRecord.mHandler,
+ DUMMY_REQUEST_ID, routerRecord, uniqueSessionId, route));
}
private void setSessionVolumeWithRouter2Locked(@NonNull IMediaRouter2 router,
@@ -667,8 +669,8 @@ class MediaRouter2ServiceImpl {
routerRecord.mUserRecord.mHandler.sendMessage(
obtainMessage(UserHandler::setSessionVolumeOnHandler,
- routerRecord.mUserRecord.mHandler, uniqueSessionId, volume,
- DUMMY_REQUEST_ID));
+ routerRecord.mUserRecord.mHandler,
+ DUMMY_REQUEST_ID, uniqueSessionId, volume));
}
private void releaseSessionWithRouter2Locked(@NonNull IMediaRouter2 router,
@@ -682,8 +684,8 @@ class MediaRouter2ServiceImpl {
routerRecord.mUserRecord.mHandler.sendMessage(
obtainMessage(UserHandler::releaseSessionOnHandler,
- routerRecord.mUserRecord.mHandler, routerRecord, uniqueSessionId,
- DUMMY_REQUEST_ID));
+ routerRecord.mUserRecord.mHandler,
+ DUMMY_REQUEST_ID, routerRecord, uniqueSessionId));
}
////////////////////////////////////////////////////////////
@@ -755,8 +757,9 @@ class MediaRouter2ServiceImpl {
disposeUserIfNeededLocked(userRecord); // since manager removed from user
}
- private void setRouteVolumeWithManagerLocked(@NonNull IMediaRouter2Manager manager,
- @NonNull MediaRoute2Info route, int volume, int requestId) {
+ private void setRouteVolumeWithManagerLocked(int requestId,
+ @NonNull IMediaRouter2Manager manager,
+ @NonNull MediaRoute2Info route, int volume) {
final IBinder binder = manager.asBinder();
ManagerRecord managerRecord = mAllManagerRecords.get(binder);
@@ -767,11 +770,13 @@ class MediaRouter2ServiceImpl {
long uniqueRequestId = toUniqueRequestId(managerRecord.mManagerId, requestId);
managerRecord.mUserRecord.mHandler.sendMessage(
obtainMessage(UserHandler::setRouteVolumeOnHandler,
- managerRecord.mUserRecord.mHandler, route, volume, uniqueRequestId));
+ managerRecord.mUserRecord.mHandler,
+ uniqueRequestId, route, volume));
}
- private void requestCreateSessionWithManagerLocked(@NonNull IMediaRouter2Manager manager,
- @NonNull String packageName, @NonNull MediaRoute2Info route, int requestId) {
+ private void requestCreateSessionWithManagerLocked(int requestId,
+ @NonNull IMediaRouter2Manager manager,
+ @NonNull String packageName, @NonNull MediaRoute2Info route) {
ManagerRecord managerRecord = mAllManagerRecords.get(manager.asBinder());
if (managerRecord == null || !managerRecord.mTrusted) {
return;
@@ -788,11 +793,12 @@ class MediaRouter2ServiceImpl {
routerRecord.mUserRecord.mHandler.sendMessage(
obtainMessage(UserHandler::requestCreateSessionOnHandler,
routerRecord.mUserRecord.mHandler,
- routerRecord, route, uniqueRequestId, null /* sessionHints */));
+ uniqueRequestId, routerRecord, managerRecord, route,
+ /* sessionHints= */ null));
}
- private void selectRouteWithManagerLocked(@NonNull IMediaRouter2Manager manager,
- @NonNull String uniqueSessionId, @NonNull MediaRoute2Info route, int requestId) {
+ private void selectRouteWithManagerLocked(int requestId, @NonNull IMediaRouter2Manager manager,
+ @NonNull String uniqueSessionId, @NonNull MediaRoute2Info route) {
final IBinder binder = manager.asBinder();
ManagerRecord managerRecord = mAllManagerRecords.get(binder);
@@ -807,12 +813,13 @@ class MediaRouter2ServiceImpl {
long uniqueRequestId = toUniqueRequestId(managerRecord.mManagerId, requestId);
managerRecord.mUserRecord.mHandler.sendMessage(
obtainMessage(UserHandler::selectRouteOnHandler,
- managerRecord.mUserRecord.mHandler, routerRecord, uniqueSessionId, route,
- uniqueRequestId));
+ managerRecord.mUserRecord.mHandler,
+ uniqueRequestId, routerRecord, uniqueSessionId, route));
}
- private void deselectRouteWithManagerLocked(@NonNull IMediaRouter2Manager manager,
- @NonNull String uniqueSessionId, @NonNull MediaRoute2Info route, int requestId) {
+ private void deselectRouteWithManagerLocked(int requestId,
+ @NonNull IMediaRouter2Manager manager,
+ @NonNull String uniqueSessionId, @NonNull MediaRoute2Info route) {
final IBinder binder = manager.asBinder();
ManagerRecord managerRecord = mAllManagerRecords.get(binder);
@@ -827,12 +834,13 @@ class MediaRouter2ServiceImpl {
long uniqueRequestId = toUniqueRequestId(managerRecord.mManagerId, requestId);
managerRecord.mUserRecord.mHandler.sendMessage(
obtainMessage(UserHandler::deselectRouteOnHandler,
- managerRecord.mUserRecord.mHandler, routerRecord, uniqueSessionId, route,
- uniqueRequestId));
+ managerRecord.mUserRecord.mHandler,
+ uniqueRequestId, routerRecord, uniqueSessionId, route));
}
- private void transferToRouteWithManagerLocked(@NonNull IMediaRouter2Manager manager,
- @NonNull String uniqueSessionId, @NonNull MediaRoute2Info route, int requestId) {
+ private void transferToRouteWithManagerLocked(int requestId,
+ @NonNull IMediaRouter2Manager manager,
+ @NonNull String uniqueSessionId, @NonNull MediaRoute2Info route) {
final IBinder binder = manager.asBinder();
ManagerRecord managerRecord = mAllManagerRecords.get(binder);
@@ -847,12 +855,13 @@ class MediaRouter2ServiceImpl {
long uniqueRequestId = toUniqueRequestId(managerRecord.mManagerId, requestId);
managerRecord.mUserRecord.mHandler.sendMessage(
obtainMessage(UserHandler::transferToRouteOnHandler,
- managerRecord.mUserRecord.mHandler, routerRecord, uniqueSessionId, route,
- uniqueRequestId));
+ managerRecord.mUserRecord.mHandler,
+ uniqueRequestId, routerRecord, uniqueSessionId, route));
}
- private void setSessionVolumeWithManagerLocked(@NonNull IMediaRouter2Manager manager,
- @NonNull String uniqueSessionId, int volume, int requestId) {
+ private void setSessionVolumeWithManagerLocked(int requestId,
+ @NonNull IMediaRouter2Manager manager,
+ @NonNull String uniqueSessionId, int volume) {
final IBinder binder = manager.asBinder();
ManagerRecord managerRecord = mAllManagerRecords.get(binder);
@@ -863,12 +872,13 @@ class MediaRouter2ServiceImpl {
long uniqueRequestId = toUniqueRequestId(managerRecord.mManagerId, requestId);
managerRecord.mUserRecord.mHandler.sendMessage(
obtainMessage(UserHandler::setSessionVolumeOnHandler,
- managerRecord.mUserRecord.mHandler, uniqueSessionId, volume,
- uniqueRequestId));
+ managerRecord.mUserRecord.mHandler,
+ uniqueRequestId, uniqueSessionId, volume));
}
- private void releaseSessionWithManagerLocked(@NonNull IMediaRouter2Manager manager,
- @NonNull String uniqueSessionId, int requestId) {
+ private void releaseSessionWithManagerLocked(int requestId,
+ @NonNull IMediaRouter2Manager manager,
+ @NonNull String uniqueSessionId) {
final IBinder binder = manager.asBinder();
ManagerRecord managerRecord = mAllManagerRecords.get(binder);
@@ -885,8 +895,8 @@ class MediaRouter2ServiceImpl {
long uniqueRequestId = toUniqueRequestId(managerRecord.mManagerId, requestId);
managerRecord.mUserRecord.mHandler.sendMessage(
obtainMessage(UserHandler::releaseSessionOnHandler,
- managerRecord.mUserRecord.mHandler, routerRecord, uniqueSessionId,
- uniqueRequestId));
+ managerRecord.mUserRecord.mHandler,
+ uniqueRequestId, routerRecord, uniqueSessionId));
}
////////////////////////////////////////////////////////////
@@ -923,11 +933,11 @@ class MediaRouter2ServiceImpl {
}
}
- static long toUniqueRequestId(int routerOrManagerId, int originalRequestId) {
- return ((long) routerOrManagerId << 32) | originalRequestId;
+ static long toUniqueRequestId(int requesterId, int originalRequestId) {
+ return ((long) requesterId << 32) | originalRequestId;
}
- static int toRouterOrManagerId(long uniqueRequestId) {
+ static int toRequesterId(long uniqueRequestId) {
return (int) (uniqueRequestId >> 32);
}
@@ -1102,16 +1112,11 @@ class MediaRouter2ServiceImpl {
@Override
public void onSessionCreated(@NonNull MediaRoute2Provider provider,
- @NonNull RoutingSessionInfo sessionInfo, long requestId) {
+ long requestId, @NonNull RoutingSessionInfo sessionInfo) {
sendMessage(PooledLambda.obtainMessage(UserHandler::onSessionCreatedOnHandler,
- this, provider, sessionInfo, requestId));
+ this, provider, requestId, sessionInfo));
}
- @Override
- public void onSessionCreationFailed(@NonNull MediaRoute2Provider provider, long requestId) {
- sendMessage(PooledLambda.obtainMessage(UserHandler::onSessionCreationFailedOnHandler,
- this, provider, requestId));
- }
@Override
public void onSessionUpdated(@NonNull MediaRoute2Provider provider,
@@ -1222,8 +1227,9 @@ class MediaRouter2ServiceImpl {
return -1;
}
- private void requestCreateSessionOnHandler(@NonNull RouterRecord routerRecord,
- @NonNull MediaRoute2Info route, long requestId, @Nullable Bundle sessionHints) {
+ private void requestCreateSessionOnHandler(long requestId,
+ @NonNull RouterRecord routerRecord, @Nullable ManagerRecord managerRecord,
+ @NonNull MediaRoute2Info route, @Nullable Bundle sessionHints) {
final MediaRoute2Provider provider = findProvider(route.getProviderId());
if (provider == null) {
@@ -1233,18 +1239,17 @@ class MediaRouter2ServiceImpl {
return;
}
- // TODO: Apply timeout for each request (How many seconds should we wait?)
SessionCreationRequest request =
- new SessionCreationRequest(routerRecord, route, requestId);
+ new SessionCreationRequest(routerRecord, requestId, route, managerRecord);
mSessionCreationRequests.add(request);
- provider.requestCreateSession(routerRecord.mPackageName, route.getOriginalId(),
- requestId, sessionHints);
+ provider.requestCreateSession(requestId, routerRecord.mPackageName,
+ route.getOriginalId(), sessionHints);
}
// routerRecord can be null if the session is system's.
- private void selectRouteOnHandler(@Nullable RouterRecord routerRecord,
- @NonNull String uniqueSessionId, @NonNull MediaRoute2Info route, long requestId) {
+ private void selectRouteOnHandler(long requestId, @Nullable RouterRecord routerRecord,
+ @NonNull String uniqueSessionId, @NonNull MediaRoute2Info route) {
if (!checkArgumentsForSessionControl(routerRecord, uniqueSessionId, route,
"selecting")) {
return;
@@ -1256,12 +1261,12 @@ class MediaRouter2ServiceImpl {
if (provider == null) {
return;
}
- provider.selectRoute(getOriginalId(uniqueSessionId), route.getOriginalId(), requestId);
+ provider.selectRoute(requestId, getOriginalId(uniqueSessionId), route.getOriginalId());
}
// routerRecord can be null if the session is system's.
- private void deselectRouteOnHandler(@Nullable RouterRecord routerRecord,
- @NonNull String uniqueSessionId, @NonNull MediaRoute2Info route, long requestId) {
+ private void deselectRouteOnHandler(long requestId, @Nullable RouterRecord routerRecord,
+ @NonNull String uniqueSessionId, @NonNull MediaRoute2Info route) {
if (!checkArgumentsForSessionControl(routerRecord, uniqueSessionId, route,
"deselecting")) {
return;
@@ -1273,13 +1278,14 @@ class MediaRouter2ServiceImpl {
if (provider == null) {
return;
}
- provider.deselectRoute(getOriginalId(uniqueSessionId), route.getOriginalId(),
- requestId);
+
+ provider.deselectRoute(requestId, getOriginalId(uniqueSessionId),
+ route.getOriginalId());
}
// routerRecord can be null if the session is system's.
- private void transferToRouteOnHandler(@Nullable RouterRecord routerRecord,
- @NonNull String uniqueSessionId, @NonNull MediaRoute2Info route, long requestId) {
+ private void transferToRouteOnHandler(long requestId, @Nullable RouterRecord routerRecord,
+ @NonNull String uniqueSessionId, @NonNull MediaRoute2Info route) {
if (!checkArgumentsForSessionControl(routerRecord, uniqueSessionId, route,
"transferring to")) {
return;
@@ -1291,8 +1297,8 @@ class MediaRouter2ServiceImpl {
if (provider == null) {
return;
}
- provider.transferToRoute(getOriginalId(uniqueSessionId), route.getOriginalId(),
- requestId);
+ provider.transferToRoute(requestId, getOriginalId(uniqueSessionId),
+ route.getOriginalId());
}
private boolean checkArgumentsForSessionControl(@Nullable RouterRecord routerRecord,
@@ -1334,8 +1340,29 @@ class MediaRouter2ServiceImpl {
return true;
}
- private void releaseSessionOnHandler(@NonNull RouterRecord routerRecord,
- @NonNull String uniqueSessionId, long uniqueRequestId) {
+ private void setRouteVolumeOnHandler(long requestId, @NonNull MediaRoute2Info route,
+ int volume) {
+ final MediaRoute2Provider provider = findProvider(route.getProviderId());
+ if (provider == null) {
+ Slog.w(TAG, "setRouteVolume: couldn't find provider for route=" + route);
+ return;
+ }
+ provider.setRouteVolume(requestId, route.getOriginalId(), volume);
+ }
+
+ private void setSessionVolumeOnHandler(long requestId, @NonNull String uniqueSessionId,
+ int volume) {
+ final MediaRoute2Provider provider = findProvider(getProviderId(uniqueSessionId));
+ if (provider == null) {
+ Slog.w(TAG, "setSessionVolume: couldn't find provider for session "
+ + "id=" + uniqueSessionId);
+ return;
+ }
+ provider.setSessionVolume(requestId, getOriginalId(uniqueSessionId), volume);
+ }
+
+ private void releaseSessionOnHandler(long uniqueRequestId,
+ @NonNull RouterRecord routerRecord, @NonNull String uniqueSessionId) {
final RouterRecord matchingRecord = mSessionToRouterMap.get(uniqueSessionId);
if (matchingRecord != routerRecord) {
Slog.w(TAG, "Ignoring releasing session from non-matching router."
@@ -1365,11 +1392,11 @@ class MediaRouter2ServiceImpl {
return;
}
- provider.releaseSession(sessionId, uniqueRequestId);
+ provider.releaseSession(uniqueRequestId, sessionId);
}
private void onSessionCreatedOnHandler(@NonNull MediaRoute2Provider provider,
- @NonNull RoutingSessionInfo sessionInfo, long requestId) {
+ long requestId, @NonNull RoutingSessionInfo sessionInfo) {
notifySessionCreatedToManagers(getManagers(), sessionInfo);
if (requestId == REQUEST_ID_NONE) {
@@ -1417,34 +1444,10 @@ class MediaRouter2ServiceImpl {
// Succeeded
notifySessionCreatedToRouter(matchingRequest.mRouterRecord,
- sessionInfo, toOriginalRequestId(requestId));
+ toOriginalRequestId(requestId), sessionInfo);
mSessionToRouterMap.put(sessionInfo.getId(), routerRecord);
}
- private void onSessionCreationFailedOnHandler(@NonNull MediaRoute2Provider provider,
- long requestId) {
- SessionCreationRequest matchingRequest = null;
-
- for (SessionCreationRequest request : mSessionCreationRequests) {
- if (request.mRequestId == requestId
- && TextUtils.equals(
- request.mRoute.getProviderId(), provider.getUniqueId())) {
- matchingRequest = request;
- break;
- }
- }
-
- if (matchingRequest == null) {
- Slog.w(TAG, "Ignoring session creation failed result for unknown request. "
- + "requestId=" + requestId);
- return;
- }
-
- mSessionCreationRequests.remove(matchingRequest);
- notifySessionCreationFailedToRouter(matchingRequest.mRouterRecord,
- toOriginalRequestId(requestId));
- }
-
private void onSessionInfoChangedOnHandler(@NonNull MediaRoute2Provider provider,
@NonNull RoutingSessionInfo sessionInfo) {
List<IMediaRouter2Manager> managers = getManagers();
@@ -1483,36 +1486,62 @@ class MediaRouter2ServiceImpl {
private void onRequestFailedOnHandler(@NonNull MediaRoute2Provider provider,
long requestId, int reason) {
- final int managerId = toRouterOrManagerId(requestId);
-
- MediaRouter2ServiceImpl service = mServiceRef.get();
- if (service == null) {
+ if (handleSessionCreationRequestFailed(provider, requestId, reason)) {
return;
}
- ManagerRecord managerToNotifyFailure = null;
- synchronized (service.mLock) {
- for (ManagerRecord manager : mUserRecord.mManagerRecords) {
- if (manager.mManagerId == managerId) {
- managerToNotifyFailure = manager;
- break;
- }
+ final int requesterId = toRequesterId(requestId);
+ for (ManagerRecord manager : getManagerRecords()) {
+ if (manager.mManagerId == requesterId) {
+ notifyRequestFailedToManager(
+ manager.mManager, toOriginalRequestId(requestId), reason);
+ return;
}
}
- if (managerToNotifyFailure == null) {
- Slog.w(TAG, "No matching managerRecord found for managerId=" + managerId);
- return;
+ // Currently, only the manager can get notified of failures.
+ // TODO: Notify router too when the related callback is introduced.
+ }
+
+ // TODO: Find a way to prevent providers from notifying error on random requestId.
+ // Solutions can be:
+ // 1) Record the other type of requests too (not only session creation request)
+ // 2) Throw exception on providers when they try to notify error on random requestId.
+ private boolean handleSessionCreationRequestFailed(@NonNull MediaRoute2Provider provider,
+ long requestId, int reason) {
+ // Check whether the failure is about creating a session
+ SessionCreationRequest matchingRequest = null;
+ for (SessionCreationRequest request : mSessionCreationRequests) {
+ if (request.mRequestId == requestId && TextUtils.equals(
+ request.mRoute.getProviderId(), provider.getUniqueId())) {
+ matchingRequest = request;
+ break;
+ }
+ }
+
+ if (matchingRequest == null) {
+ // The failure is not about creating a session.
+ return false;
}
- notifyRequestFailedToManager(
- managerToNotifyFailure.mManager, toOriginalRequestId(requestId), reason);
+ mSessionCreationRequests.remove(matchingRequest);
+
+ // Notify the requester about the failure.
+ // The call should be made by either MediaRouter2 or MediaRouter2Manager.
+ if (matchingRequest.mRequestedManagerRecord == null) {
+ notifySessionCreationFailedToRouter(
+ matchingRequest.mRouterRecord, toOriginalRequestId(requestId));
+ } else {
+ notifyRequestFailedToManager(matchingRequest.mRequestedManagerRecord.mManager,
+ toOriginalRequestId(requestId), reason);
+ }
+ return true;
}
private void notifySessionCreatedToRouter(@NonNull RouterRecord routerRecord,
- @NonNull RoutingSessionInfo sessionInfo, int requestId) {
+ int requestId, @NonNull RoutingSessionInfo sessionInfo) {
try {
- routerRecord.mRouter.notifySessionCreated(sessionInfo, requestId);
+ routerRecord.mRouter.notifySessionCreated(requestId, sessionInfo);
} catch (RemoteException ex) {
Slog.w(TAG, "Failed to notify router of the session creation."
+ " Router probably died.", ex);
@@ -1522,7 +1551,7 @@ class MediaRouter2ServiceImpl {
private void notifySessionCreationFailedToRouter(@NonNull RouterRecord routerRecord,
int requestId) {
try {
- routerRecord.mRouter.notifySessionCreated(/* sessionInfo= */ null, requestId);
+ routerRecord.mRouter.notifySessionCreated(requestId, /* sessionInfo= */ null);
} catch (RemoteException ex) {
Slog.w(TAG, "Failed to notify router of the session creation failure."
+ " Router probably died.", ex);
@@ -1549,25 +1578,6 @@ class MediaRouter2ServiceImpl {
}
}
- private void setRouteVolumeOnHandler(@NonNull MediaRoute2Info route, int volume,
- long requestId) {
- final MediaRoute2Provider provider = findProvider(route.getProviderId());
- if (provider != null) {
- provider.setRouteVolume(route.getOriginalId(), volume, requestId);
- }
- }
-
- private void setSessionVolumeOnHandler(@NonNull String uniqueSessionId, int volume,
- long requestId) {
- final MediaRoute2Provider provider = findProvider(getProviderId(uniqueSessionId));
- if (provider == null) {
- Slog.w(TAG, "setSessionVolume: couldn't find provider for session "
- + "id=" + uniqueSessionId);
- return;
- }
- provider.setSessionVolume(getOriginalId(uniqueSessionId), volume, requestId);
- }
-
private List<IMediaRouter2> getRouters() {
final List<IMediaRouter2> routers = new ArrayList<>();
MediaRouter2ServiceImpl service = mServiceRef.get();
@@ -1596,6 +1606,16 @@ class MediaRouter2ServiceImpl {
return managers;
}
+ private List<ManagerRecord> getManagerRecords() {
+ MediaRouter2ServiceImpl service = mServiceRef.get();
+ if (service == null) {
+ return Collections.emptyList();
+ }
+ synchronized (service.mLock) {
+ return new ArrayList<>(mUserRecord.mManagerRecords);
+ }
+ }
+
private void notifyRoutesToRouter(@NonNull IMediaRouter2 router) {
List<MediaRoute2Info> routes = new ArrayList<>();
for (MediaRoute2ProviderInfo providerInfo : mLastProviderInfos) {
@@ -1789,14 +1809,18 @@ class MediaRouter2ServiceImpl {
final class SessionCreationRequest {
public final RouterRecord mRouterRecord;
- public final MediaRoute2Info mRoute;
public final long mRequestId;
+ public final MediaRoute2Info mRoute;
+ public final ManagerRecord mRequestedManagerRecord;
- SessionCreationRequest(@NonNull RouterRecord routerRecord,
- @NonNull MediaRoute2Info route, long requestId) {
+ // requestedManagerRecord is not null only when the request is made by manager.
+ SessionCreationRequest(@NonNull RouterRecord routerRecord, long requestId,
+ @NonNull MediaRoute2Info route,
+ @Nullable ManagerRecord requestedManagerRecord) {
mRouterRecord = routerRecord;
- mRoute = route;
mRequestId = requestId;
+ mRoute = route;
+ mRequestedManagerRecord = requestedManagerRecord;
}
}
}
diff --git a/services/core/java/com/android/server/media/MediaRouterService.java b/services/core/java/com/android/server/media/MediaRouterService.java
index a13ee1058a26..d6bf9fb4d9b5 100644
--- a/services/core/java/com/android/server/media/MediaRouterService.java
+++ b/services/core/java/com/android/server/media/MediaRouterService.java
@@ -480,9 +480,9 @@ public final class MediaRouterService extends IMediaRouterService.Stub
// Binder call
@Override
- public void requestCreateSessionWithRouter2(IMediaRouter2 router, MediaRoute2Info route,
- int requestId, Bundle sessionHints) {
- mService2.requestCreateSessionWithRouter2(router, route, requestId, sessionHints);
+ public void requestCreateSessionWithRouter2(IMediaRouter2 router, int requestId,
+ MediaRoute2Info route, Bundle sessionHints) {
+ mService2.requestCreateSessionWithRouter2(router, requestId, route, sessionHints);
}
// Binder call
@@ -542,51 +542,51 @@ public final class MediaRouterService extends IMediaRouterService.Stub
// Binder call
@Override
- public void setRouteVolumeWithManager(IMediaRouter2Manager manager,
- MediaRoute2Info route, int volume, int requestId) {
- mService2.setRouteVolumeWithManager(manager, route, volume, requestId);
+ public void setRouteVolumeWithManager(IMediaRouter2Manager manager, int requestId,
+ MediaRoute2Info route, int volume) {
+ mService2.setRouteVolumeWithManager(manager, requestId, route, volume);
}
// Binder call
@Override
- public void requestCreateSessionWithManager(IMediaRouter2Manager manager, String packageName,
- MediaRoute2Info route, int requestId) {
- mService2.requestCreateSessionWithManager(manager, packageName, route, requestId);
+ public void requestCreateSessionWithManager(IMediaRouter2Manager manager,
+ int requestId, String packageName, MediaRoute2Info route) {
+ mService2.requestCreateSessionWithManager(manager, requestId, packageName, route);
}
// Binder call
@Override
- public void selectRouteWithManager(IMediaRouter2Manager manager, String sessionId,
- MediaRoute2Info route, int requestId) {
- mService2.selectRouteWithManager(manager, sessionId, route, requestId);
+ public void selectRouteWithManager(IMediaRouter2Manager manager, int requestId,
+ String sessionId, MediaRoute2Info route) {
+ mService2.selectRouteWithManager(manager, requestId, sessionId, route);
}
// Binder call
@Override
- public void deselectRouteWithManager(IMediaRouter2Manager manager, String sessionId,
- MediaRoute2Info route, int requestId) {
- mService2.deselectRouteWithManager(manager, sessionId, route, requestId);
+ public void deselectRouteWithManager(IMediaRouter2Manager manager, int requestId,
+ String sessionId, MediaRoute2Info route) {
+ mService2.deselectRouteWithManager(manager, requestId, sessionId, route);
}
// Binder call
@Override
- public void transferToRouteWithManager(IMediaRouter2Manager manager, String sessionId,
- MediaRoute2Info route, int requestId) {
- mService2.transferToRouteWithManager(manager, sessionId, route, requestId);
+ public void transferToRouteWithManager(IMediaRouter2Manager manager, int requestId,
+ String sessionId, MediaRoute2Info route) {
+ mService2.transferToRouteWithManager(manager, requestId, sessionId, route);
}
// Binder call
@Override
- public void setSessionVolumeWithManager(IMediaRouter2Manager manager,
- String sessionId, int volume, int requestId) {
- mService2.setSessionVolumeWithManager(manager, sessionId, volume, requestId);
+ public void setSessionVolumeWithManager(IMediaRouter2Manager manager, int requestId,
+ String sessionId, int volume) {
+ mService2.setSessionVolumeWithManager(manager, requestId, sessionId, volume);
}
// Binder call
@Override
- public void releaseSessionWithManager(IMediaRouter2Manager manager, String sessionId,
- int requestId) {
- mService2.releaseSessionWithManager(manager, sessionId, requestId);
+ public void releaseSessionWithManager(IMediaRouter2Manager manager, int requestId,
+ String sessionId) {
+ mService2.releaseSessionWithManager(manager, requestId, sessionId);
}
void restoreBluetoothA2dp() {
diff --git a/services/core/java/com/android/server/media/MediaSession2Record.java b/services/core/java/com/android/server/media/MediaSession2Record.java
index 11b7a8a23e14..7f1d035f0739 100644
--- a/services/core/java/com/android/server/media/MediaSession2Record.java
+++ b/services/core/java/com/android/server/media/MediaSession2Record.java
@@ -142,7 +142,6 @@ public class MediaSession2Record implements MediaSessionRecordImpl {
return false;
}
-
@Override
public int getSessionPolicies() {
synchronized (mLock) {
diff --git a/services/core/java/com/android/server/media/MediaSessionService.java b/services/core/java/com/android/server/media/MediaSessionService.java
index 7ffac062b7f5..a6930dd30337 100644
--- a/services/core/java/com/android/server/media/MediaSessionService.java
+++ b/services/core/java/com/android/server/media/MediaSessionService.java
@@ -74,6 +74,7 @@ import android.util.SparseIntArray;
import android.view.KeyEvent;
import android.view.ViewConfiguration;
+import com.android.internal.R;
import com.android.internal.annotations.GuardedBy;
import com.android.internal.util.DumpUtils;
import com.android.server.LocalServices;
@@ -83,6 +84,9 @@ import com.android.server.Watchdog.Monitor;
import java.io.FileDescriptor;
import java.io.PrintWriter;
+import java.lang.reflect.Constructor;
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
@@ -138,6 +142,8 @@ public class MediaSessionService extends SystemService implements Monitor {
private SessionPolicyProvider mCustomSessionPolicyProvider;
private MediaKeyDispatcher mCustomMediaKeyDispatcher;
+ private Method mGetSessionForKeyEventMethod;
+ private Method mGetSessionPoliciesMethod;
public MediaSessionService(Context context) {
super(context);
@@ -178,8 +184,8 @@ public class MediaSessionService extends SystemService implements Monitor {
mHasFeatureLeanback = mContext.getPackageManager().hasSystemFeature(
PackageManager.FEATURE_LEANBACK);
- // TODO: (jinpark) check if config value for custom MediaKeyDispatcher and
- // SessionPolicyProvider have been overlayed and instantiate using reflection.
+ instantiateCustomProvider(null);
+ instantiateCustomDispatcher(null);
updateUser();
}
@@ -561,9 +567,18 @@ public class MediaSessionService extends SystemService implements Monitor {
* 4. It needs to be added to the relevant user record.
*/
private MediaSessionRecord createSessionInternal(int callerPid, int callerUid, int userId,
- String callerPackageName, ISessionCallback cb, String tag, Bundle sessionInfo,
- int policies) {
+ String callerPackageName, ISessionCallback cb, String tag, Bundle sessionInfo) {
synchronized (mLock) {
+ int policies = 0;
+ if (mCustomSessionPolicyProvider != null && mGetSessionPoliciesMethod != null) {
+ try {
+ policies = (int) mGetSessionPoliciesMethod.invoke(
+ mCustomSessionPolicyProvider, callerUid, callerPackageName);
+ } catch (InvocationTargetException | IllegalAccessException e) {
+ Log.w(TAG, "Encountered problem while using reflection", e);
+ }
+ }
+
FullUserRecord user = getFullUserRecordLocked(userId);
if (user == null) {
Log.w(TAG, "Request from invalid user: " + userId + ", pkg=" + callerPackageName);
@@ -746,6 +761,48 @@ public class MediaSessionService extends SystemService implements Monitor {
return null;
}
+ private void instantiateCustomDispatcher(String nameFromTesting) {
+ mCustomMediaKeyDispatcher = null;
+ mGetSessionForKeyEventMethod = null;
+
+ String customDispatcherClassName = (nameFromTesting == null)
+ ? mContext.getResources().getString(R.string.config_customMediaKeyDispatcher)
+ : nameFromTesting;
+ try {
+ if (!TextUtils.isEmpty(customDispatcherClassName)) {
+ Class customDispatcherClass = Class.forName(customDispatcherClassName);
+ Constructor constructor = customDispatcherClass.getDeclaredConstructor();
+ mCustomMediaKeyDispatcher = (MediaKeyDispatcher) constructor.newInstance();
+ mGetSessionForKeyEventMethod = customDispatcherClass.getDeclaredMethod(
+ "getSessionForKeyEvent", KeyEvent.class, int.class, boolean.class);
+ }
+ } catch (ClassNotFoundException | InstantiationException | InvocationTargetException
+ | IllegalAccessException | NoSuchMethodException e) {
+ Log.w(TAG, "Encountered problem while using reflection", e);
+ }
+ }
+
+ private void instantiateCustomProvider(String nameFromTesting) {
+ mCustomSessionPolicyProvider = null;
+ mGetSessionPoliciesMethod = null;
+
+ String customProviderClassName = (nameFromTesting == null)
+ ? mContext.getResources().getString(R.string.config_customSessionPolicyProvider)
+ : nameFromTesting;
+ try {
+ if (!TextUtils.isEmpty(customProviderClassName)) {
+ Class customProviderClass = Class.forName(customProviderClassName);
+ Constructor constructor = customProviderClass.getDeclaredConstructor();
+ mCustomSessionPolicyProvider = (SessionPolicyProvider) constructor.newInstance();
+ mGetSessionPoliciesMethod = customProviderClass.getDeclaredMethod(
+ "getSessionPoliciesForApplication", int.class, String.class);
+ }
+ } catch (ClassNotFoundException | InstantiationException | InvocationTargetException
+ | IllegalAccessException | NoSuchMethodException e) {
+ Log.w(TAG, "Encountered problem while using reflection", e);
+ }
+ }
+
/**
* Information about a full user and its corresponding managed profiles.
*
@@ -1064,11 +1121,8 @@ public class MediaSessionService extends SystemService implements Monitor {
if (cb == null) {
throw new IllegalArgumentException("Controller callback cannot be null");
}
- int policies = (mCustomSessionPolicyProvider != null)
- ? mCustomSessionPolicyProvider.getSessionPoliciesForApplication(
- uid, packageName) : 0;
return createSessionInternal(pid, uid, resolvedUserId, packageName, cb, tag,
- sessionInfo, policies).getSessionBinder();
+ sessionInfo).getSessionBinder();
} finally {
Binder.restoreCallingIdentity(token);
}
@@ -1909,6 +1963,16 @@ public class MediaSessionService extends SystemService implements Monitor {
}
}
+ @Override
+ public void setCustomMediaKeyDispatcherForTesting(String name) {
+ instantiateCustomDispatcher(name);
+ }
+
+ @Override
+ public void setCustomSessionPolicyProviderForTesting(String name) {
+ instantiateCustomProvider(name);
+ }
+
// For MediaSession
private int verifySessionsRequest(ComponentName componentName, int userId, final int pid,
final int uid) {
@@ -2057,11 +2121,15 @@ public class MediaSessionService extends SystemService implements Monitor {
MediaSessionRecord session = null;
// Retrieve custom session for key event if it exists.
- if (mCustomMediaKeyDispatcher != null) {
- MediaSession.Token token =
- mCustomMediaKeyDispatcher.getSessionForKeyEvent(keyEvent, asSystemService);
- if (token != null) {
- session = getMediaSessionRecordLocked(token);
+ if (mCustomMediaKeyDispatcher != null && mGetSessionForKeyEventMethod != null) {
+ try {
+ Object tokenObject = mGetSessionForKeyEventMethod.invoke(
+ mCustomMediaKeyDispatcher, keyEvent, uid, asSystemService);
+ if (tokenObject != null) {
+ session = getMediaSessionRecordLocked((MediaSession.Token) tokenObject);
+ }
+ } catch (InvocationTargetException | IllegalAccessException e) {
+ Log.w(TAG, "Encountered problem while using reflection", e);
}
}
diff --git a/services/core/java/com/android/server/media/MediaSessionStack.java b/services/core/java/com/android/server/media/MediaSessionStack.java
index 07b1a1acf466..367f131a39bb 100644
--- a/services/core/java/com/android/server/media/MediaSessionStack.java
+++ b/services/core/java/com/android/server/media/MediaSessionStack.java
@@ -187,7 +187,9 @@ class MediaSessionStack {
for (int i = 0; i < audioPlaybackUids.size(); i++) {
MediaSessionRecordImpl mediaButtonSession =
findMediaButtonSession(audioPlaybackUids.get(i));
- if (mediaButtonSession != null) {
+ if (mediaButtonSession != null
+ && (mediaButtonSession.getSessionPolicies()
+ & SessionPolicyProvider.SESSION_POLICY_IGNORE_BUTTON_SESSION) == 0) {
// Found the media button session.
mAudioPlayerStateMonitor.cleanUpAudioPlaybackUids(mediaButtonSession.getUid());
if (mMediaButtonSession != mediaButtonSession) {
@@ -278,7 +280,7 @@ class MediaSessionStack {
// session.
if (newMediaButtonSession != null) {
int policies = newMediaButtonSession.getSessionPolicies();
- if ((policies & SessionPolicyProvider.SESSION_POLICY_IGNORE_BUTTON_SESSION) == 1) {
+ if ((policies & SessionPolicyProvider.SESSION_POLICY_IGNORE_BUTTON_SESSION) != 0) {
return;
}
}
diff --git a/services/core/java/com/android/server/media/SessionPolicyProvider.java b/services/core/java/com/android/server/media/SessionPolicyProvider.java
index 6eb79ef8dd71..40a3d2d66b1b 100644
--- a/services/core/java/com/android/server/media/SessionPolicyProvider.java
+++ b/services/core/java/com/android/server/media/SessionPolicyProvider.java
@@ -24,9 +24,12 @@ import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
/**
- * Interface for customizing {@link MediaSessionService}
+ * Abstract class for customizing how {@link MediaSessionService} handles sessions.
+ *
+ * Note: When instantiating this class, {@link MediaSessionService} will only use the constructor
+ * without any parameters.
*/
-public interface SessionPolicyProvider {
+public abstract class SessionPolicyProvider {
@IntDef(value = {
SESSION_POLICY_IGNORE_BUTTON_RECEIVER,
SESSION_POLICY_IGNORE_BUTTON_SESSION
@@ -40,7 +43,7 @@ public interface SessionPolicyProvider {
*
* @see MediaSession#setMediaButtonReceiver
*/
- int SESSION_POLICY_IGNORE_BUTTON_RECEIVER = 1 << 0;
+ static final int SESSION_POLICY_IGNORE_BUTTON_RECEIVER = 1 << 0;
/**
* Policy to ignore sessions that should not respond to media key events via
@@ -48,7 +51,11 @@ public interface SessionPolicyProvider {
* ignore sessions that should not respond to media key events even if their playback state has
* changed most recently.
*/
- int SESSION_POLICY_IGNORE_BUTTON_SESSION = 1 << 1;
+ static final int SESSION_POLICY_IGNORE_BUTTON_SESSION = 1 << 1;
+
+ public SessionPolicyProvider() {
+ // Constructor used for reflection
+ }
/**
* Use this to statically set policies for sessions when they are created.
@@ -59,5 +66,7 @@ public interface SessionPolicyProvider {
* @param packageName
* @return list of policies
*/
- @SessionPolicy int getSessionPoliciesForApplication(int uid, @NonNull String packageName);
+ @SessionPolicy int getSessionPoliciesForApplication(int uid, @NonNull String packageName) {
+ return 0;
+ }
}
diff --git a/services/core/java/com/android/server/media/SystemMediaRoute2Provider.java b/services/core/java/com/android/server/media/SystemMediaRoute2Provider.java
index da9c27e5bf0a..aad72034296d 100644
--- a/services/core/java/com/android/server/media/SystemMediaRoute2Provider.java
+++ b/services/core/java/com/android/server/media/SystemMediaRoute2Provider.java
@@ -125,13 +125,14 @@ class SystemMediaRoute2Provider extends MediaRoute2Provider {
}
@Override
- public void requestCreateSession(String packageName, String routeId, long requestId,
+ public void requestCreateSession(long requestId, String packageName, String routeId,
Bundle sessionHints) {
- // Do nothing
+ // Handle it as an internal transfer.
+ transferToRoute(requestId, SYSTEM_SESSION_ID, routeId);
}
@Override
- public void releaseSession(String sessionId, long requestId) {
+ public void releaseSession(long requestId, String sessionId) {
// Do nothing
}
@@ -141,17 +142,17 @@ class SystemMediaRoute2Provider extends MediaRoute2Provider {
}
@Override
- public void selectRoute(String sessionId, String routeId, long requestId) {
+ public void selectRoute(long requestId, String sessionId, String routeId) {
// Do nothing since we don't support multiple BT yet.
}
@Override
- public void deselectRoute(String sessionId, String routeId, long requestId) {
+ public void deselectRoute(long requestId, String sessionId, String routeId) {
// Do nothing since we don't support multiple BT yet.
}
@Override
- public void transferToRoute(String sessionId, String routeId, long requestId) {
+ public void transferToRoute(long requestId, String sessionId, String routeId) {
if (TextUtils.equals(routeId, mDefaultRoute.getId())) {
mBtRouteProvider.transferTo(null);
} else {
@@ -160,7 +161,7 @@ class SystemMediaRoute2Provider extends MediaRoute2Provider {
}
@Override
- public void setRouteVolume(String routeId, int volume, long requestId) {
+ public void setRouteVolume(long requestId, String routeId, int volume) {
if (!TextUtils.equals(routeId, mSelectedRouteId)) {
return;
}
@@ -168,7 +169,7 @@ class SystemMediaRoute2Provider extends MediaRoute2Provider {
}
@Override
- public void setSessionVolume(String sessionId, int volume, long requestId) {
+ public void setSessionVolume(long requestId, String sessionId, int volume) {
// Do nothing since we don't support grouping volume yet.
}
diff --git a/services/core/java/com/android/server/notification/NotificationHistoryManager.java b/services/core/java/com/android/server/notification/NotificationHistoryManager.java
index 7d680127740c..f7fb9b71ec87 100644
--- a/services/core/java/com/android/server/notification/NotificationHistoryManager.java
+++ b/services/core/java/com/android/server/notification/NotificationHistoryManager.java
@@ -358,7 +358,9 @@ public class NotificationHistoryManager {
false, this, UserHandle.USER_ALL);
synchronized (mLock) {
for (UserInfo userInfo : mUserManager.getUsers()) {
- update(null, userInfo.id);
+ if (!userInfo.isProfile()) {
+ update(null, userInfo.id);
+ }
}
}
}
@@ -379,7 +381,10 @@ public class NotificationHistoryManager {
boolean historyEnabled = Settings.Secure.getIntForUser(resolver,
Settings.Secure.NOTIFICATION_HISTORY_ENABLED, 0, userId)
!= 0;
- onHistoryEnabledChanged(userId, historyEnabled);
+ int[] profiles = mUserManager.getProfileIds(userId, true);
+ for (int profileId : profiles) {
+ onHistoryEnabledChanged(profileId, historyEnabled);
+ }
}
}
}
diff --git a/services/core/java/com/android/server/notification/NotificationManagerService.java b/services/core/java/com/android/server/notification/NotificationManagerService.java
index b5e7ea0731f3..69a5b35a5b12 100755
--- a/services/core/java/com/android/server/notification/NotificationManagerService.java
+++ b/services/core/java/com/android/server/notification/NotificationManagerService.java
@@ -2189,19 +2189,19 @@ public class NotificationManagerService extends SystemService {
private void registerNotificationPreferencesPullers() {
mPullAtomCallback = new StatsPullAtomCallbackImpl();
- mStatsManager.registerPullAtomCallback(
+ mStatsManager.setPullAtomCallback(
PACKAGE_NOTIFICATION_PREFERENCES,
null, // use default PullAtomMetadata values
BackgroundThread.getExecutor(),
mPullAtomCallback
);
- mStatsManager.registerPullAtomCallback(
+ mStatsManager.setPullAtomCallback(
PACKAGE_NOTIFICATION_CHANNEL_PREFERENCES,
null, // use default PullAtomMetadata values
BackgroundThread.getExecutor(),
mPullAtomCallback
);
- mStatsManager.registerPullAtomCallback(
+ mStatsManager.setPullAtomCallback(
PACKAGE_NOTIFICATION_CHANNEL_GROUP_PREFERENCES,
null, // use default PullAtomMetadata values
BackgroundThread.getExecutor(),
@@ -2684,6 +2684,7 @@ public class NotificationManagerService extends SystemService {
mHistoryManager.addNotification(new HistoricalNotification.Builder()
.setPackage(r.getSbn().getPackageName())
.setUid(r.getSbn().getUid())
+ .setUserId(r.getUserId())
.setChannelId(r.getChannel().getId())
.setChannelName(r.getChannel().getName().toString())
.setPostedTimeMs(System.currentTimeMillis())
diff --git a/services/core/java/com/android/server/om/OverlayActorEnforcer.java b/services/core/java/com/android/server/om/OverlayActorEnforcer.java
index 40efb7cd96d7..91979564fe96 100644
--- a/services/core/java/com/android/server/om/OverlayActorEnforcer.java
+++ b/services/core/java/com/android/server/om/OverlayActorEnforcer.java
@@ -29,7 +29,6 @@ import android.util.Pair;
import com.android.internal.util.ArrayUtils;
import com.android.internal.util.CollectionUtils;
-import com.android.server.SystemConfig;
import java.io.IOException;
import java.util.List;
@@ -38,6 +37,8 @@ import java.util.Map;
/**
* Performs verification that a calling UID can act on a target package's overlayable.
*
+ * Actors requirements are specified in {@link android.content.om.OverlayManager}.
+ *
* @hide
*/
public class OverlayActorEnforcer {
@@ -99,13 +100,7 @@ public class OverlayActorEnforcer {
}
/**
- * An actor is valid if any of the following is true:
- * - is {@link Process#ROOT_UID}, {@link Process#SYSTEM_UID}
- * - is the target overlay package
- * - has the CHANGE_OVERLAY_PACKAGES permission and an actor is not defined
- * - is the same the as the package defined in {@link SystemConfig#getNamedActors()} for a given
- * namespace and actor name
- *
+ * See {@link OverlayActorEnforcer} class comment for actor requirements.
* @return true if the actor is allowed to act on the target overlayInfo
*/
private ActorState isAllowedActor(String methodName, OverlayInfo overlayInfo,
diff --git a/services/core/java/com/android/server/pm/AppsFilter.java b/services/core/java/com/android/server/pm/AppsFilter.java
index 0ad0b2373a79..b90681de3518 100644
--- a/services/core/java/com/android/server/pm/AppsFilter.java
+++ b/services/core/java/com/android/server/pm/AppsFilter.java
@@ -43,6 +43,7 @@ import android.util.ArrayMap;
import android.util.ArraySet;
import android.util.Slog;
import android.util.SparseArray;
+import android.util.SparseBooleanArray;
import android.util.SparseSetArray;
import com.android.internal.R;
@@ -123,6 +124,7 @@ public class AppsFilter {
}
public interface FeatureConfig {
+
/** Called when the system is ready and components can be queried. */
void onSystemReady();
@@ -132,11 +134,21 @@ public class AppsFilter {
/** @return true if the feature is enabled for the given package. */
boolean packageIsEnabled(AndroidPackage pkg);
+ /** @return true if debug logging is enabled for the given package. */
+ boolean isLoggingEnabled(int appId);
+
+ /**
+ * Turns on logging for the given appId
+ * @param enable true if logging should be enabled, false if disabled.
+ */
+ void enableLogging(int appId, boolean enable);
+
/**
* Initializes the package enablement state for the given package. This gives opportunity
* to do any expensive operations ahead of the actual checks.
+ * @param removed true if adding, false if removing
*/
- void initializePackageState(String packageName);
+ void updatePackageState(PackageSetting setting, boolean removed);
}
private static class FeatureConfigImpl implements FeatureConfig, CompatChange.ChangeListener {
@@ -147,6 +159,9 @@ public class AppsFilter {
PackageManager.APP_ENUMERATION_ENABLED_BY_DEFAULT;
private final ArraySet<String> mDisabledPackages = new ArraySet<>();
+ @Nullable
+ private SparseBooleanArray mLoggingEnabled = null;
+
private FeatureConfigImpl(
PackageManagerInternal pmInternal, PackageManagerService.Injector injector) {
mPmInternal = pmInternal;
@@ -192,39 +207,65 @@ public class AppsFilter {
}
}
- private boolean fetchPackageIsEnabled(AndroidPackage pkg) {
+ @Override
+ public boolean isLoggingEnabled(int uid) {
+ return mLoggingEnabled != null && mLoggingEnabled.indexOfKey(uid) >= 0;
+ }
+
+ @Override
+ public void enableLogging(int appId, boolean enable) {
+ if (enable) {
+ if (mLoggingEnabled == null) {
+ mLoggingEnabled = new SparseBooleanArray();
+ }
+ mLoggingEnabled.put(appId, true);
+ } else {
+ if (mLoggingEnabled != null) {
+ final int index = mLoggingEnabled.indexOfKey(appId);
+ if (index >= 0) {
+ mLoggingEnabled.removeAt(index);
+ if (mLoggingEnabled.size() == 0) {
+ mLoggingEnabled = null;
+ }
+ }
+ }
+ }
+ }
+
+ @Override
+ public void onCompatChange(String packageName) {
+ updateEnabledState(mPmInternal.getPackage(packageName));
+ }
+
+ private void updateEnabledState(AndroidPackage pkg) {
final long token = Binder.clearCallingIdentity();
try {
// TODO(b/135203078): Do not use toAppInfo
- final boolean changeEnabled =
+ final boolean enabled =
mInjector.getCompatibility().isChangeEnabled(
PackageManager.FILTER_APPLICATION_QUERY,
pkg.toAppInfoWithoutState());
- return changeEnabled;
+ if (enabled) {
+ mDisabledPackages.remove(pkg.getPackageName());
+ } else {
+ mDisabledPackages.add(pkg.getPackageName());
+ }
} finally {
Binder.restoreCallingIdentity(token);
}
}
@Override
- public void onCompatChange(String packageName) {
- final AndroidPackage pkg = mPmInternal.getPackage(packageName);
- if (pkg == null) {
- mDisabledPackages.remove(packageName);
- return;
- }
- boolean enabled = fetchPackageIsEnabled(pkg);
- if (enabled) {
- mDisabledPackages.remove(packageName);
+ public void updatePackageState(PackageSetting setting, boolean removed) {
+ final boolean enableLogging =
+ !removed && (setting.pkg.isTestOnly() || setting.pkg.isDebuggable());
+ enableLogging(setting.appId, enableLogging);
+ if (removed) {
+ mDisabledPackages.remove(setting.pkg.getPackageName());
} else {
- mDisabledPackages.add(packageName);
+ updateEnabledState(setting.pkg);
}
}
-
- @Override
- public void initializePackageState(String packageName) {
- onCompatChange(packageName);
- }
}
/** Builder method for an AppsFilter */
@@ -250,6 +291,10 @@ public class AppsFilter {
forceSystemAppsQueryable, null);
}
+ public FeatureConfig getFeatureConfig() {
+ return mFeatureConfig;
+ }
+
/** Returns true if the querying package may query for the potential target package */
private static boolean canQueryViaComponents(AndroidPackage querying,
AndroidPackage potentialTarget) {
@@ -447,7 +492,7 @@ public class AppsFilter {
}
}
mOverlayReferenceMapper.addPkg(newPkgSetting.pkg, existingPkgs);
- mFeatureConfig.initializePackageState(newPkgSetting.pkg.getPackageName());
+ mFeatureConfig.updatePackageState(newPkgSetting, false /*removed*/);
} finally {
Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
}
@@ -499,7 +544,7 @@ public class AppsFilter {
}
mOverlayReferenceMapper.removePkg(setting.name);
- mFeatureConfig.initializePackageState(setting.pkg.getPackageName());
+ mFeatureConfig.updatePackageState(setting, true /*removed*/);
}
/**
@@ -516,13 +561,13 @@ public class AppsFilter {
PackageSetting targetPkgSetting, int userId) {
Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "shouldFilterApplication");
try {
- if (!shouldFilterApplicationInternal(callingUid, callingSetting, targetPkgSetting,
- userId)) {
+
+ if (!shouldFilterApplicationInternal(
+ callingUid, callingSetting, targetPkgSetting, userId)) {
return false;
}
- if (DEBUG_LOGGING) {
- log(callingSetting, targetPkgSetting,
- DEBUG_ALLOW_ALL ? "ALLOWED" : "BLOCKED", new RuntimeException());
+ if (DEBUG_LOGGING || mFeatureConfig.isLoggingEnabled(UserHandle.getAppId(callingUid))) {
+ log(callingSetting, targetPkgSetting, "BLOCKED");
}
return !DEBUG_ALLOW_ALL;
} finally {
@@ -737,17 +782,11 @@ public class AppsFilter {
}
}
- private static void log(SettingBase callingPkgSetting, PackageSetting targetPkgSetting,
+ private static void log(SettingBase callingSetting, PackageSetting targetPkgSetting,
String description) {
- log(callingPkgSetting, targetPkgSetting, description, null);
- }
-
- private static void log(SettingBase callingPkgSetting, PackageSetting targetPkgSetting,
- String description, Throwable throwable) {
- Slog.wtf(TAG,
- "interaction: " + callingPkgSetting
- + " -> " + targetPkgSetting + " "
- + description, throwable);
+ Slog.i(TAG,
+ "interaction: " + (callingSetting == null ? "system" : callingSetting) + " -> "
+ + targetPkgSetting + " " + description);
}
public void dumpQueries(
diff --git a/services/core/java/com/android/server/pm/DataLoaderManagerService.java b/services/core/java/com/android/server/pm/DataLoaderManagerService.java
index ad20d38e9ed4..8eb773a2d0f8 100644
--- a/services/core/java/com/android/server/pm/DataLoaderManagerService.java
+++ b/services/core/java/com/android/server/pm/DataLoaderManagerService.java
@@ -116,9 +116,6 @@ public class DataLoaderManagerService extends SystemService {
return null;
}
- // TODO(b/136132412): better way to enable privileged data loaders in tests
- boolean checkLoader =
- android.os.SystemProperties.getBoolean("incremental.check_loader", false);
int numServices = services.size();
for (int i = 0; i < numServices; i++) {
ResolveInfo ri = services.get(i);
@@ -128,7 +125,7 @@ public class DataLoaderManagerService extends SystemService {
// If there's more than one, return the first one found.
try {
ApplicationInfo ai = pm.getApplicationInfo(resolved.getPackageName(), 0);
- if (checkLoader && !ai.isPrivilegedApp()) {
+ if (!ai.isPrivilegedApp()) {
Slog.w(TAG,
"Data loader: " + resolved + " is not a privileged app, skipping.");
continue;
diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java
index a8996d5cfea4..799ce65669db 100644
--- a/services/core/java/com/android/server/pm/PackageManagerService.java
+++ b/services/core/java/com/android/server/pm/PackageManagerService.java
@@ -3364,6 +3364,10 @@ public class PackageManagerService extends IPackageManager.Stub
// critical part of the core system.
mRequiredPermissionControllerPackage = getRequiredPermissionControllerLPr();
+ mSettings.setPermissionControllerVersion(
+ getPackageInfo(mRequiredPermissionControllerPackage, 0,
+ UserHandle.USER_SYSTEM).getLongVersionCode());
+
// Initialize InstantAppRegistry's Instant App list for all users.
final int[] userIds = UserManagerService.getInstance().getUserIds();
for (AndroidPackage pkg : mPackages.values()) {
@@ -6838,7 +6842,7 @@ public class PackageManagerService extends IPackageManager.Stub
|| (matchVisibleToInstantAppOnly && isCallerInstantApp
&& isTargetHiddenFromInstantApp));
final boolean blockNormalResolution = !isTargetInstantApp && !isCallerInstantApp
- && !resolveForStart && shouldFilterApplicationLocked(
+ && shouldFilterApplicationLocked(
getPackageSettingInternal(ai.applicationInfo.packageName,
Process.SYSTEM_UID), filterCallingUid, userId);
if (!blockInstantResolution && !blockNormalResolution) {
@@ -18558,9 +18562,10 @@ public class PackageManagerService extends IPackageManager.Stub
Slog.d(TAG, "Updating package:" + ps.name + " install state for user:"
+ nextUserId);
}
-
- destroyAppDataLIF(pkg, nextUserId,
- FLAG_STORAGE_DE | FLAG_STORAGE_CE | FLAG_STORAGE_EXTERNAL);
+ if ((flags & PackageManager.DELETE_KEEP_DATA) == 0) {
+ destroyAppDataLIF(pkg, nextUserId,
+ FLAG_STORAGE_DE | FLAG_STORAGE_CE | FLAG_STORAGE_EXTERNAL);
+ }
clearDefaultBrowserIfNeededForUser(ps.name, nextUserId);
removeKeystoreDataIfNeeded(mInjector.getUserManagerInternal(), nextUserId, ps.appId);
clearPackagePreferredActivities(ps.name, nextUserId);
@@ -19985,6 +19990,11 @@ public class PackageManagerService extends IPackageManager.Stub
long token = Binder.clearCallingIdentity();
try {
if (getPackageInfo(packageName, MATCH_FACTORY_ONLY, UserHandle.USER_SYSTEM) == null) {
+ PackageInfo packageInfo = getPackageInfo(packageName, 0, UserHandle.USER_SYSTEM);
+ if (packageInfo != null) {
+ EventLog.writeEvent(0x534e4554, "145981139", packageInfo.applicationInfo.uid,
+ "");
+ }
return null;
}
} finally {
@@ -22668,7 +22678,7 @@ public class PackageManagerService extends IPackageManager.Stub
boolean readPermissionStateForUser(@UserIdInt int userId) {
synchronized (mPackages) {
mSettings.readPermissionStateForUserSyncLPr(userId);
- return mSettings.areDefaultRuntimePermissionsGrantedLPr(userId);
+ return mPmInternal.isPermissionUpgradeNeeded(userId);
}
}
@@ -24067,10 +24077,9 @@ public class PackageManagerService extends IPackageManager.Stub
}
@Override
- public void setRuntimePermissionsFingerPrint(@NonNull String fingerPrint,
- @UserIdInt int userId) {
+ public void updateRuntimePermissionsFingerprint(@UserIdInt int userId) {
synchronized (mLock) {
- mSettings.setRuntimePermissionsFingerPrintLPr(fingerPrint, userId);
+ mSettings.updateRuntimePermissionsFingerprintLPr(userId);
}
}
@@ -24122,9 +24131,9 @@ public class PackageManagerService extends IPackageManager.Stub
}
@Override
- public boolean areDefaultRuntimePermissionsGranted(int userId) {
+ public boolean isPermissionUpgradeNeeded(int userId) {
synchronized (mLock) {
- return mSettings.areDefaultRuntimePermissionsGrantedLPr(userId);
+ return mSettings.isPermissionUpgradeNeededLPr(userId);
}
}
@@ -24152,6 +24161,18 @@ public class PackageManagerService extends IPackageManager.Stub
public List<String> getMimeGroup(String packageName, String mimeGroup) {
return PackageManagerService.this.getMimeGroup(packageName, mimeGroup);
}
+
+ @Override
+ public void setVisibilityLogging(String packageName, boolean enable) {
+ final PackageSetting pkg;
+ synchronized (mLock) {
+ pkg = mSettings.getPackageLPr(packageName);
+ }
+ if (pkg == null) {
+ throw new IllegalStateException("No package found for " + packageName);
+ }
+ mAppsFilter.getFeatureConfig().enableLogging(pkg.appId, enable);
+ }
}
@GuardedBy("mLock")
diff --git a/services/core/java/com/android/server/pm/PackageManagerShellCommand.java b/services/core/java/com/android/server/pm/PackageManagerShellCommand.java
index 0f06c186b9ff..be17dd8989a3 100644
--- a/services/core/java/com/android/server/pm/PackageManagerShellCommand.java
+++ b/services/core/java/com/android/server/pm/PackageManagerShellCommand.java
@@ -295,6 +295,8 @@ class PackageManagerShellCommand extends ShellCommand {
return runRollbackApp();
case "get-moduleinfo":
return runGetModuleInfo();
+ case "log-visibility":
+ return runLogVisibility();
default: {
String nextArg = getNextArg();
if (nextArg == null) {
@@ -360,6 +362,36 @@ class PackageManagerShellCommand extends ShellCommand {
return 1;
}
+ private int runLogVisibility() {
+ final PrintWriter pw = getOutPrintWriter();
+ boolean enable = true;
+
+ String opt;
+ while ((opt = getNextOption()) != null) {
+ switch (opt) {
+ case "--disable":
+ enable = false;
+ break;
+ case "--enable":
+ enable = true;
+ break;
+ default:
+ pw.println("Error: Unknown option: " + opt);
+ return -1;
+ }
+ }
+
+ String packageName = getNextArg();
+ if (packageName != null) {
+ LocalServices.getService(PackageManagerInternal.class)
+ .setVisibilityLogging(packageName, enable);
+ } else {
+ getErrPrintWriter().println("Error: no package specified");
+ return -1;
+ }
+ return 1;
+ }
+
private int uninstallSystemUpdates() {
final PrintWriter pw = getOutPrintWriter();
List<String> failedUninstalls = new LinkedList<>();
@@ -3715,6 +3747,11 @@ class PackageManagerShellCommand extends ShellCommand {
pw.println(" --all: show all module info");
pw.println(" --installed: show only installed modules");
pw.println("");
+ pw.println(" log-visibility [--enable|--disable] <PACKAGE>");
+ pw.println(" Turns on debug logging when visibility is blocked for the given package.");
+ pw.println(" --enable: turn on debug logging (default)");
+ pw.println(" --disable: turn off debug logging");
+ pw.println("");
Intent.printIntentArgsHelp(pw , "");
}
diff --git a/services/core/java/com/android/server/pm/PackageSetting.java b/services/core/java/com/android/server/pm/PackageSetting.java
index 2bd1a26f1e28..a83a8476b8db 100644
--- a/services/core/java/com/android/server/pm/PackageSetting.java
+++ b/services/core/java/com/android/server/pm/PackageSetting.java
@@ -321,6 +321,8 @@ public class PackageSetting extends PackageSettingBase {
Set<String> mimeGroupNames = other.mimeGroups != null ? other.mimeGroups.keySet() : null;
updateMimeGroups(mimeGroupNames);
+
+ getPkgState().updateFrom(other.getPkgState());
}
@NonNull
diff --git a/services/core/java/com/android/server/pm/Settings.java b/services/core/java/com/android/server/pm/Settings.java
index 1dc705b4add9..2d16854f787a 100644
--- a/services/core/java/com/android/server/pm/Settings.java
+++ b/services/core/java/com/android/server/pm/Settings.java
@@ -1319,13 +1319,12 @@ public final class Settings {
}
}
- boolean areDefaultRuntimePermissionsGrantedLPr(int userId) {
- return mRuntimePermissionsPersistence
- .areDefaultRuntimePermissionsGrantedLPr(userId);
+ boolean isPermissionUpgradeNeededLPr(int userId) {
+ return mRuntimePermissionsPersistence.isPermissionUpgradeNeeded(userId);
}
- void setRuntimePermissionsFingerPrintLPr(@NonNull String fingerPrint, @UserIdInt int userId) {
- mRuntimePermissionsPersistence.setRuntimePermissionsFingerPrintLPr(fingerPrint, userId);
+ void updateRuntimePermissionsFingerprintLPr(@UserIdInt int userId) {
+ mRuntimePermissionsPersistence.updateRuntimePermissionsFingerprintLPr(userId);
}
int getDefaultRuntimePermissionsVersionLPr(int userId) {
@@ -1336,6 +1335,10 @@ public final class Settings {
mRuntimePermissionsPersistence.setVersionLPr(version, userId);
}
+ void setPermissionControllerVersion(long version) {
+ mRuntimePermissionsPersistence.setPermissionControllerVersion(version);
+ }
+
public VersionInfo findOrCreateVersion(String volumeUuid) {
VersionInfo ver = mVersion.get(volumeUuid);
if (ver == null) {
@@ -5296,6 +5299,8 @@ public final class Settings {
private static final int UPGRADE_VERSION = -1;
private static final int INITIAL_VERSION = 0;
+ private String mExtendedFingerprint;
+
private final RuntimePermissionsPersistence mPersistence =
RuntimePermissionsPersistence.createInstance();
@@ -5320,7 +5325,7 @@ public final class Settings {
@GuardedBy("mLock")
// The mapping keys are user ids.
- private final SparseBooleanArray mDefaultPermissionsGranted = new SparseBooleanArray();
+ private final SparseBooleanArray mPermissionUpgradeNeeded = new SparseBooleanArray();
public RuntimePermissionPersistence(Object persistenceLock) {
mPersistenceLock = persistenceLock;
@@ -5338,17 +5343,36 @@ public final class Settings {
}
@GuardedBy("Settings.this.mLock")
- public boolean areDefaultRuntimePermissionsGrantedLPr(int userId) {
- return mDefaultPermissionsGranted.get(userId);
+ public boolean isPermissionUpgradeNeeded(int userId) {
+ return mPermissionUpgradeNeeded.get(userId, true);
}
@GuardedBy("Settings.this.mLock")
- public void setRuntimePermissionsFingerPrintLPr(@NonNull String fingerPrint,
- @UserIdInt int userId) {
- mFingerprints.put(userId, fingerPrint);
+ public void updateRuntimePermissionsFingerprintLPr(@UserIdInt int userId) {
+ if (mExtendedFingerprint == null) {
+ throw new RuntimeException("The version of the permission controller hasn't been "
+ + "set before trying to update the fingerprint.");
+ }
+ mFingerprints.put(userId, mExtendedFingerprint);
writePermissionsForUserAsyncLPr(userId);
}
+ public void setPermissionControllerVersion(long version) {
+ int numUser = mFingerprints.size();
+ mExtendedFingerprint = getExtendedFingerprint(version);
+
+ for (int i = 0; i < numUser; i++) {
+ int userId = mFingerprints.keyAt(i);
+ String fingerprint = mFingerprints.valueAt(i);
+ mPermissionUpgradeNeeded.put(userId,
+ !TextUtils.equals(mExtendedFingerprint, fingerprint));
+ }
+ }
+
+ private String getExtendedFingerprint(long version) {
+ return Build.FINGERPRINT + "?pc_version=" + version;
+ }
+
public void writePermissionsForUserSyncLPr(int userId) {
mHandler.removeMessages(userId);
writePermissionsSync(userId);
@@ -5461,7 +5485,7 @@ public final class Settings {
revokeRuntimePermissionsAndClearFlags(sb, userId);
}
- mDefaultPermissionsGranted.delete(userId);
+ mPermissionUpgradeNeeded.delete(userId);
mVersions.delete(userId);
mFingerprints.remove(userId);
}
@@ -5503,8 +5527,6 @@ public final class Settings {
String fingerprint = runtimePermissions.getFingerprint();
mFingerprints.put(userId, fingerprint);
- boolean defaultPermissionsGranted = Build.FINGERPRINT.equals(fingerprint);
- mDefaultPermissionsGranted.put(userId, defaultPermissionsGranted);
boolean isUpgradeToR = getInternalVersion().sdkVersion < Build.VERSION_CODES.R;
@@ -5636,7 +5658,7 @@ public final class Settings {
} catch (XmlPullParserException | IOException e) {
throw new IllegalStateException("Failed parsing permissions file: "
- + permissionsFile , e);
+ + permissionsFile, e);
} finally {
IoUtils.closeQuietly(in);
}
@@ -5664,8 +5686,6 @@ public final class Settings {
mVersions.put(userId, version);
String fingerprint = parser.getAttributeValue(null, ATTR_FINGERPRINT);
mFingerprints.put(userId, fingerprint);
- final boolean defaultsGranted = Build.FINGERPRINT.equals(fingerprint);
- mDefaultPermissionsGranted.put(userId, defaultsGranted);
} break;
case TAG_PACKAGE: {
@@ -5724,13 +5744,14 @@ public final class Settings {
if (granted) {
permissionsState.grantRuntimePermission(bp, userId);
permissionsState.updatePermissionFlags(bp, userId,
- PackageManager.MASK_PERMISSION_FLAGS_ALL, flags);
+ PackageManager.MASK_PERMISSION_FLAGS_ALL, flags);
} else {
permissionsState.updatePermissionFlags(bp, userId,
PackageManager.MASK_PERMISSION_FLAGS_ALL, flags);
}
- } break;
+ }
+ break;
}
}
}
diff --git a/services/core/java/com/android/server/pm/StagingManager.java b/services/core/java/com/android/server/pm/StagingManager.java
index 7dd2e5506bb7..83fe5562324f 100644
--- a/services/core/java/com/android/server/pm/StagingManager.java
+++ b/services/core/java/com/android/server/pm/StagingManager.java
@@ -331,7 +331,8 @@ public class StagingManager {
}
// Reverts apex sessions and user data (if checkpoint is supported). Also reboots the device.
- private void abortCheckpoint() {
+ private void abortCheckpoint(String errorMsg) {
+ Slog.e(TAG, "Aborting checkpoint: " + errorMsg);
try {
if (supportsCheckpoint() && needsCheckpoint()) {
mApexManager.revertActiveSessions();
@@ -504,6 +505,8 @@ public class StagingManager {
// mode. If not, we fail all sessions.
if (supportsCheckpoint() && !needsCheckpoint()) {
// TODO(b/146343545): Persist failure reason across checkpoint reboot
+ Slog.d(TAG, "Reverting back to safe state. Marking " + session.sessionId
+ + " as failed.");
session.setStagedSessionFailed(SessionInfo.STAGED_SESSION_UNKNOWN,
"Reverting back to safe state");
return;
@@ -524,26 +527,29 @@ public class StagingManager {
if (hasApex) {
if (apexSessionInfo == null) {
+ String errorMsg = "apexd did not know anything about a staged session supposed to"
+ + " be activated";
session.setStagedSessionFailed(SessionInfo.STAGED_SESSION_ACTIVATION_FAILED,
- "apexd did not know anything about a staged session supposed to be"
- + "activated");
- abortCheckpoint();
+ errorMsg);
+ abortCheckpoint(errorMsg);
return;
}
if (isApexSessionFailed(apexSessionInfo)) {
+ String errorMsg = "APEX activation failed. Check logcat messages from apexd for "
+ + "more information.";
session.setStagedSessionFailed(SessionInfo.STAGED_SESSION_ACTIVATION_FAILED,
- "APEX activation failed. Check logcat messages from apexd for "
- + "more information.");
- abortCheckpoint();
+ errorMsg);
+ abortCheckpoint(errorMsg);
return;
}
if (!apexSessionInfo.isActivated && !apexSessionInfo.isSuccess) {
// Apexd did not apply the session for some unknown reason. There is no guarantee
// that apexd will install it next time. Safer to proactively mark as failed.
+ String errorMsg = "Staged session " + session.sessionId + "at boot didn't "
+ + "activate nor fail. Marking it as failed anyway.";
session.setStagedSessionFailed(SessionInfo.STAGED_SESSION_ACTIVATION_FAILED,
- "Staged session " + session.sessionId + "at boot didn't "
- + "activate nor fail. Marking it as failed anyway.");
- abortCheckpoint();
+ errorMsg);
+ abortCheckpoint(errorMsg);
return;
}
snapshotAndRestoreForApexSession(session);
@@ -556,7 +562,7 @@ public class StagingManager {
installApksInSession(session);
} catch (PackageManagerException e) {
session.setStagedSessionFailed(e.error, e.getMessage());
- abortCheckpoint();
+ abortCheckpoint(e.getMessage());
// If checkpoint is not supported, we have to handle failure for one staged session.
if (!hasApex) {
diff --git a/services/core/java/com/android/server/pm/permission/DefaultPermissionGrantPolicy.java b/services/core/java/com/android/server/pm/permission/DefaultPermissionGrantPolicy.java
index 2feddb6a4fe3..e3abcda2530f 100644
--- a/services/core/java/com/android/server/pm/permission/DefaultPermissionGrantPolicy.java
+++ b/services/core/java/com/android/server/pm/permission/DefaultPermissionGrantPolicy.java
@@ -60,10 +60,8 @@ import android.util.ArrayMap;
import android.util.ArraySet;
import android.util.Log;
import android.util.Slog;
-import android.util.SparseIntArray;
import android.util.Xml;
-import com.android.internal.annotations.GuardedBy;
import com.android.internal.util.ArrayUtils;
import com.android.internal.util.XmlUtils;
import com.android.server.LocalServices;
@@ -226,9 +224,6 @@ public final class DefaultPermissionGrantPolicy {
private final PackageManagerInternal mServiceInternal;
private final PermissionManagerService mPermissionManager;
- @GuardedBy("mLock")
- private SparseIntArray mDefaultPermissionsGrantedUsers = new SparseIntArray();
-
DefaultPermissionGrantPolicy(Context context, Looper looper,
@NonNull PermissionManagerService permissionManager) {
mContext = context;
@@ -297,19 +292,10 @@ public final class DefaultPermissionGrantPolicy {
}
}
- public boolean wereDefaultPermissionsGrantedSinceBoot(int userId) {
- synchronized (mLock) {
- return mDefaultPermissionsGrantedUsers.indexOfKey(userId) >= 0;
- }
- }
-
public void grantDefaultPermissions(int userId) {
grantPermissionsToSysComponentsAndPrivApps(userId);
grantDefaultSystemHandlerPermissions(userId);
grantDefaultPermissionExceptions(userId);
- synchronized (mLock) {
- mDefaultPermissionsGrantedUsers.put(userId, userId);
- }
}
private void grantRuntimePermissionsForSystemPackage(int userId, PackageInfo pkg) {
diff --git a/services/core/java/com/android/server/pm/permission/PermissionManagerService.java b/services/core/java/com/android/server/pm/permission/PermissionManagerService.java
index 4a85027854d6..85da5593223b 100644
--- a/services/core/java/com/android/server/pm/permission/PermissionManagerService.java
+++ b/services/core/java/com/android/server/pm/permission/PermissionManagerService.java
@@ -4223,7 +4223,7 @@ public class PermissionManagerService extends IPermissionManager.Stub {
int[] grantPermissionsUserIds = EMPTY_INT_ARRAY;
for (int userId : UserManagerService.getInstance().getUserIds()) {
- if (!mPackageManagerInt.areDefaultRuntimePermissionsGranted(userId)) {
+ if (mPackageManagerInt.isPermissionUpgradeNeeded(userId)) {
grantPermissionsUserIds = ArrayUtils.appendInt(
grantPermissionsUserIds, userId);
}
@@ -4628,13 +4628,6 @@ public class PermissionManagerService extends IPermissionManager.Stub {
}
@Override
- public boolean wereDefaultPermissionsGrantedSinceBoot(int userId) {
- synchronized (mLock) {
- return mDefaultPermissionGrantPolicy.wereDefaultPermissionsGrantedSinceBoot(userId);
- }
- }
-
- @Override
public void onNewUserCreated(int userId) {
mDefaultPermissionGrantPolicy.grantDefaultPermissions(userId);
synchronized (mLock) {
diff --git a/services/core/java/com/android/server/pm/permission/PermissionManagerServiceInternal.java b/services/core/java/com/android/server/pm/permission/PermissionManagerServiceInternal.java
index 048e487fdaeb..32ef2cee5685 100644
--- a/services/core/java/com/android/server/pm/permission/PermissionManagerServiceInternal.java
+++ b/services/core/java/com/android/server/pm/permission/PermissionManagerServiceInternal.java
@@ -447,12 +447,6 @@ public abstract class PermissionManagerServiceInternal extends PermissionManager
public abstract void grantDefaultPermissionsToDefaultUseOpenWifiApp(
@NonNull String packageName, @UserIdInt int userId);
- /**
- * Returns whether or not default permission grants have been performed for the given
- * user since the device booted.
- */
- public abstract boolean wereDefaultPermissionsGrantedSinceBoot(@UserIdInt int userId);
-
/** Called when a new user has been created. */
public abstract void onNewUserCreated(@UserIdInt int userId);
}
diff --git a/services/core/java/com/android/server/pm/pkg/PackageStateUnserialized.java b/services/core/java/com/android/server/pm/pkg/PackageStateUnserialized.java
index e27bf48b6b61..edb6d65bd96f 100644
--- a/services/core/java/com/android/server/pm/pkg/PackageStateUnserialized.java
+++ b/services/core/java/com/android/server/pm/pkg/PackageStateUnserialized.java
@@ -27,6 +27,7 @@ import android.content.pm.SharedLibraryInfo;
import com.android.internal.util.DataClass;
import com.android.server.pm.PackageSetting;
+import java.util.ArrayList;
import java.util.List;
/**
@@ -88,6 +89,22 @@ public class PackageStateUnserialized {
return latestUse;
}
+ public void updateFrom(PackageStateUnserialized other) {
+ this.hiddenUntilInstalled = other.hiddenUntilInstalled;
+
+ if (!other.usesLibraryInfos.isEmpty()) {
+ this.usesLibraryInfos = new ArrayList<>(other.usesLibraryInfos);
+ }
+
+ if (!other.usesLibraryFiles.isEmpty()) {
+ this.usesLibraryFiles = new ArrayList<>(other.usesLibraryFiles);
+ }
+
+ this.updatedSystemApp = other.updatedSystemApp;
+ this.lastPackageUsageTimeInMills = other.lastPackageUsageTimeInMills;
+ this.overrideSeInfo = other.overrideSeInfo;
+ }
+
// Code below generated by codegen v1.0.14.
diff --git a/services/core/java/com/android/server/policy/PermissionPolicyService.java b/services/core/java/com/android/server/policy/PermissionPolicyService.java
index 139c844256fa..d589353cf3a0 100644
--- a/services/core/java/com/android/server/policy/PermissionPolicyService.java
+++ b/services/core/java/com/android/server/policy/PermissionPolicyService.java
@@ -280,7 +280,7 @@ public final class PermissionPolicyService extends SystemService {
LocalServices.getService(PackageManagerInternal.class);
final PermissionManagerServiceInternal permissionManagerInternal =
LocalServices.getService(PermissionManagerServiceInternal.class);
- if (permissionManagerInternal.wereDefaultPermissionsGrantedSinceBoot(userId)) {
+ if (packageManagerInternal.isPermissionUpgradeNeeded(userId)) {
if (DEBUG) Slog.i(LOG_TAG, "defaultPermsWereGrantedSinceBoot(" + userId + ")");
// Now call into the permission controller to apply policy around permissions
@@ -314,7 +314,7 @@ public final class PermissionPolicyService extends SystemService {
permissionControllerManager.updateUserSensitive();
- packageManagerInternal.setRuntimePermissionsFingerPrint(Build.FINGERPRINT, userId);
+ packageManagerInternal.updateRuntimePermissionsFingerprint(userId);
}
}
diff --git a/services/core/java/com/android/server/power/PowerManagerService.java b/services/core/java/com/android/server/power/PowerManagerService.java
index f04be0b1aa9d..294deba459fe 100644
--- a/services/core/java/com/android/server/power/PowerManagerService.java
+++ b/services/core/java/com/android/server/power/PowerManagerService.java
@@ -42,6 +42,8 @@ import android.hardware.SystemSensorManager;
import android.hardware.display.AmbientDisplayConfiguration;
import android.hardware.display.DisplayManagerInternal;
import android.hardware.display.DisplayManagerInternal.DisplayPowerRequest;
+import android.hardware.power.Boost;
+import android.hardware.power.Mode;
import android.hardware.power.V1_0.PowerHint;
import android.net.Uri;
import android.os.BatteryManager;
@@ -732,6 +734,16 @@ public final class PowerManagerService extends SystemService
PowerManagerService.nativeSendPowerHint(hintId, data);
}
+ /** Wrapper for PowerManager.nativeSetPowerBoost */
+ public void nativeSetPowerBoost(int boost, int durationMs) {
+ PowerManagerService.nativeSetPowerBoost(boost, durationMs);
+ }
+
+ /** Wrapper for PowerManager.nativeSetPowerMode */
+ public void nativeSetPowerMode(int mode, boolean enabled) {
+ PowerManagerService.nativeSetPowerMode(mode, enabled);
+ }
+
/** Wrapper for PowerManager.nativeSetFeature */
public void nativeSetFeature(int featureId, int data) {
PowerManagerService.nativeSetFeature(featureId, data);
@@ -817,6 +829,8 @@ public final class PowerManagerService extends SystemService
private static native void nativeSetInteractive(boolean enable);
private static native void nativeSetAutoSuspend(boolean enable);
private static native void nativeSendPowerHint(int hintId, int data);
+ private static native void nativeSetPowerBoost(int boost, int durationMs);
+ private static native void nativeSetPowerMode(int mode, boolean enabled);
private static native void nativeSetFeature(int featureId, int data);
private static native boolean nativeForceSuspend();
@@ -3608,6 +3622,16 @@ public final class PowerManagerService extends SystemService
mNativeWrapper.nativeSendPowerHint(hintId, data);
}
+ private void setPowerBoostInternal(int boost, int durationMs) {
+ // Maybe filter the event.
+ mNativeWrapper.nativeSetPowerBoost(boost, durationMs);
+ }
+
+ private void setPowerModeInternal(int mode, boolean enabled) {
+ // Maybe filter the event.
+ mNativeWrapper.nativeSetPowerMode(mode, enabled);
+ }
+
@VisibleForTesting
boolean wasDeviceIdleForInternal(long ms) {
synchronized (mLock) {
@@ -4664,6 +4688,26 @@ public final class PowerManagerService extends SystemService
}
@Override // Binder call
+ public void setPowerBoost(int boost, int durationMs) {
+ if (!mSystemReady) {
+ // Service not ready yet, so who the heck cares about power hints, bah.
+ return;
+ }
+ mContext.enforceCallingOrSelfPermission(android.Manifest.permission.DEVICE_POWER, null);
+ setPowerBoostInternal(boost, durationMs);
+ }
+
+ @Override // Binder call
+ public void setPowerMode(int mode, boolean enabled) {
+ if (!mSystemReady) {
+ // Service not ready yet, so who the heck cares about power hints, bah.
+ return;
+ }
+ mContext.enforceCallingOrSelfPermission(android.Manifest.permission.DEVICE_POWER, null);
+ setPowerModeInternal(mode, enabled);
+ }
+
+ @Override // Binder call
public void acquireWakeLock(IBinder lock, int flags, String tag, String packageName,
WorkSource ws, String historyTag) {
if (lock == null) {
@@ -5457,6 +5501,15 @@ public final class PowerManagerService extends SystemService
}
@Override
+ public void setPowerBoost(int boost, int durationMs) {
+ setPowerBoostInternal(boost, durationMs);
+ }
+
+ @Override
+ public void setPowerMode(int mode, boolean enabled) {
+ setPowerModeInternal(mode, enabled);
+ }
+ @Override
public boolean wasDeviceIdleFor(long ms) {
return wasDeviceIdleForInternal(ms);
}
diff --git a/services/core/java/com/android/server/soundtrigger_middleware/SoundTriggerMiddlewareValidation.java b/services/core/java/com/android/server/soundtrigger_middleware/SoundTriggerMiddlewareValidation.java
index c45f37dfdbd8..1292f6c121b4 100644
--- a/services/core/java/com/android/server/soundtrigger_middleware/SoundTriggerMiddlewareValidation.java
+++ b/services/core/java/com/android/server/soundtrigger_middleware/SoundTriggerMiddlewareValidation.java
@@ -203,15 +203,18 @@ public class SoundTriggerMiddlewareValidation implements ISoundTriggerMiddleware
checkPreemptPermissions();
// Input validation (always valid).
- synchronized (this) {
- // State validation (always valid).
-
- // From here on, every exception isn't client's fault.
- try {
- mDelegate.setExternalCaptureState(active);
- } catch (Exception e) {
- throw handleException(e);
- }
+ // State validation (always valid).
+
+ // Normally, we would acquire a lock here. However, we do not access any state here so it
+ // is safe to not lock. This call is typically done from a different context than all the
+ // other calls and may result in a deadlock if we lock here (between the audio server and
+ // the system server).
+
+ // From here on, every exception isn't client's fault.
+ try {
+ mDelegate.setExternalCaptureState(active);
+ } catch (Exception e) {
+ throw handleException(e);
}
}
@@ -249,21 +252,8 @@ public class SoundTriggerMiddlewareValidation implements ISoundTriggerMiddleware
* @param permission The permission to check.
*/
void enforcePermission(String permission) {
- final int status = PermissionChecker.checkCallingOrSelfPermissionForPreflight(mContext,
- permission);
- switch (status) {
- case PermissionChecker.PERMISSION_GRANTED:
- return;
- case PermissionChecker.PERMISSION_HARD_DENIED:
- throw new SecurityException(
- String.format("Caller must have the %s permission.", permission));
- case PermissionChecker.PERMISSION_SOFT_DENIED:
- throw new ServiceSpecificException(Status.TEMPORARY_PERMISSION_DENIED,
- String.format("Caller must have the %s permission.", permission));
- default:
- throw new InternalServerError(
- new RuntimeException("Unexpected perimission check result."));
- }
+ mContext.enforceCallingOrSelfPermission(permission,
+ String.format("Caller must have the %s permission.", permission));
}
@Override
diff --git a/services/core/java/com/android/server/stats/pull/StatsPullAtomService.java b/services/core/java/com/android/server/stats/pull/StatsPullAtomService.java
index 612989f76cd3..98579af5835b 100644
--- a/services/core/java/com/android/server/stats/pull/StatsPullAtomService.java
+++ b/services/core/java/com/android/server/stats/pull/StatsPullAtomService.java
@@ -24,6 +24,8 @@ import static android.os.Debug.getIonHeapsSizeKb;
import static android.os.Process.getUidForPid;
import static android.os.storage.VolumeInfo.TYPE_PRIVATE;
import static android.os.storage.VolumeInfo.TYPE_PUBLIC;
+import static android.util.MathUtils.abs;
+import static android.util.MathUtils.constrain;
import static com.android.server.am.MemoryStatUtil.readMemoryStatFromFilesystem;
import static com.android.server.stats.pull.IonMemoryUtil.readProcessSystemIonHeapSizesFromDebugfs;
@@ -146,12 +148,15 @@ import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
+import java.time.Instant;
+import java.time.temporal.ChronoUnit;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.MissingResourceException;
+import java.util.Random;
import java.util.Set;
import java.util.UUID;
import java.util.concurrent.CompletableFuture;
@@ -169,6 +174,9 @@ public class StatsPullAtomService extends SystemService {
private static final String TAG = "StatsPullAtomService";
private static final boolean DEBUG = true;
+ // Random seed stable for StatsPullAtomService life cycle - can be used for stable sampling
+ private static final int RANDOM_SEED = new Random().nextInt();
+
/**
* Lowest available uid for apps.
*
@@ -182,7 +190,7 @@ public class StatsPullAtomService extends SystemService {
* How long to wait on an individual subsystem to return its stats.
*/
private static final long EXTERNAL_STATS_SYNC_TIMEOUT_MILLIS = 2000;
- private static final long NS_PER_SEC = 1000000000;
+ private static final long MILLIS_PER_SEC = 1000;
private static final long MILLI_AMP_HR_TO_NANO_AMP_SECS = 1_000_000L * 3600L;
private static final int MAX_BATTERY_STATS_HELPER_FREQUENCY_MS = 1000;
@@ -256,6 +264,8 @@ public class StatsPullAtomService extends SystemService {
private StatsPullAtomCallbackImpl mStatsCallbackImpl;
+ private int mAppOpsSamplingRate = 0;
+
public StatsPullAtomService(Context context) {
super(context);
mContext = context;
@@ -680,7 +690,7 @@ public class StatsPullAtomService extends SystemService {
PullAtomMetadata metadata = new PullAtomMetadata.Builder()
.setAdditiveFields(new int[] {2, 3, 4, 5})
.build();
- mStatsManager.registerPullAtomCallback(
+ mStatsManager.setPullAtomCallback(
tagId,
metadata,
BackgroundThread.getExecutor(),
@@ -772,7 +782,7 @@ public class StatsPullAtomService extends SystemService {
PullAtomMetadata metadata = new PullAtomMetadata.Builder()
.setAdditiveFields(new int[] {3, 4, 5, 6})
.build();
- mStatsManager.registerPullAtomCallback(
+ mStatsManager.setPullAtomCallback(
tagId,
metadata,
BackgroundThread.getExecutor(),
@@ -810,7 +820,7 @@ public class StatsPullAtomService extends SystemService {
PullAtomMetadata metadata = new PullAtomMetadata.Builder()
.setAdditiveFields(new int[] {2, 3, 4, 5})
.build();
- mStatsManager.registerPullAtomCallback(
+ mStatsManager.setPullAtomCallback(
tagId,
metadata,
BackgroundThread.getExecutor(),
@@ -848,7 +858,7 @@ public class StatsPullAtomService extends SystemService {
PullAtomMetadata metadata = new PullAtomMetadata.Builder()
.setAdditiveFields(new int[] {3, 4, 5, 6})
.build();
- mStatsManager.registerPullAtomCallback(
+ mStatsManager.setPullAtomCallback(
tagId,
metadata,
BackgroundThread.getExecutor(),
@@ -886,7 +896,7 @@ public class StatsPullAtomService extends SystemService {
PullAtomMetadata metadata = new PullAtomMetadata.Builder()
.setAdditiveFields(new int[] {2, 3})
.build();
- mStatsManager.registerPullAtomCallback(
+ mStatsManager.setPullAtomCallback(
tagId,
metadata,
BackgroundThread.getExecutor(),
@@ -955,7 +965,7 @@ public class StatsPullAtomService extends SystemService {
private void registerKernelWakelock() {
int tagId = FrameworkStatsLog.KERNEL_WAKELOCK;
- mStatsManager.registerPullAtomCallback(
+ mStatsManager.setPullAtomCallback(
tagId,
/* PullAtomMetadata */ null,
BackgroundThread.getExecutor(),
@@ -986,7 +996,7 @@ public class StatsPullAtomService extends SystemService {
PullAtomMetadata metadata = new PullAtomMetadata.Builder()
.setAdditiveFields(new int[] {3})
.build();
- mStatsManager.registerPullAtomCallback(
+ mStatsManager.setPullAtomCallback(
tagId,
metadata,
BackgroundThread.getExecutor(),
@@ -1017,7 +1027,7 @@ public class StatsPullAtomService extends SystemService {
PullAtomMetadata metadata = new PullAtomMetadata.Builder()
.setAdditiveFields(new int[] {2, 3})
.build();
- mStatsManager.registerPullAtomCallback(
+ mStatsManager.setPullAtomCallback(
tagId,
metadata,
BackgroundThread.getExecutor(),
@@ -1046,7 +1056,7 @@ public class StatsPullAtomService extends SystemService {
PullAtomMetadata metadata = new PullAtomMetadata.Builder()
.setAdditiveFields(new int[] {4})
.build();
- mStatsManager.registerPullAtomCallback(
+ mStatsManager.setPullAtomCallback(
tagId,
metadata,
BackgroundThread.getExecutor(),
@@ -1078,7 +1088,7 @@ public class StatsPullAtomService extends SystemService {
PullAtomMetadata metadata = new PullAtomMetadata.Builder()
.setAdditiveFields(new int[] {2})
.build();
- mStatsManager.registerPullAtomCallback(
+ mStatsManager.setPullAtomCallback(
tagId,
metadata,
BackgroundThread.getExecutor(),
@@ -1105,7 +1115,7 @@ public class StatsPullAtomService extends SystemService {
PullAtomMetadata metadata = new PullAtomMetadata.Builder()
.setAdditiveFields(new int[] {3})
.build();
- mStatsManager.registerPullAtomCallback(
+ mStatsManager.setPullAtomCallback(
tagId,
metadata,
BackgroundThread.getExecutor(),
@@ -1130,7 +1140,7 @@ public class StatsPullAtomService extends SystemService {
private void registerWifiActivityInfo() {
int tagId = FrameworkStatsLog.WIFI_ACTIVITY_INFO;
- mStatsManager.registerPullAtomCallback(
+ mStatsManager.setPullAtomCallback(
tagId,
null, // use default PullAtomMetadata values
BackgroundThread.getExecutor(),
@@ -1182,7 +1192,7 @@ public class StatsPullAtomService extends SystemService {
private void registerModemActivityInfo() {
int tagId = FrameworkStatsLog.MODEM_ACTIVITY_INFO;
- mStatsManager.registerPullAtomCallback(
+ mStatsManager.setPullAtomCallback(
tagId,
null, // use default PullAtomMetadata values
BackgroundThread.getExecutor(),
@@ -1220,7 +1230,7 @@ public class StatsPullAtomService extends SystemService {
private void registerBluetoothActivityInfo() {
int tagId = FrameworkStatsLog.BLUETOOTH_ACTIVITY_INFO;
- mStatsManager.registerPullAtomCallback(
+ mStatsManager.setPullAtomCallback(
tagId,
/* metadata */ null,
BackgroundThread.getExecutor(),
@@ -1249,10 +1259,10 @@ public class StatsPullAtomService extends SystemService {
private void registerSystemElapsedRealtime() {
int tagId = FrameworkStatsLog.SYSTEM_ELAPSED_REALTIME;
PullAtomMetadata metadata = new PullAtomMetadata.Builder()
- .setCoolDownNs(NS_PER_SEC)
- .setTimeoutNs(NS_PER_SEC / 2)
+ .setCoolDownMillis(MILLIS_PER_SEC)
+ .setTimeoutMillis(MILLIS_PER_SEC / 2)
.build();
- mStatsManager.registerPullAtomCallback(
+ mStatsManager.setPullAtomCallback(
tagId,
metadata,
BackgroundThread.getExecutor(),
@@ -1271,7 +1281,7 @@ public class StatsPullAtomService extends SystemService {
private void registerSystemUptime() {
int tagId = FrameworkStatsLog.SYSTEM_UPTIME;
- mStatsManager.registerPullAtomCallback(
+ mStatsManager.setPullAtomCallback(
tagId,
null, // use default PullAtomMetadata values
BackgroundThread.getExecutor(),
@@ -1293,7 +1303,7 @@ public class StatsPullAtomService extends SystemService {
PullAtomMetadata metadata = new PullAtomMetadata.Builder()
.setAdditiveFields(new int[] {4, 5, 6, 7, 8})
.build();
- mStatsManager.registerPullAtomCallback(
+ mStatsManager.setPullAtomCallback(
tagId,
metadata,
BackgroundThread.getExecutor(),
@@ -1336,7 +1346,7 @@ public class StatsPullAtomService extends SystemService {
private void registerProcessMemoryHighWaterMark() {
int tagId = FrameworkStatsLog.PROCESS_MEMORY_HIGH_WATER_MARK;
- mStatsManager.registerPullAtomCallback(
+ mStatsManager.setPullAtomCallback(
tagId,
null, // use default PullAtomMetadata values
BackgroundThread.getExecutor(),
@@ -1389,7 +1399,7 @@ public class StatsPullAtomService extends SystemService {
private void registerProcessMemorySnapshot() {
int tagId = FrameworkStatsLog.PROCESS_MEMORY_SNAPSHOT;
- mStatsManager.registerPullAtomCallback(
+ mStatsManager.setPullAtomCallback(
tagId,
null, // use default PullAtomMetadata values
BackgroundThread.getExecutor(),
@@ -1449,7 +1459,7 @@ public class StatsPullAtomService extends SystemService {
private void registerSystemIonHeapSize() {
int tagId = FrameworkStatsLog.SYSTEM_ION_HEAP_SIZE;
- mStatsManager.registerPullAtomCallback(
+ mStatsManager.setPullAtomCallback(
tagId,
null, // use default PullAtomMetadata values
BackgroundThread.getExecutor(),
@@ -1472,7 +1482,7 @@ public class StatsPullAtomService extends SystemService {
return;
}
int tagId = FrameworkStatsLog.ION_HEAP_SIZE;
- mStatsManager.registerPullAtomCallback(
+ mStatsManager.setPullAtomCallback(
tagId,
/* PullAtomMetadata */ null,
BackgroundThread.getExecutor(),
@@ -1492,7 +1502,7 @@ public class StatsPullAtomService extends SystemService {
private void registerProcessSystemIonHeapSize() {
int tagId = FrameworkStatsLog.PROCESS_SYSTEM_ION_HEAP_SIZE;
- mStatsManager.registerPullAtomCallback(
+ mStatsManager.setPullAtomCallback(
tagId,
null, // use default PullAtomMetadata values
BackgroundThread.getExecutor(),
@@ -1518,7 +1528,7 @@ public class StatsPullAtomService extends SystemService {
private void registerTemperature() {
int tagId = FrameworkStatsLog.TEMPERATURE;
- mStatsManager.registerPullAtomCallback(
+ mStatsManager.setPullAtomCallback(
tagId,
null, // use default PullAtomMetadata values
BackgroundThread.getExecutor(),
@@ -1556,7 +1566,7 @@ public class StatsPullAtomService extends SystemService {
private void registerCoolingDevice() {
int tagId = FrameworkStatsLog.COOLING_DEVICE;
- mStatsManager.registerPullAtomCallback(
+ mStatsManager.setPullAtomCallback(
tagId,
null, // use default PullAtomMetadata values
BackgroundThread.getExecutor(),
@@ -1596,7 +1606,7 @@ public class StatsPullAtomService extends SystemService {
PullAtomMetadata metadata = new PullAtomMetadata.Builder()
.setAdditiveFields(new int[] {4, 5, 6, 8, 12})
.build();
- mStatsManager.registerPullAtomCallback(
+ mStatsManager.setPullAtomCallback(
tagId,
metadata,
BackgroundThread.getExecutor(),
@@ -1639,7 +1649,7 @@ public class StatsPullAtomService extends SystemService {
private void registerBinderCallsStatsExceptions() {
int tagId = FrameworkStatsLog.BINDER_CALLS_EXCEPTIONS;
- mStatsManager.registerPullAtomCallback(
+ mStatsManager.setPullAtomCallback(
tagId,
null, // use default PullAtomMetadata values
BackgroundThread.getExecutor(),
@@ -1674,7 +1684,7 @@ public class StatsPullAtomService extends SystemService {
PullAtomMetadata metadata = new PullAtomMetadata.Builder()
.setAdditiveFields(new int[] {5, 6, 7, 8, 9})
.build();
- mStatsManager.registerPullAtomCallback(
+ mStatsManager.setPullAtomCallback(
tagId,
metadata,
BackgroundThread.getExecutor(),
@@ -1716,7 +1726,7 @@ public class StatsPullAtomService extends SystemService {
private void registerDiskStats() {
int tagId = FrameworkStatsLog.DISK_STATS;
- mStatsManager.registerPullAtomCallback(
+ mStatsManager.setPullAtomCallback(
tagId,
null, // use default PullAtomMetadata values
BackgroundThread.getExecutor(),
@@ -1782,7 +1792,7 @@ public class StatsPullAtomService extends SystemService {
private void registerDirectoryUsage() {
int tagId = FrameworkStatsLog.DIRECTORY_USAGE;
- mStatsManager.registerPullAtomCallback(
+ mStatsManager.setPullAtomCallback(
tagId,
null, // use default PullAtomMetadata values
BackgroundThread.getExecutor(),
@@ -1823,7 +1833,7 @@ public class StatsPullAtomService extends SystemService {
private void registerAppSize() {
int tagId = FrameworkStatsLog.APP_SIZE;
- mStatsManager.registerPullAtomCallback(
+ mStatsManager.setPullAtomCallback(
tagId,
null, // use default PullAtomMetadata values
BackgroundThread.getExecutor(),
@@ -1867,7 +1877,7 @@ public class StatsPullAtomService extends SystemService {
private void registerCategorySize() {
int tagId = FrameworkStatsLog.CATEGORY_SIZE;
- mStatsManager.registerPullAtomCallback(
+ mStatsManager.setPullAtomCallback(
tagId,
null, // use default PullAtomMetadata values
BackgroundThread.getExecutor(),
@@ -1971,7 +1981,7 @@ public class StatsPullAtomService extends SystemService {
private void registerNumFingerprintsEnrolled() {
int tagId = FrameworkStatsLog.NUM_FINGERPRINTS_ENROLLED;
- mStatsManager.registerPullAtomCallback(
+ mStatsManager.setPullAtomCallback(
tagId,
null, // use default PullAtomMetadata values
BackgroundThread.getExecutor(),
@@ -1981,7 +1991,7 @@ public class StatsPullAtomService extends SystemService {
private void registerNumFacesEnrolled() {
int tagId = FrameworkStatsLog.NUM_FACES_ENROLLED;
- mStatsManager.registerPullAtomCallback(
+ mStatsManager.setPullAtomCallback(
tagId,
null, // use default PullAtomMetadata values
BackgroundThread.getExecutor(),
@@ -2039,7 +2049,7 @@ public class StatsPullAtomService extends SystemService {
private void registerProcStats() {
int tagId = FrameworkStatsLog.PROC_STATS;
- mStatsManager.registerPullAtomCallback(
+ mStatsManager.setPullAtomCallback(
tagId,
null, // use default PullAtomMetadata values
BackgroundThread.getExecutor(),
@@ -2049,7 +2059,7 @@ public class StatsPullAtomService extends SystemService {
private void registerProcStatsPkgProc() {
int tagId = FrameworkStatsLog.PROC_STATS_PKG_PROC;
- mStatsManager.registerPullAtomCallback(
+ mStatsManager.setPullAtomCallback(
tagId,
null, // use default PullAtomMetadata values
BackgroundThread.getExecutor(),
@@ -2120,9 +2130,9 @@ public class StatsPullAtomService extends SystemService {
int tagId = FrameworkStatsLog.DISK_IO;
PullAtomMetadata metadata = new PullAtomMetadata.Builder()
.setAdditiveFields(new int[] {2, 3, 4, 5, 6, 7, 8, 9, 10, 11})
- .setCoolDownNs(3 * NS_PER_SEC)
+ .setCoolDownMillis(3 * MILLIS_PER_SEC)
.build();
- mStatsManager.registerPullAtomCallback(
+ mStatsManager.setPullAtomCallback(
tagId,
metadata,
BackgroundThread.getExecutor(),
@@ -2155,7 +2165,7 @@ public class StatsPullAtomService extends SystemService {
private void registerPowerProfile() {
int tagId = FrameworkStatsLog.POWER_PROFILE;
- mStatsManager.registerPullAtomCallback(
+ mStatsManager.setPullAtomCallback(
tagId,
/* PullAtomMetadata */ null,
BackgroundThread.getExecutor(),
@@ -2180,9 +2190,9 @@ public class StatsPullAtomService extends SystemService {
int tagId = FrameworkStatsLog.PROCESS_CPU_TIME;
// Min cool-down is 5 sec, in line with what ActivityManagerService uses.
PullAtomMetadata metadata = new PullAtomMetadata.Builder()
- .setCoolDownNs(5 * NS_PER_SEC)
+ .setCoolDownMillis(5 * MILLIS_PER_SEC)
.build();
- mStatsManager.registerPullAtomCallback(
+ mStatsManager.setPullAtomCallback(
tagId,
metadata,
BackgroundThread.getExecutor(),
@@ -2217,7 +2227,7 @@ public class StatsPullAtomService extends SystemService {
PullAtomMetadata metadata = new PullAtomMetadata.Builder()
.setAdditiveFields(new int[] {7, 9, 11, 13, 15, 17, 19, 21})
.build();
- mStatsManager.registerPullAtomCallback(
+ mStatsManager.setPullAtomCallback(
tagId,
metadata,
BackgroundThread.getExecutor(),
@@ -2310,7 +2320,7 @@ public class StatsPullAtomService extends SystemService {
private void registerDeviceCalculatedPowerUse() {
int tagId = FrameworkStatsLog.DEVICE_CALCULATED_POWER_USE;
- mStatsManager.registerPullAtomCallback(
+ mStatsManager.setPullAtomCallback(
tagId,
null, // use default PullAtomMetadata values
BackgroundThread.getExecutor(),
@@ -2330,7 +2340,7 @@ public class StatsPullAtomService extends SystemService {
private void registerDeviceCalculatedPowerBlameUid() {
int tagId = FrameworkStatsLog.DEVICE_CALCULATED_POWER_BLAME_UID;
- mStatsManager.registerPullAtomCallback(
+ mStatsManager.setPullAtomCallback(
tagId,
null, // use default PullAtomMetadata values
BackgroundThread.getExecutor(),
@@ -2360,7 +2370,7 @@ public class StatsPullAtomService extends SystemService {
private void registerDeviceCalculatedPowerBlameOther() {
int tagId = FrameworkStatsLog.DEVICE_CALCULATED_POWER_BLAME_OTHER;
- mStatsManager.registerPullAtomCallback(
+ mStatsManager.setPullAtomCallback(
tagId,
null, // use default PullAtomMetadata values
BackgroundThread.getExecutor(),
@@ -2396,7 +2406,7 @@ public class StatsPullAtomService extends SystemService {
PullAtomMetadata metadata = new PullAtomMetadata.Builder()
.setAdditiveFields(new int[] {1, 2, 3, 4})
.build();
- mStatsManager.registerPullAtomCallback(
+ mStatsManager.setPullAtomCallback(
tagId,
metadata,
BackgroundThread.getExecutor(),
@@ -2447,7 +2457,7 @@ public class StatsPullAtomService extends SystemService {
PullAtomMetadata metadata = new PullAtomMetadata.Builder()
.setAdditiveFields(new int[] {1, 2, 3, 4})
.build();
- mStatsManager.registerPullAtomCallback(
+ mStatsManager.setPullAtomCallback(
tagId,
metadata,
BackgroundThread.getExecutor(),
@@ -2485,7 +2495,7 @@ public class StatsPullAtomService extends SystemService {
private void registerBuildInformation() {
int tagId = FrameworkStatsLog.BUILD_INFORMATION;
- mStatsManager.registerPullAtomCallback(
+ mStatsManager.setPullAtomCallback(
tagId,
null, // use default PullAtomMetadata values
BackgroundThread.getExecutor(),
@@ -2512,7 +2522,7 @@ public class StatsPullAtomService extends SystemService {
private void registerRoleHolder() {
int tagId = FrameworkStatsLog.ROLE_HOLDER;
- mStatsManager.registerPullAtomCallback(
+ mStatsManager.setPullAtomCallback(
tagId,
null, // use default PullAtomMetadata values
BackgroundThread.getExecutor(),
@@ -2570,7 +2580,7 @@ public class StatsPullAtomService extends SystemService {
private void registerDangerousPermissionState() {
int tagId = FrameworkStatsLog.DANGEROUS_PERMISSION_STATE;
- mStatsManager.registerPullAtomCallback(
+ mStatsManager.setPullAtomCallback(
tagId,
null, // use default PullAtomMetadata values
BackgroundThread.getExecutor(),
@@ -2660,7 +2670,7 @@ public class StatsPullAtomService extends SystemService {
private void registerTimeZoneDataInfo() {
int tagId = FrameworkStatsLog.TIME_ZONE_DATA_INFO;
- mStatsManager.registerPullAtomCallback(
+ mStatsManager.setPullAtomCallback(
tagId,
null, // use default PullAtomMetadata values
BackgroundThread.getExecutor(),
@@ -2687,7 +2697,7 @@ public class StatsPullAtomService extends SystemService {
private void registerExternalStorageInfo() {
int tagId = FrameworkStatsLog.EXTERNAL_STORAGE_INFO;
- mStatsManager.registerPullAtomCallback(
+ mStatsManager.setPullAtomCallback(
tagId,
null, // use default PullAtomMetadata values
BackgroundThread.getExecutor(),
@@ -2737,7 +2747,7 @@ public class StatsPullAtomService extends SystemService {
private void registerAppsOnExternalStorageInfo() {
int tagId = FrameworkStatsLog.APPS_ON_EXTERNAL_STORAGE_INFO;
- mStatsManager.registerPullAtomCallback(
+ mStatsManager.setPullAtomCallback(
tagId,
null, // use default PullAtomMetadata values
BackgroundThread.getExecutor(),
@@ -2793,7 +2803,7 @@ public class StatsPullAtomService extends SystemService {
private void registerFaceSettings() {
int tagId = FrameworkStatsLog.FACE_SETTINGS;
- mStatsManager.registerPullAtomCallback(
+ mStatsManager.setPullAtomCallback(
tagId,
null, // use default PullAtomMetadata values
BackgroundThread.getExecutor(),
@@ -2847,7 +2857,7 @@ public class StatsPullAtomService extends SystemService {
private void registerAppOps() {
int tagId = FrameworkStatsLog.APP_OPS;
- mStatsManager.registerPullAtomCallback(
+ mStatsManager.setPullAtomCallback(
tagId,
null, // use default PullAtomMetadata values
BackgroundThread.getExecutor(),
@@ -2857,7 +2867,7 @@ public class StatsPullAtomService extends SystemService {
private void registerRuntimeAppOpAccessMessage() {
int tagId = FrameworkStatsLog.RUNTIME_APP_OP_ACCESS;
- mStatsManager.registerPullAtomCallback(
+ mStatsManager.setPullAtomCallback(
tagId,
null, // use default PullAtomMetadata values
BackgroundThread.getExecutor(),
@@ -2877,44 +2887,7 @@ public class StatsPullAtomService extends SystemService {
HistoricalOps histOps = ops.get(EXTERNAL_STATS_SYNC_TIMEOUT_MILLIS,
TimeUnit.MILLISECONDS);
-
- for (int uidIdx = 0; uidIdx < histOps.getUidCount(); uidIdx++) {
- final HistoricalUidOps uidOps = histOps.getUidOpsAt(uidIdx);
- final int uid = uidOps.getUid();
- for (int pkgIdx = 0; pkgIdx < uidOps.getPackageCount(); pkgIdx++) {
- final HistoricalPackageOps packageOps = uidOps.getPackageOpsAt(pkgIdx);
- for (int opIdx = 0; opIdx < packageOps.getOpCount(); opIdx++) {
- final AppOpsManager.HistoricalOp op = packageOps.getOpAt(opIdx);
-
- StatsEvent.Builder e = StatsEvent.newBuilder();
- e.setAtomId(atomTag);
- e.writeInt(uid);
- e.writeString(packageOps.getPackageName());
- e.writeInt(op.getOpCode());
- e.writeLong(op.getForegroundAccessCount(OP_FLAGS_PULLED));
- e.writeLong(op.getBackgroundAccessCount(OP_FLAGS_PULLED));
- e.writeLong(op.getForegroundRejectCount(OP_FLAGS_PULLED));
- e.writeLong(op.getBackgroundRejectCount(OP_FLAGS_PULLED));
- e.writeLong(op.getForegroundAccessDuration(OP_FLAGS_PULLED));
- e.writeLong(op.getBackgroundAccessDuration(OP_FLAGS_PULLED));
-
- String perm = AppOpsManager.opToPermission(op.getOpCode());
- if (perm == null) {
- e.writeBoolean(false);
- } else {
- PermissionInfo permInfo;
- try {
- permInfo = mContext.getPackageManager().getPermissionInfo(perm, 0);
- e.writeBoolean(permInfo.getProtection() == PROTECTION_DANGEROUS);
- } catch (PackageManager.NameNotFoundException exception) {
- e.writeBoolean(false);
- }
- }
-
- pulledData.add(e.build());
- }
- }
- }
+ processHistoricalOps(histOps, atomTag, pulledData);
} catch (Throwable t) {
// TODO: catch exceptions at a more granular level
Slog.e(TAG, "Could not read appops", t);
@@ -2927,7 +2900,7 @@ public class StatsPullAtomService extends SystemService {
private void registerAppFeaturesOps() {
int tagId = FrameworkStatsLog.APP_FEATURES_OPS;
- mStatsManager.registerPullAtomCallback(
+ mStatsManager.setPullAtomCallback(
tagId,
null, // use default PullAtomMetadata values
BackgroundThread.getExecutor(),
@@ -2945,62 +2918,125 @@ public class StatsPullAtomService extends SystemService {
new HistoricalOpsRequest.Builder(0, Long.MAX_VALUE).setFlags(
OP_FLAGS_PULLED).build();
appOps.getHistoricalOps(histOpsRequest, mContext.getMainExecutor(), ops::complete);
-
HistoricalOps histOps = ops.get(EXTERNAL_STATS_SYNC_TIMEOUT_MILLIS,
TimeUnit.MILLISECONDS);
+ if (mAppOpsSamplingRate == 0) {
+ mAppOpsSamplingRate = constrain((5000 * 100) / estimateAppOpsSize(), 1, 100);
+ }
+ processHistoricalOps(histOps, atomTag, pulledData);
+ } catch (Throwable t) {
+ // TODO: catch exceptions at a more granular level
+ Slog.e(TAG, "Could not read appops", t);
+ return StatsManager.PULL_SKIP;
+ } finally {
+ Binder.restoreCallingIdentity(token);
+ }
+ return StatsManager.PULL_SUCCESS;
+ }
- for (int uidIdx = 0; uidIdx < histOps.getUidCount(); uidIdx++) {
- final HistoricalUidOps uidOps = histOps.getUidOpsAt(uidIdx);
- final int uid = uidOps.getUid();
- for (int pkgIdx = 0; pkgIdx < uidOps.getPackageCount(); pkgIdx++) {
- final HistoricalPackageOps packageOps = uidOps.getPackageOpsAt(pkgIdx);
+ private int estimateAppOpsSize() throws Exception {
+ AppOpsManager appOps = mContext.getSystemService(AppOpsManager.class);
+
+ CompletableFuture<HistoricalOps> ops = new CompletableFuture<>();
+ HistoricalOpsRequest histOpsRequest =
+ new HistoricalOpsRequest.Builder(
+ Instant.now().minus(1, ChronoUnit.DAYS).toEpochMilli(),
+ Long.MAX_VALUE).setFlags(
+ OP_FLAGS_PULLED).build();
+ appOps.getHistoricalOps(histOpsRequest, mContext.getMainExecutor(), ops::complete);
+ HistoricalOps histOps = ops.get(EXTERNAL_STATS_SYNC_TIMEOUT_MILLIS,
+ TimeUnit.MILLISECONDS);
+ return processHistoricalOps(histOps, FrameworkStatsLog.APP_FEATURES_OPS, null);
+ }
+
+ int processHistoricalOps(HistoricalOps histOps, int atomTag, List<StatsEvent> pulledData) {
+ int counter = 0;
+ for (int uidIdx = 0; uidIdx < histOps.getUidCount(); uidIdx++) {
+ final HistoricalUidOps uidOps = histOps.getUidOpsAt(uidIdx);
+ final int uid = uidOps.getUid();
+ for (int pkgIdx = 0; pkgIdx < uidOps.getPackageCount(); pkgIdx++) {
+ final HistoricalPackageOps packageOps = uidOps.getPackageOpsAt(pkgIdx);
+ if (atomTag == FrameworkStatsLog.APP_FEATURES_OPS) {
for (int featureIdx = 0; featureIdx < packageOps.getFeatureCount();
featureIdx++) {
final AppOpsManager.HistoricalFeatureOps featureOps =
packageOps.getFeatureOpsAt(featureIdx);
for (int opIdx = 0; opIdx < featureOps.getOpCount(); opIdx++) {
final AppOpsManager.HistoricalOp op = featureOps.getOpAt(opIdx);
- StatsEvent.Builder e = StatsEvent.newBuilder();
- e.setAtomId(atomTag);
- e.writeInt(uid);
- e.writeString(packageOps.getPackageName());
- e.writeString(featureOps.getFeatureId());
- e.writeString(op.getOpName());
- e.writeLong(op.getForegroundAccessCount(OP_FLAGS_PULLED));
- e.writeLong(op.getBackgroundAccessCount(OP_FLAGS_PULLED));
- e.writeLong(op.getForegroundRejectCount(OP_FLAGS_PULLED));
- e.writeLong(op.getBackgroundRejectCount(OP_FLAGS_PULLED));
- e.writeLong(op.getForegroundAccessDuration(OP_FLAGS_PULLED));
- e.writeLong(op.getBackgroundAccessDuration(OP_FLAGS_PULLED));
-
- String perm = AppOpsManager.opToPermission(op.getOpCode());
- if (perm == null) {
- e.writeBoolean(false);
- } else {
- PermissionInfo permInfo;
- try {
- permInfo = mContext.getPackageManager().getPermissionInfo(perm,
- 0);
- e.writeBoolean(
- permInfo.getProtection() == PROTECTION_DANGEROUS);
- } catch (PackageManager.NameNotFoundException exception) {
- e.writeBoolean(false);
- }
- }
- pulledData.add(e.build());
+ counter += processHistoricalOp(op, atomTag, pulledData, uid,
+ packageOps.getPackageName(), featureOps.getFeatureId());
}
-
+ }
+ } else if (atomTag == FrameworkStatsLog.APP_OPS) {
+ for (int opIdx = 0; opIdx < packageOps.getOpCount(); opIdx++) {
+ final AppOpsManager.HistoricalOp op = packageOps.getOpAt(opIdx);
+ counter += processHistoricalOp(op, atomTag, pulledData, uid,
+ packageOps.getPackageName(), null);
}
}
}
- } catch (Throwable t) {
- // TODO: catch exceptions at a more granular level
- Slog.e(TAG, "Could not read appops", t);
- return StatsManager.PULL_SKIP;
- } finally {
- Binder.restoreCallingIdentity(token);
}
- return StatsManager.PULL_SUCCESS;
+ return counter;
+ }
+
+ private int processHistoricalOp(AppOpsManager.HistoricalOp op, int atomTag,
+ @Nullable List<StatsEvent> pulledData, int uid, String packageName,
+ @Nullable String feature) {
+ if (atomTag == FrameworkStatsLog.APP_FEATURES_OPS) {
+ if (pulledData == null) { // this is size estimation call
+ if (op.getForegroundAccessCount(OP_FLAGS_PULLED) + op.getBackgroundAccessCount(
+ OP_FLAGS_PULLED) == 0) {
+ return 0;
+ } else {
+ return 32 + packageName.length() + (feature == null ? 1 : feature.length());
+ }
+ } else {
+ if (abs((op.getOpCode() + feature + packageName).hashCode() + RANDOM_SEED) % 100
+ >= mAppOpsSamplingRate) {
+ return 0;
+ }
+ }
+ }
+
+ StatsEvent.Builder e = StatsEvent.newBuilder();
+ e.setAtomId(atomTag);
+ e.writeInt(uid);
+ e.writeString(packageName);
+ if (atomTag == FrameworkStatsLog.APP_FEATURES_OPS) {
+ e.writeString(feature);
+ }
+ if (atomTag == FrameworkStatsLog.APP_FEATURES_OPS) {
+ e.writeString(op.getOpName());
+ } else {
+ e.writeInt(op.getOpCode());
+ }
+ e.writeLong(op.getForegroundAccessCount(OP_FLAGS_PULLED));
+ e.writeLong(op.getBackgroundAccessCount(OP_FLAGS_PULLED));
+ e.writeLong(op.getForegroundRejectCount(OP_FLAGS_PULLED));
+ e.writeLong(op.getBackgroundRejectCount(OP_FLAGS_PULLED));
+ e.writeLong(op.getForegroundAccessDuration(OP_FLAGS_PULLED));
+ e.writeLong(op.getBackgroundAccessDuration(OP_FLAGS_PULLED));
+
+ String perm = AppOpsManager.opToPermission(op.getOpCode());
+ if (perm == null) {
+ e.writeBoolean(false);
+ } else {
+ PermissionInfo permInfo;
+ try {
+ permInfo = mContext.getPackageManager().getPermissionInfo(
+ perm,
+ 0);
+ e.writeBoolean(
+ permInfo.getProtection() == PROTECTION_DANGEROUS);
+ } catch (PackageManager.NameNotFoundException exception) {
+ e.writeBoolean(false);
+ }
+ }
+ if (atomTag == FrameworkStatsLog.APP_FEATURES_OPS) {
+ e.writeInt(mAppOpsSamplingRate);
+ }
+ pulledData.add(e.build());
+ return 0;
}
int pullRuntimeAppOpAccessMessage(int atomTag, List<StatsEvent> pulledData) {
@@ -3080,7 +3116,7 @@ public class StatsPullAtomService extends SystemService {
private void registerNotificationRemoteViews() {
int tagId = FrameworkStatsLog.NOTIFICATION_REMOTE_VIEWS;
- mStatsManager.registerPullAtomCallback(
+ mStatsManager.setPullAtomCallback(
tagId,
null, // use default PullAtomMetadata values
BackgroundThread.getExecutor(),
@@ -3124,7 +3160,7 @@ public class StatsPullAtomService extends SystemService {
private void registerDangerousPermissionStateSampled() {
int tagId = FrameworkStatsLog.DANGEROUS_PERMISSION_STATE_SAMPLED;
- mStatsManager.registerPullAtomCallback(
+ mStatsManager.setPullAtomCallback(
tagId,
null, // use default PullAtomMetadata values
BackgroundThread.getExecutor(),
@@ -3134,7 +3170,7 @@ public class StatsPullAtomService extends SystemService {
private void registerBatteryLevel() {
int tagId = FrameworkStatsLog.BATTERY_LEVEL;
- mStatsManager.registerPullAtomCallback(
+ mStatsManager.setPullAtomCallback(
tagId,
null, // use default PullAtomMetadata values
BackgroundThread.getExecutor(),
@@ -3144,7 +3180,7 @@ public class StatsPullAtomService extends SystemService {
private void registerRemainingBatteryCapacity() {
int tagId = FrameworkStatsLog.REMAINING_BATTERY_CAPACITY;
- mStatsManager.registerPullAtomCallback(
+ mStatsManager.setPullAtomCallback(
tagId,
null, // use default PullAtomMetadata values
BackgroundThread.getExecutor(),
@@ -3154,7 +3190,7 @@ public class StatsPullAtomService extends SystemService {
private void registerFullBatteryCapacity() {
int tagId = FrameworkStatsLog.FULL_BATTERY_CAPACITY;
- mStatsManager.registerPullAtomCallback(
+ mStatsManager.setPullAtomCallback(
tagId,
null, // use default PullAtomMetadata values
BackgroundThread.getExecutor(),
@@ -3164,7 +3200,7 @@ public class StatsPullAtomService extends SystemService {
private void registerBatteryVoltage() {
int tagId = FrameworkStatsLog.BATTERY_VOLTAGE;
- mStatsManager.registerPullAtomCallback(
+ mStatsManager.setPullAtomCallback(
tagId,
null, // use default PullAtomMetadata values
BackgroundThread.getExecutor(),
@@ -3174,7 +3210,7 @@ public class StatsPullAtomService extends SystemService {
private void registerBatteryCycleCount() {
int tagId = FrameworkStatsLog.BATTERY_CYCLE_COUNT;
- mStatsManager.registerPullAtomCallback(
+ mStatsManager.setPullAtomCallback(
tagId,
null, // use default PullAtomMetadata values
BackgroundThread.getExecutor(),
diff --git a/services/core/java/com/android/server/statusbar/StatusBarManagerService.java b/services/core/java/com/android/server/statusbar/StatusBarManagerService.java
index feb3e06c172e..84cd4cfd67be 100644
--- a/services/core/java/com/android/server/statusbar/StatusBarManagerService.java
+++ b/services/core/java/com/android/server/statusbar/StatusBarManagerService.java
@@ -60,6 +60,7 @@ import com.android.internal.statusbar.StatusBarIcon;
import com.android.internal.util.DumpUtils;
import com.android.internal.view.AppearanceRegion;
import com.android.server.LocalServices;
+import com.android.server.UiThread;
import com.android.server.notification.NotificationDelegate;
import com.android.server.policy.GlobalActionsProvider;
import com.android.server.power.ShutdownThread;
@@ -1118,7 +1119,7 @@ public class StatusBarManagerService extends IStatusBarService.Stub implements D
}
private void notifyBarAttachChanged() {
- mHandler.post(() -> {
+ UiThread.getHandler().post(() -> {
if (mGlobalActionListener == null) return;
mGlobalActionListener.onGlobalActionsAvailableChanged(mBar != null);
});
diff --git a/services/core/java/com/android/server/timezonedetector/TimeZoneDetectorCallbackImpl.java b/services/core/java/com/android/server/timezonedetector/TimeZoneDetectorCallbackImpl.java
index 2520316b5d54..35194658a48f 100644
--- a/services/core/java/com/android/server/timezonedetector/TimeZoneDetectorCallbackImpl.java
+++ b/services/core/java/com/android/server/timezonedetector/TimeZoneDetectorCallbackImpl.java
@@ -20,6 +20,7 @@ import android.annotation.Nullable;
import android.app.AlarmManager;
import android.content.ContentResolver;
import android.content.Context;
+import android.net.ConnectivityManager;
import android.os.SystemProperties;
import android.provider.Settings;
@@ -40,7 +41,20 @@ public final class TimeZoneDetectorCallbackImpl implements TimeZoneDetectorStrat
@Override
public boolean isAutoTimeZoneDetectionEnabled() {
- return Settings.Global.getInt(mCr, Settings.Global.AUTO_TIME_ZONE, 1 /* default */) > 0;
+ if (isAutoTimeZoneDetectionSupported()) {
+ return Settings.Global.getInt(mCr, Settings.Global.AUTO_TIME_ZONE, 1 /* default */) > 0;
+ }
+ return false;
+ }
+
+ private boolean isAutoTimeZoneDetectionSupported() {
+ return deviceHasTelephonyNetwork();
+ }
+
+ private boolean deviceHasTelephonyNetwork() {
+ // TODO b/150583524 Avoid the use of a deprecated API.
+ return mContext.getSystemService(ConnectivityManager.class)
+ .isNetworkSupported(ConnectivityManager.TYPE_MOBILE);
}
@Override
diff --git a/services/core/java/com/android/server/tv/TvRemoteProviderWatcher.java b/services/core/java/com/android/server/tv/TvRemoteProviderWatcher.java
index cddcabe80f33..06c2354c7a7d 100644
--- a/services/core/java/com/android/server/tv/TvRemoteProviderWatcher.java
+++ b/services/core/java/com/android/server/tv/TvRemoteProviderWatcher.java
@@ -30,6 +30,8 @@ import android.os.UserHandle;
import android.util.Log;
import android.util.Slog;
+import com.android.internal.annotations.VisibleForTesting;
+
import java.util.ArrayList;
import java.util.Collections;
@@ -140,7 +142,8 @@ final class TvRemoteProviderWatcher {
}
}
- private boolean verifyServiceTrusted(ServiceInfo serviceInfo) {
+ @VisibleForTesting
+ boolean verifyServiceTrusted(ServiceInfo serviceInfo) {
if (serviceInfo.permission == null || !serviceInfo.permission.equals(
Manifest.permission.BIND_TV_REMOTE_SERVICE)) {
// If the service does not require this permission then any app could
diff --git a/services/core/java/com/android/server/tv/tunerresourcemanager/ClientProfile.java b/services/core/java/com/android/server/tv/tunerresourcemanager/ClientProfile.java
index 4eff954f1ec8..e100ff816f00 100644
--- a/services/core/java/com/android/server/tv/tunerresourcemanager/ClientProfile.java
+++ b/services/core/java/com/android/server/tv/tunerresourcemanager/ClientProfile.java
@@ -15,8 +15,8 @@
*/
package com.android.server.tv.tunerresourcemanager;
-import java.util.ArrayList;
-import java.util.List;
+import java.util.HashSet;
+import java.util.Set;
/**
* A client profile object used by the Tuner Resource Manager to record the registered clients'
@@ -65,7 +65,7 @@ public final class ClientProfile {
/**
* List of the frontend ids that are used by the current client.
*/
- private List<Integer> mUsingFrontendIds = new ArrayList<>();
+ private Set<Integer> mUsingFrontendIds = new HashSet<>();
/**
* Optional arbitrary priority value given by the client.
@@ -131,7 +131,7 @@ public final class ClientProfile {
mUsingFrontendIds.add(frontendId);
}
- public List<Integer> getInUseFrontendIds() {
+ public Iterable<Integer> getInUseFrontendIds() {
return mUsingFrontendIds;
}
diff --git a/services/core/java/com/android/server/tv/tunerresourcemanager/FrontendResource.java b/services/core/java/com/android/server/tv/tunerresourcemanager/FrontendResource.java
index a109265e2f50..56f61599c998 100644
--- a/services/core/java/com/android/server/tv/tunerresourcemanager/FrontendResource.java
+++ b/services/core/java/com/android/server/tv/tunerresourcemanager/FrontendResource.java
@@ -15,12 +15,11 @@
*/
package com.android.server.tv.tunerresourcemanager;
-import android.annotation.Nullable;
import android.media.tv.tuner.frontend.FrontendSettings.Type;
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.List;
+import java.util.Collection;
+import java.util.HashSet;
+import java.util.Set;
/**
* A frontend resource object used by the Tuner Resource Manager to record the tuner frontend
@@ -50,7 +49,7 @@ public final class FrontendResource {
/**
* An array to save all the FE ids under the same exclisive group.
*/
- private List<Integer> mExclusiveGroupMemberFeIds = new ArrayList<>();
+ private Set<Integer> mExclusiveGroupMemberFeIds = new HashSet<>();
/**
* If the current resource is in use. Once resources under the same exclusive group id is in use
@@ -82,12 +81,12 @@ public final class FrontendResource {
return mExclusiveGroupId;
}
- public List<Integer> getExclusiveGroupMemberFeIds() {
+ public Set<Integer> getExclusiveGroupMemberFeIds() {
return mExclusiveGroupMemberFeIds;
}
/**
- * Add one id into the exclusive group member id list.
+ * Add one id into the exclusive group member id collection.
*
* @param id the id to be added.
*/
@@ -96,21 +95,21 @@ public final class FrontendResource {
}
/**
- * Add one id list to the exclusive group member id list.
+ * Add one id collection to the exclusive group member id collection.
*
- * @param ids the id list to be added.
+ * @param ids the id collection to be added.
*/
- public void addExclusiveGroupMemberFeId(List<Integer> ids) {
+ public void addExclusiveGroupMemberFeIds(Collection<Integer> ids) {
mExclusiveGroupMemberFeIds.addAll(ids);
}
/**
- * Remove one id from the exclusive group member id list.
+ * Remove one id from the exclusive group member id collection.
*
* @param id the id to be removed.
*/
public void removeExclusiveGroupMemberFeId(int id) {
- mExclusiveGroupMemberFeIds.remove(new Integer(id));
+ mExclusiveGroupMemberFeIds.remove(id);
}
public boolean isInUse() {
@@ -143,22 +142,10 @@ public final class FrontendResource {
public String toString() {
return "FrontendResource[id=" + this.mId + ", type=" + this.mType
+ ", exclusiveGId=" + this.mExclusiveGroupId + ", exclusiveGMemeberIds="
- + Arrays.toString(this.mExclusiveGroupMemberFeIds.toArray())
+ + this.mExclusiveGroupMemberFeIds
+ ", isInUse=" + this.mIsInUse + ", ownerClientId=" + this.mOwnerClientId + "]";
}
- @Override
- public boolean equals(@Nullable Object o) {
- if (o instanceof FrontendResource) {
- FrontendResource fe = (FrontendResource) o;
- return mId == fe.getId() && mType == fe.getType()
- && mExclusiveGroupId == fe.getExclusiveGroupId()
- && mExclusiveGroupMemberFeIds.equals(fe.getExclusiveGroupMemberFeIds())
- && mIsInUse == fe.isInUse() && mOwnerClientId == fe.getOwnerClientId();
- }
- return false;
- }
-
/**
* Builder class for {@link FrontendResource}.
*/
diff --git a/services/core/java/com/android/server/tv/tunerresourcemanager/TunerResourceManagerService.java b/services/core/java/com/android/server/tv/tunerresourcemanager/TunerResourceManagerService.java
index cb31a502ecfa..04d551d0f84e 100644
--- a/services/core/java/com/android/server/tv/tunerresourcemanager/TunerResourceManagerService.java
+++ b/services/core/java/com/android/server/tv/tunerresourcemanager/TunerResourceManagerService.java
@@ -29,16 +29,19 @@ import android.media.tv.tunerresourcemanager.TunerFrontendRequest;
import android.media.tv.tunerresourcemanager.TunerLnbRequest;
import android.media.tv.tunerresourcemanager.TunerResourceManager;
import android.os.Binder;
+import android.os.IBinder;
import android.os.RemoteException;
import android.util.Log;
import android.util.Slog;
-import android.util.SparseArray;
+import com.android.internal.annotations.GuardedBy;
import com.android.internal.annotations.VisibleForTesting;
import com.android.server.SystemService;
-import java.util.ArrayList;
-import java.util.List;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Map;
+import java.util.Set;
/**
* This class provides a system service that manages the TV tuner resources.
@@ -52,18 +55,15 @@ public class TunerResourceManagerService extends SystemService {
public static final int INVALID_CLIENT_ID = -1;
private static final int MAX_CLIENT_PRIORITY = 1000;
- // Array of the registered client profiles
- @VisibleForTesting private SparseArray<ClientProfile> mClientProfiles = new SparseArray<>();
+ // Map of the registered client profiles
+ private Map<Integer, ClientProfile> mClientProfiles = new HashMap<>();
private int mNextUnusedClientId = 0;
- private List<Integer> mRegisteredClientIds = new ArrayList<Integer>();
- // Array of the current available frontend resources
- @VisibleForTesting
- private SparseArray<FrontendResource> mFrontendResources = new SparseArray<>();
- // Array of the current available frontend ids
- private List<Integer> mAvailableFrontendIds = new ArrayList<Integer>();
+ // Map of the current available frontend resources
+ private Map<Integer, FrontendResource> mFrontendResources = new HashMap<>();
- private SparseArray<IResourcesReclaimListener> mListeners = new SparseArray<>();
+ @GuardedBy("mLock")
+ private Map<Integer, ResourcesReclaimListenerRecord> mListeners = new HashMap<>();
private TvInputManager mManager;
private UseCasePriorityHints mPriorityCongfig = new UseCasePriorityHints();
@@ -103,6 +103,10 @@ public class TunerResourceManagerService extends SystemService {
throw new RemoteException("clientId can't be null!");
}
+ if (listener == null) {
+ throw new RemoteException("IResourcesReclaimListener can't be null!");
+ }
+
if (!mPriorityCongfig.isDefinedUseCase(profile.getUseCase())) {
throw new RemoteException("Use undefined client use case:" + profile.getUseCase());
}
@@ -261,9 +265,7 @@ public class TunerResourceManagerService extends SystemService {
.build();
clientProfile.setPriority(getClientPriority(profile.getUseCase(), pid));
- mClientProfiles.append(clientId[0], clientProfile);
- mListeners.append(clientId[0], listener);
- mRegisteredClientIds.add(clientId[0]);
+ addClientProfile(clientId[0], clientProfile, listener);
}
@VisibleForTesting
@@ -271,15 +273,7 @@ public class TunerResourceManagerService extends SystemService {
if (DEBUG) {
Slog.d(TAG, "unregisterClientProfile(clientId=" + clientId + ")");
}
- for (int id : getClientProfile(clientId).getInUseFrontendIds()) {
- getFrontendResource(id).removeOwner();
- for (int groupMemberId : getFrontendResource(id).getExclusiveGroupMemberFeIds()) {
- getFrontendResource(groupMemberId).removeOwner();
- }
- }
- mClientProfiles.remove(clientId);
- mListeners.remove(clientId);
- mRegisteredClientIds.remove(clientId);
+ removeClientProfile(clientId);
}
@VisibleForTesting
@@ -313,56 +307,32 @@ public class TunerResourceManagerService extends SystemService {
}
}
- // An arrayList to record the frontends pending on updating. Ids will be removed
- // from this list once its updating finished. Any frontend left in this list when all
- // the updates are done will be removed from mAvailableFrontendIds and
- // mFrontendResources.
- List<Integer> updatingFrontendIds = new ArrayList<>(mAvailableFrontendIds);
+ // A set to record the frontends pending on updating. Ids will be removed
+ // from this set once its updating finished. Any frontend left in this set when all
+ // the updates are done will be removed from mFrontendResources.
+ Set<Integer> updatingFrontendIds = new HashSet<>(getFrontendResources().keySet());
- // Update frontendResources sparse array and other mappings accordingly
+ // Update frontendResources map and other mappings accordingly
for (int i = 0; i < infos.length; i++) {
if (getFrontendResource(infos[i].getId()) != null) {
if (DEBUG) {
Slog.d(TAG, "Frontend id=" + infos[i].getId() + "exists.");
}
- updatingFrontendIds.remove(new Integer(infos[i].getId()));
+ updatingFrontendIds.remove(infos[i].getId());
} else {
// Add a new fe resource
FrontendResource newFe = new FrontendResource.Builder(infos[i].getId())
.type(infos[i].getFrontendType())
.exclusiveGroupId(infos[i].getExclusiveGroupId())
.build();
- // Update the exclusive group member list in all the existing Frontend resource
- for (Integer feId : mAvailableFrontendIds) {
- FrontendResource fe = getFrontendResource(feId.intValue());
- if (fe.getExclusiveGroupId() == newFe.getExclusiveGroupId()) {
- newFe.addExclusiveGroupMemberFeId(fe.getId());
- newFe.addExclusiveGroupMemberFeId(fe.getExclusiveGroupMemberFeIds());
- for (Integer excGroupmemberFeId : fe.getExclusiveGroupMemberFeIds()) {
- getFrontendResource(excGroupmemberFeId.intValue())
- .addExclusiveGroupMemberFeId(newFe.getId());
- }
- fe.addExclusiveGroupMemberFeId(newFe.getId());
- break;
- }
- }
- // Update resource list and available id list
- mFrontendResources.append(newFe.getId(), newFe);
- mAvailableFrontendIds.add(newFe.getId());
+ addFrontendResource(newFe);
}
}
// TODO check if the removing resource is in use or not. Handle the conflict.
- for (Integer removingId : updatingFrontendIds) {
- // update the exclusive group id memver list
- FrontendResource fe = getFrontendResource(removingId.intValue());
- fe.removeExclusiveGroupMemberFeId(new Integer(fe.getId()));
- for (Integer excGroupmemberFeId : fe.getExclusiveGroupMemberFeIds()) {
- getFrontendResource(excGroupmemberFeId.intValue())
- .removeExclusiveGroupMemberFeId(new Integer(fe.getId()));
- }
- mFrontendResources.remove(removingId.intValue());
- mAvailableFrontendIds.remove(removingId);
+ for (int removingId : updatingFrontendIds) {
+ // update the exclusive group id member list
+ removeFrontendResource(removingId);
}
}
@@ -383,25 +353,24 @@ public class TunerResourceManagerService extends SystemService {
int inUseLowestPriorityFrId = -1;
// Priority max value is 1000
int currentLowestPriority = MAX_CLIENT_PRIORITY + 1;
- for (int id : mAvailableFrontendIds) {
- FrontendResource fr = getFrontendResource(id);
+ for (FrontendResource fr : getFrontendResources().values()) {
if (fr.getType() == request.getFrontendType()) {
if (!fr.isInUse()) {
// Grant unused frontend with no exclusive group members first.
- if (fr.getExclusiveGroupMemberFeIds().size() == 0) {
- grantingFrontendId = id;
+ if (fr.getExclusiveGroupMemberFeIds().isEmpty()) {
+ grantingFrontendId = fr.getId();
break;
} else if (grantingFrontendId < 0) {
// Grant the unused frontend with lower id first if all the unused
// frontends have exclusive group members.
- grantingFrontendId = id;
+ grantingFrontendId = fr.getId();
}
} else if (grantingFrontendId < 0) {
// Record the frontend id with the lowest client priority among all the
// in use frontends when no available frontend has been found.
- int priority = getOwnerClientPriority(id);
+ int priority = getOwnerClientPriority(fr);
if (currentLowestPriority > priority) {
- inUseLowestPriorityFrId = id;
+ inUseLowestPriorityFrId = fr.getId();
currentLowestPriority = priority;
}
}
@@ -428,6 +397,62 @@ public class TunerResourceManagerService extends SystemService {
}
@VisibleForTesting
+ protected class ResourcesReclaimListenerRecord implements IBinder.DeathRecipient {
+ private final IResourcesReclaimListener mListener;
+ private final int mClientId;
+
+ public ResourcesReclaimListenerRecord(IResourcesReclaimListener listener, int clientId) {
+ mListener = listener;
+ mClientId = clientId;
+ }
+
+ @Override
+ public void binderDied() {
+ synchronized (mLock) {
+ removeClientProfile(mClientId);
+ }
+ }
+
+ public int getId() {
+ return mClientId;
+ }
+
+ public IResourcesReclaimListener getListener() {
+ return mListener;
+ }
+ }
+
+ private void addResourcesReclaimListener(int clientId, IResourcesReclaimListener listener) {
+ if (listener == null) {
+ if (DEBUG) {
+ Slog.w(TAG, "Listener is null when client " + clientId + " registered!");
+ }
+ return;
+ }
+
+ ResourcesReclaimListenerRecord record =
+ new ResourcesReclaimListenerRecord(listener, clientId);
+
+ try {
+ listener.asBinder().linkToDeath(record, 0);
+ } catch (RemoteException e) {
+ Slog.w(TAG, "Listener already died.");
+ return;
+ }
+
+ mListeners.put(clientId, record);
+ }
+
+ @VisibleForTesting
+ protected void reclaimFrontendResource(int reclaimingId) {
+ try {
+ mListeners.get(reclaimingId).getListener().onReclaimResources();
+ } catch (RemoteException e) {
+ Slog.e(TAG, "Failed to reclaim resources on client " + reclaimingId, e);
+ }
+ }
+
+ @VisibleForTesting
protected int getClientPriority(int useCase, int pid) {
if (DEBUG) {
Slog.d(TAG, "getClientPriority useCase=" + useCase
@@ -446,17 +471,6 @@ public class TunerResourceManagerService extends SystemService {
return true;
}
- @VisibleForTesting
- protected void reclaimFrontendResource(int reclaimingId) throws RemoteException {
- if (mListeners.get(reclaimingId) != null) {
- try {
- mListeners.get(reclaimingId).onReclaimResources();
- } catch (RemoteException e) {
- throw e.rethrowFromSystemServer();
- }
- }
- }
-
private void updateFrontendClientMappingOnNewGrant(int grantingId, int ownerClientId) {
FrontendResource grantingFrontend = getFrontendResource(grantingId);
ClientProfile ownerProfile = getClientProfile(ownerClientId);
@@ -471,33 +485,77 @@ public class TunerResourceManagerService extends SystemService {
/**
* Get the owner client's priority from the frontend id.
*
- * @param frontendId an in use frontend id.
+ * @param frontend an in use frontend.
* @return the priority of the owner client of the frontend.
*/
- private int getOwnerClientPriority(int frontendId) {
- return getClientProfile(getFrontendResource(frontendId).getOwnerClientId()).getPriority();
- }
-
- private ClientProfile getClientProfile(int clientId) {
- return mClientProfiles.get(clientId);
+ private int getOwnerClientPriority(FrontendResource frontend) {
+ return getClientProfile(frontend.getOwnerClientId()).getPriority();
}
+ @VisibleForTesting
+ @Nullable
protected FrontendResource getFrontendResource(int frontendId) {
return mFrontendResources.get(frontendId);
}
@VisibleForTesting
- protected SparseArray<ClientProfile> getClientProfiles() {
- return mClientProfiles;
+ protected Map<Integer, FrontendResource> getFrontendResources() {
+ return mFrontendResources;
+ }
+
+ private void addFrontendResource(FrontendResource newFe) {
+ // Update the exclusive group member list in all the existing Frontend resource
+ for (FrontendResource fe : getFrontendResources().values()) {
+ if (fe.getExclusiveGroupId() == newFe.getExclusiveGroupId()) {
+ newFe.addExclusiveGroupMemberFeId(fe.getId());
+ newFe.addExclusiveGroupMemberFeIds(fe.getExclusiveGroupMemberFeIds());
+ for (int excGroupmemberFeId : fe.getExclusiveGroupMemberFeIds()) {
+ getFrontendResource(excGroupmemberFeId)
+ .addExclusiveGroupMemberFeId(newFe.getId());
+ }
+ fe.addExclusiveGroupMemberFeId(newFe.getId());
+ break;
+ }
+ }
+ // Update resource list and available id list
+ mFrontendResources.put(newFe.getId(), newFe);
+ }
+
+ private void removeFrontendResource(int removingId) {
+ FrontendResource fe = getFrontendResource(removingId);
+ for (int excGroupmemberFeId : fe.getExclusiveGroupMemberFeIds()) {
+ getFrontendResource(excGroupmemberFeId)
+ .removeExclusiveGroupMemberFeId(fe.getId());
+ }
+ mFrontendResources.remove(removingId);
}
@VisibleForTesting
- protected SparseArray<FrontendResource> getFrontendResources() {
- return mFrontendResources;
+ @Nullable
+ protected ClientProfile getClientProfile(int clientId) {
+ return mClientProfiles.get(clientId);
+ }
+
+ private void addClientProfile(int clientId, ClientProfile profile,
+ IResourcesReclaimListener listener) {
+ mClientProfiles.put(clientId, profile);
+ addResourcesReclaimListener(clientId, listener);
}
- private boolean checkClientExists(int clientId) {
- return mRegisteredClientIds.contains(clientId);
+ private void removeClientProfile(int clientId) {
+ for (int id : getClientProfile(clientId).getInUseFrontendIds()) {
+ getFrontendResource(id).removeOwner();
+ for (int groupMemberId : getFrontendResource(id).getExclusiveGroupMemberFeIds()) {
+ getFrontendResource(groupMemberId).removeOwner();
+ }
+ }
+ mClientProfiles.remove(clientId);
+ mListeners.remove(clientId);
+ }
+
+ @VisibleForTesting
+ protected boolean checkClientExists(int clientId) {
+ return mClientProfiles.keySet().contains(clientId);
}
private void enforceAccessPermission() {
diff --git a/services/core/java/com/android/server/tv/tunerresourcemanager/UseCasePriorityHints.java b/services/core/java/com/android/server/tv/tunerresourcemanager/UseCasePriorityHints.java
index 8c2de475b99b..367b966a46ed 100644
--- a/services/core/java/com/android/server/tv/tunerresourcemanager/UseCasePriorityHints.java
+++ b/services/core/java/com/android/server/tv/tunerresourcemanager/UseCasePriorityHints.java
@@ -31,8 +31,8 @@ import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
-import java.util.ArrayList;
-import java.util.List;
+import java.util.HashSet;
+import java.util.Set;
/**
* This class provides the Tuner Resource Manager use case priority hints config info including a
@@ -56,7 +56,7 @@ public class UseCasePriorityHints {
*/
SparseArray<int[]> mPriorityHints = new SparseArray<>();
- List<Integer> mVendorDefinedUseCase = new ArrayList<>();
+ Set<Integer> mVendorDefinedUseCase = new HashSet<>();
private int mDefaultForeground = 150;
private int mDefaultBackground = 50;
diff --git a/services/core/java/com/android/server/updates/ConfigUpdateInstallReceiver.java b/services/core/java/com/android/server/updates/ConfigUpdateInstallReceiver.java
index 73bb4bf956c3..948439da4863 100644
--- a/services/core/java/com/android/server/updates/ConfigUpdateInstallReceiver.java
+++ b/services/core/java/com/android/server/updates/ConfigUpdateInstallReceiver.java
@@ -20,6 +20,7 @@ import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.net.Uri;
+import android.os.Binder;
import android.util.EventLog;
import android.util.Slog;
@@ -134,7 +135,12 @@ public class ConfigUpdateInstallReceiver extends BroadcastReceiver {
private BufferedInputStream getAltContent(Context c, Intent i) throws IOException {
Uri content = getContentFromIntent(i);
- return new BufferedInputStream(c.getContentResolver().openInputStream(content));
+ Binder.allowBlockingForCurrentThread();
+ try {
+ return new BufferedInputStream(c.getContentResolver().openInputStream(content));
+ } finally {
+ Binder.defaultBlockingForCurrentThread();
+ }
}
private byte[] getCurrentContent() {
diff --git a/services/core/java/com/android/server/wm/AccessibilityController.java b/services/core/java/com/android/server/wm/AccessibilityController.java
index 61a33b4fb781..68224b59a287 100644
--- a/services/core/java/com/android/server/wm/AccessibilityController.java
+++ b/services/core/java/com/android/server/wm/AccessibilityController.java
@@ -27,7 +27,6 @@ import static com.android.server.wm.utils.RegionUtils.forEachRect;
import android.animation.ObjectAnimator;
import android.animation.ValueAnimator;
import android.annotation.NonNull;
-import android.app.Service;
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
@@ -127,7 +126,7 @@ final class AccessibilityController {
public boolean setWindowsForAccessibilityCallbackLocked(int displayId,
WindowsForAccessibilityCallback callback) {
if (callback != null) {
- final DisplayContent dc = mService.mRoot.getDisplayContent(displayId);
+ final DisplayContent dc = mService.mRoot.getDisplayContentOrCreate(displayId);
if (dc == null) {
return false;
}
@@ -1392,7 +1391,7 @@ final class AccessibilityController {
tempWindowStatesList.add(w);
}
}, false /* traverseTopToBottom */);
- // Insert the re-parented windows in another display on top of their parents in
+ // Insert the re-parented windows in another display below their parents in
// default display.
mService.mRoot.forAllWindows(w -> {
final WindowState parentWindow = findRootDisplayParentWindow(w);
diff --git a/services/core/java/com/android/server/wm/ActivityRecord.java b/services/core/java/com/android/server/wm/ActivityRecord.java
index 76bc36620c85..b6ad24184803 100644
--- a/services/core/java/com/android/server/wm/ActivityRecord.java
+++ b/services/core/java/com/android/server/wm/ActivityRecord.java
@@ -200,6 +200,7 @@ import static com.android.server.wm.TaskPersister.IMAGE_EXTENSION;
import static com.android.server.wm.WindowContainer.AnimationFlags.CHILDREN;
import static com.android.server.wm.WindowContainer.AnimationFlags.PARENTS;
import static com.android.server.wm.WindowContainer.AnimationFlags.TRANSITION;
+import static com.android.server.wm.WindowContainerChildProto.ACTIVITY;
import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_ANIM;
import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_LAYOUT_REPEATS;
import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_STARTING_WINDOW_VERBOSE;
@@ -3150,7 +3151,7 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A
// Reset the last saved PiP snap fraction on removal.
mDisplayContent.mPinnedStackControllerLocked.resetReentryBounds(mActivityComponent);
-
+ mWmService.mEmbeddedWindowController.onActivityRemoved(this);
mRemovingFromDisplay = false;
}
@@ -6187,10 +6188,12 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A
/**
* @return {@code true} if this activity is in size compatibility mode that uses the different
- * density or bounds from its parent.
+ * density than its parent or its bounds don't fit in parent naturally.
*/
boolean inSizeCompatMode() {
- if (mCompatDisplayInsets == null || !shouldUseSizeCompatMode()) {
+ if (mCompatDisplayInsets == null || !shouldUseSizeCompatMode()
+ // The orientation is different from parent when transforming.
+ || isFixedRotationTransforming()) {
return false;
}
final Rect appBounds = getConfiguration().windowConfiguration.getAppBounds();
@@ -6228,8 +6231,8 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A
// The rest of the condition is that only one side is smaller than the parent, but it still
// needs to exclude the cases where the size is limited by the fixed aspect ratio.
if (info.maxAspectRatio > 0) {
- final float aspectRatio =
- (float) Math.max(appWidth, appHeight) / Math.min(appWidth, appHeight);
+ final float aspectRatio = (0.5f + Math.max(appWidth, appHeight))
+ / Math.min(appWidth, appHeight);
if (aspectRatio >= info.maxAspectRatio) {
// The current size has reached the max aspect ratio.
return false;
@@ -6309,26 +6312,25 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A
}
// The role of CompatDisplayInsets is like the override bounds.
- final DisplayContent display = getDisplay();
- if (display != null) {
- mCompatDisplayInsets = new CompatDisplayInsets(display.mDisplayContent,
- getWindowConfiguration().getBounds(),
- getWindowConfiguration().tasksAreFloating());
- }
+ mCompatDisplayInsets = new CompatDisplayInsets(mDisplayContent, this);
}
- private void clearSizeCompatMode() {
+ @VisibleForTesting
+ void clearSizeCompatMode() {
+ mSizeCompatScale = 1f;
+ mSizeCompatBounds = null;
mCompatDisplayInsets = null;
onRequestedOverrideConfigurationChanged(EMPTY);
}
@Override
public boolean matchParentBounds() {
- if (super.matchParentBounds()) {
+ if (super.matchParentBounds() && mCompatDisplayInsets == null) {
return true;
}
- // An activity in size compatibility mode may have override bounds which equals to its
- // parent bounds, so the exact bounds should also be checked.
+ // An activity in size compatibility mode may have resolved override bounds, so the exact
+ // bounds should also be checked. Otherwise IME window will show with offset. See
+ // {@link DisplayContent#isImeAttachedToApp}.
final WindowContainer parent = getParent();
return parent == null || parent.getBounds().equals(getResolvedOverrideBounds());
}
@@ -6348,7 +6350,8 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A
// can use the resolved configuration directly. Otherwise (e.g. fixed aspect ratio),
// the rotated configuration is used as parent configuration to compute the actual
// resolved configuration. It is like putting the activity in a rotated container.
- mTmpConfig.setTo(resolvedConfig);
+ mTmpConfig.setTo(newParentConfiguration);
+ mTmpConfig.updateFrom(resolvedConfig);
newParentConfiguration = mTmpConfig;
}
if (mCompatDisplayInsets != null) {
@@ -6356,17 +6359,31 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A
} else {
// We ignore activities' requested orientation in multi-window modes. Task level may
// take them into consideration when calculating bounds.
- if (getParent() != null && getParent().inMultiWindowMode()) {
+ if (inMultiWindowMode()) {
resolvedConfig.orientation = Configuration.ORIENTATION_UNDEFINED;
}
- applyAspectRatio(resolvedConfig.windowConfiguration.getBounds(),
- newParentConfiguration.windowConfiguration.getAppBounds(),
- newParentConfiguration.windowConfiguration.getBounds());
- // If the activity has override bounds, the relative configuration (e.g. screen size,
- // layout) needs to be resolved according to the bounds.
- if (task != null && !resolvedConfig.windowConfiguration.getBounds().isEmpty()) {
- task.computeConfigResourceOverrides(getResolvedOverrideConfiguration(),
- newParentConfiguration);
+ final Rect parentAppBounds = newParentConfiguration.windowConfiguration.getAppBounds();
+ final Rect parentBounds = newParentConfiguration.windowConfiguration.getBounds();
+ // Use tmp bounds to calculate aspect ratio so we can know whether the activity should
+ // use restricted size (resolvedBounds may be the requested override bounds).
+ mTmpBounds.setEmpty();
+ applyAspectRatio(mTmpBounds, parentAppBounds, parentBounds);
+ // If the out bounds is not empty, it means the activity cannot fill parent's app
+ // bounds, then the relative configuration (e.g. screen size, layout) needs to be
+ // resolved according to the bounds.
+ if (!mTmpBounds.isEmpty()) {
+ final Rect resolvedBounds = resolvedConfig.windowConfiguration.getBounds();
+ resolvedBounds.set(mTmpBounds);
+ // Exclude the horizontal decor area because the activity will be centered
+ // horizontally in parent's app bounds to balance the visual appearance.
+ resolvedBounds.left = parentAppBounds.left;
+ task.computeConfigResourceOverrides(resolvedConfig, newParentConfiguration,
+ getFixedRotationTransformDisplayInfo());
+ final int offsetX = getHorizontalCenterOffset(
+ parentAppBounds.width(), resolvedBounds.width());
+ if (offsetX > 0) {
+ offsetBounds(resolvedConfig, offsetX - resolvedBounds.left, 0 /* offsetY */);
+ }
}
}
@@ -6384,65 +6401,41 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A
private void resolveSizeCompatModeConfiguration(Configuration newParentConfiguration) {
final Configuration resolvedConfig = getResolvedOverrideConfiguration();
final Rect resolvedBounds = resolvedConfig.windowConfiguration.getBounds();
-
- Rect parentBounds = new Rect(newParentConfiguration.windowConfiguration.getBounds());
-
- int orientation = getRequestedConfigurationOrientation();
- if (orientation == ORIENTATION_UNDEFINED) {
- orientation = newParentConfiguration.orientation;
- }
- int rotation = resolvedConfig.windowConfiguration.getRotation();
- if (rotation == ROTATION_UNDEFINED) {
- rotation = newParentConfiguration.windowConfiguration.getRotation();
+ final int requestedOrientation = getRequestedConfigurationOrientation();
+ final boolean orientationRequested = requestedOrientation != ORIENTATION_UNDEFINED;
+ final int orientation = orientationRequested
+ ? requestedOrientation
+ : newParentConfiguration.orientation;
+ int rotation = newParentConfiguration.windowConfiguration.getRotation();
+ final boolean canChangeOrientation = handlesOrientationChangeFromDescendant();
+ if (canChangeOrientation && mCompatDisplayInsets.mIsRotatable
+ && !mCompatDisplayInsets.mIsFloating) {
+ // Use parent rotation because the original display can rotate by requested orientation.
+ resolvedConfig.windowConfiguration.setRotation(rotation);
+ } else {
+ final int overrideRotation = resolvedConfig.windowConfiguration.getRotation();
+ if (overrideRotation != ROTATION_UNDEFINED) {
+ rotation = overrideRotation;
+ }
}
// Use compat insets to lock width and height. We should not use the parent width and height
// because apps in compat mode should have a constant width and height. The compat insets
// are locked when the app is first launched and are never changed after that, so we can
// rely on them to contain the original and unchanging width and height of the app.
- final Rect compatDisplayBounds = mTmpBounds;
- mCompatDisplayInsets.getDisplayBoundsByRotation(compatDisplayBounds, rotation);
final Rect containingAppBounds = new Rect();
- mCompatDisplayInsets.getFrameByOrientation(containingAppBounds, orientation);
-
- // Center containingAppBounds horizontally and aligned to top of parent. Both
- // are usually the same unless the app was frozen with an orientation letterbox.
- int left = compatDisplayBounds.left + compatDisplayBounds.width() / 2
- - containingAppBounds.width() / 2;
- resolvedBounds.set(left, compatDisplayBounds.top, left + containingAppBounds.width(),
- compatDisplayBounds.top + containingAppBounds.height());
-
- if (rotation != ROTATION_UNDEFINED) {
- // Ensure the parent and container bounds won't overlap with insets.
- Task.intersectWithInsetsIfFits(containingAppBounds, compatDisplayBounds,
- mCompatDisplayInsets.mNonDecorInsets[rotation]);
- Task.intersectWithInsetsIfFits(parentBounds, compatDisplayBounds,
- mCompatDisplayInsets.mNonDecorInsets[rotation]);
- }
-
- applyAspectRatio(resolvedBounds, containingAppBounds, compatDisplayBounds);
-
- // Center horizontally in parent and align to top of parent - this is a UX choice
- left = parentBounds.left + parentBounds.width() / 2 - resolvedBounds.width() / 2;
- resolvedBounds.set(left, parentBounds.top, left + resolvedBounds.width(),
- parentBounds.top + resolvedBounds.height());
-
- // We want to get as much of the app on the screen even if insets cover it. This is because
- // insets change but an app's bounds are more permanent after launch. After computing insets
- // and horizontally centering resolvedBounds, the resolvedBounds may end up outside parent
- // bounds. This is okay only if the resolvedBounds exceed their parent on the bottom and
- // right, because that is clipped when the final bounds are computed. To reach this state,
- // we first try and push the app as much inside the parent towards the top and left (the
- // min). The app may then end up outside the parent by going too far left and top, so we
- // push it back into the parent by taking the max with parent left and top.
- Rect fullParentBounds = newParentConfiguration.windowConfiguration.getBounds();
- resolvedBounds.offsetTo(Math.max(fullParentBounds.left,
- Math.min(fullParentBounds.right - resolvedBounds.width(), resolvedBounds.left)),
- Math.max(fullParentBounds.top,
- Math.min(fullParentBounds.bottom - resolvedBounds.height(),
- resolvedBounds.top)));
-
- // Use resolvedBounds to compute other override configurations such as appBounds
+ final Rect containingBounds = mTmpBounds;
+ mCompatDisplayInsets.getContainerBounds(containingAppBounds, containingBounds, rotation,
+ orientation, orientationRequested, canChangeOrientation);
+ resolvedBounds.set(containingAppBounds);
+ // The size of floating task is fixed (only swap), so the aspect ratio is already correct.
+ if (!mCompatDisplayInsets.mIsFloating) {
+ applyAspectRatio(resolvedBounds, containingAppBounds, containingBounds);
+ }
+
+ // Use resolvedBounds to compute other override configurations such as appBounds. The bounds
+ // are calculated in compat container space. The actual position on screen will be applied
+ // later, so the calculation is simpler that doesn't need to involve offset from parent.
task.computeConfigResourceOverrides(resolvedConfig, newParentConfiguration,
mCompatDisplayInsets);
// Use current screen layout as source because the size of app is independent to parent.
@@ -6455,6 +6448,79 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A
if (resolvedConfig.screenWidthDp == resolvedConfig.screenHeightDp) {
resolvedConfig.orientation = newParentConfiguration.orientation;
}
+
+ // Below figure is an example that puts an activity which was launched in a larger container
+ // into a smaller container.
+ // The outermost rectangle is the real display bounds.
+ // "@" is the parent app bounds.
+ // "#" is the {@code resolvedBounds} that applies to application.
+ // "*" is the {@code mSizeCompatBounds} that used to show on screen if scaled.
+ // ------------------------------
+ // | |
+ // | @@@@*********@@@@### |
+ // | @ * * @ # |
+ // | @ * * @ # |
+ // | @ * * @ # |
+ // | @@@@*********@@@@ # |
+ // ---------#--------------#-----
+ // # #
+ // ################
+ // The application is still layouted in "#" since it was launched, and it will be visually
+ // scaled and positioned to "*".
+
+ // Calculates the scale and offset to horizontal center the size compatibility bounds into
+ // the region which is available to application.
+ final Rect parentBounds = newParentConfiguration.windowConfiguration.getBounds();
+ final Rect parentAppBounds = newParentConfiguration.windowConfiguration.getAppBounds();
+ final Rect resolvedAppBounds = resolvedConfig.windowConfiguration.getAppBounds();
+ final int contentW = resolvedAppBounds.width();
+ final int contentH = resolvedAppBounds.height();
+ final int viewportW = parentAppBounds.width();
+ final int viewportH = parentAppBounds.height();
+ // Only allow to scale down.
+ mSizeCompatScale = (contentW <= viewportW && contentH <= viewportH)
+ ? 1f : Math.min((float) viewportW / contentW, (float) viewportH / contentH);
+ final int screenTopInset = parentAppBounds.top - parentBounds.top;
+ final boolean topNotAligned = screenTopInset != resolvedAppBounds.top - resolvedBounds.top;
+ if (mSizeCompatScale != 1f || topNotAligned) {
+ if (mSizeCompatBounds == null) {
+ mSizeCompatBounds = new Rect();
+ }
+ mSizeCompatBounds.set(resolvedAppBounds);
+ mSizeCompatBounds.offsetTo(0, 0);
+ mSizeCompatBounds.scale(mSizeCompatScale);
+ // The insets are included in height, e.g. the area of real cutout shouldn't be scaled.
+ mSizeCompatBounds.bottom += screenTopInset;
+ } else {
+ mSizeCompatBounds = null;
+ }
+
+ // Center horizontally in parent (app bounds) and align to top of parent (bounds)
+ // - this is a UX choice.
+ final int offsetX = getHorizontalCenterOffset(
+ (int) viewportW, (int) (contentW * mSizeCompatScale));
+ // Above coordinates are in "@" space, now place "*" and "#" to screen space.
+ final int screenPosX = parentAppBounds.left + offsetX;
+ final int screenPosY = parentBounds.top;
+ if (screenPosX > 0 || screenPosY > 0) {
+ if (mSizeCompatBounds != null) {
+ mSizeCompatBounds.offset(screenPosX, screenPosY);
+ }
+ // Add the global coordinates and remove the local coordinates.
+ final int dx = screenPosX - resolvedBounds.left;
+ final int dy = screenPosY - resolvedBounds.top;
+ offsetBounds(resolvedConfig, dx, dy);
+ }
+ }
+
+ /** @return The horizontal offset of putting the content in the center of viewport. */
+ private static int getHorizontalCenterOffset(int viewportW, int contentW) {
+ return (int) ((viewportW - contentW + 1) * 0.5f);
+ }
+
+ private static void offsetBounds(Configuration inOutConfig, int offsetX, int offsetY) {
+ inOutConfig.windowConfiguration.getBounds().offset(offsetX, offsetY);
+ inOutConfig.windowConfiguration.getAppBounds().offset(offsetX, offsetY);
}
@Override
@@ -6488,40 +6554,6 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A
return task != null ? task.getBounds() : getBounds();
}
- /**
- * Calculates the scale and offset to horizontal center the size compatibility bounds into the
- * region which is available to application.
- */
- private void calculateCompatBoundsTransformation(Configuration newParentConfig) {
- final Rect parentAppBounds = newParentConfig.windowConfiguration.getAppBounds();
- final Rect parentBounds = newParentConfig.windowConfiguration.getBounds();
- final Rect viewportBounds = parentAppBounds != null ? parentAppBounds : parentBounds;
- final Rect appBounds = getWindowConfiguration().getAppBounds();
- final Rect contentBounds = appBounds != null ? appBounds : getResolvedOverrideBounds();
- final float contentW = contentBounds.width();
- final float contentH = contentBounds.height();
- final float viewportW = viewportBounds.width();
- final float viewportH = viewportBounds.height();
- // Only allow to scale down.
- mSizeCompatScale = (contentW <= viewportW && contentH <= viewportH)
- ? 1 : Math.min(viewportW / contentW, viewportH / contentH);
- final int offsetX = (int) ((viewportW - contentW * mSizeCompatScale + 1) * 0.5f)
- + viewportBounds.left;
-
- if (mSizeCompatBounds == null) {
- mSizeCompatBounds = new Rect();
- }
- mSizeCompatBounds.set(contentBounds);
- mSizeCompatBounds.offsetTo(0, 0);
- mSizeCompatBounds.scale(mSizeCompatScale);
- // Ensure to align the top with the parent.
- mSizeCompatBounds.top = parentBounds.top;
- // The decor inset is included in height.
- mSizeCompatBounds.bottom += viewportBounds.top;
- mSizeCompatBounds.left += offsetX;
- mSizeCompatBounds.right += offsetX;
- }
-
@Override
public void onConfigurationChanged(Configuration newParentConfig) {
if (mCompatDisplayInsets != null) {
@@ -6553,28 +6585,6 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A
}
super.onConfigurationChanged(newParentConfig);
- if (shouldUseSizeCompatMode()) {
- final Rect overrideBounds = getResolvedOverrideBounds();
- if (task != null && !overrideBounds.isEmpty()) {
- final Rect taskBounds = task.getBounds();
- // Since we only center the activity horizontally, if only the fixed height is
- // smaller than its container, the override bounds don't need to take effect.
- if ((overrideBounds.width() != taskBounds.width()
- || overrideBounds.height() > taskBounds.height())) {
- calculateCompatBoundsTransformation(newParentConfig);
- updateSurfacePosition();
- } else if (mSizeCompatBounds != null) {
- mSizeCompatBounds = null;
- mSizeCompatScale = 1f;
- updateSurfacePosition();
- }
- } else if (overrideBounds.isEmpty()) {
- mSizeCompatBounds = null;
- mSizeCompatScale = 1f;
- updateSurfacePosition();
- }
- }
-
// Configuration's equality doesn't consider seq so if only seq number changes in resolved
// override configuration. Therefore ConfigurationContainer doesn't change merged override
// configuration, but it's used to push configuration changes so explicitly update that.
@@ -7441,6 +7451,11 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A
}
@Override
+ long getProtoFieldId() {
+ return ACTIVITY;
+ }
+
+ @Override
public void dumpDebug(ProtoOutputStream proto, long fieldId,
@WindowTraceLogLevel int logLevel) {
// Critical log level logs only visible elements to mitigate performance overheard
@@ -7471,12 +7486,13 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A
/**
* The precomputed insets of the display in each rotation. This is used to make the size
* compatibility mode activity compute the configuration without relying on its current display.
+ * This currently only supports fullscreen and freeform windowing mode.
*/
static class CompatDisplayInsets {
- private final int mDisplayWidth;
- private final int mDisplayHeight;
private final int mWidth;
private final int mHeight;
+ final boolean mIsFloating;
+ final boolean mIsRotatable;
/**
* The nonDecorInsets for each rotation. Includes the navigation bar and cutout insets. It
@@ -7490,30 +7506,34 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A
*/
final Rect[] mStableInsets = new Rect[4];
- /**
- * Sets bounds to {@link Task} bounds. For apps in freeform, the task bounds are the
- * parent bounds from the app's perspective. No insets because within a window.
- */
- CompatDisplayInsets(DisplayContent display, Rect activityBounds, boolean isFloating) {
- mDisplayWidth = display.mBaseDisplayWidth;
- mDisplayHeight = display.mBaseDisplayHeight;
- mWidth = activityBounds.width();
- mHeight = activityBounds.height();
- if (isFloating) {
- Rect emptyRect = new Rect();
+ /** Constructs the environment to simulate the bounds behavior of the given container. */
+ CompatDisplayInsets(DisplayContent display, WindowContainer container) {
+ mIsFloating = container.getWindowConfiguration().tasksAreFloating();
+ mIsRotatable = !mIsFloating && !display.ignoreRotationForApps();
+ if (mIsFloating) {
+ final Rect containerBounds = container.getWindowConfiguration().getBounds();
+ mWidth = containerBounds.width();
+ mHeight = containerBounds.height();
+ // For apps in freeform, the task bounds are the parent bounds from the app's
+ // perspective. No insets because within a window.
+ final Rect emptyRect = new Rect();
for (int rotation = 0; rotation < 4; rotation++) {
mNonDecorInsets[rotation] = emptyRect;
mStableInsets[rotation] = emptyRect;
}
return;
}
+
+ // If the activity is not floating, assume it fills the display.
+ mWidth = display.mBaseDisplayWidth;
+ mHeight = display.mBaseDisplayHeight;
final DisplayPolicy policy = display.getDisplayPolicy();
for (int rotation = 0; rotation < 4; rotation++) {
mNonDecorInsets[rotation] = new Rect();
mStableInsets[rotation] = new Rect();
final boolean rotated = (rotation == ROTATION_90 || rotation == ROTATION_270);
- final int dw = rotated ? mDisplayHeight : mDisplayWidth;
- final int dh = rotated ? mDisplayWidth : mDisplayHeight;
+ final int dw = rotated ? mHeight : mWidth;
+ final int dh = rotated ? mWidth : mHeight;
final DisplayCutout cutout = display.calculateDisplayCutoutForRotation(rotation)
.getDisplayCutout();
policy.getNonDecorInsetsLw(rotation, dw, dh, cutout, mNonDecorInsets[rotation]);
@@ -7522,10 +7542,10 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A
}
}
- void getDisplayBoundsByRotation(Rect outBounds, int rotation) {
+ void getBoundsByRotation(Rect outBounds, int rotation) {
final boolean rotated = (rotation == ROTATION_90 || rotation == ROTATION_270);
- final int dw = rotated ? mDisplayHeight : mDisplayWidth;
- final int dh = rotated ? mDisplayWidth : mDisplayHeight;
+ final int dw = rotated ? mHeight : mWidth;
+ final int dh = rotated ? mWidth : mHeight;
outBounds.set(0, 0, dw, dh);
}
@@ -7536,6 +7556,51 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A
outBounds.set(0, 0, isLandscape ? longSide : shortSide,
isLandscape ? shortSide : longSide);
}
+
+ /** Gets the horizontal centered container bounds for size compatibility mode. */
+ void getContainerBounds(Rect outAppBounds, Rect outBounds, int rotation, int orientation,
+ boolean orientationRequested, boolean canChangeOrientation) {
+ if (mIsFloating) {
+ getFrameByOrientation(outBounds, orientation);
+ outAppBounds.set(outBounds);
+ return;
+ }
+
+ if (mIsRotatable && canChangeOrientation) {
+ getBoundsByRotation(outBounds, rotation);
+ if (orientationRequested) {
+ getFrameByOrientation(outAppBounds, orientation);
+ } else {
+ outAppBounds.set(outBounds);
+ }
+ } else {
+ outBounds.set(0, 0, mWidth, mHeight);
+ getFrameByOrientation(outAppBounds, orientation);
+ if (orientationRequested && !canChangeOrientation
+ && (outAppBounds.width() > outAppBounds.height()) != (mWidth > mHeight)) {
+ // The orientation is mismatched but the display cannot rotate. The bounds will
+ // fit to the short side of display.
+ if (orientation == ORIENTATION_LANDSCAPE) {
+ outAppBounds.bottom = (int) ((float) mWidth * mWidth / mHeight);
+ outAppBounds.right = mWidth;
+ } else {
+ outAppBounds.bottom = mHeight;
+ outAppBounds.right = (int) ((float) mHeight * mHeight / mWidth);
+ }
+ outAppBounds.offset(getHorizontalCenterOffset(outBounds.width(),
+ outAppBounds.width()), 0 /* dy */);
+ } else {
+ outAppBounds.set(outBounds);
+ }
+ }
+
+ if (rotation != ROTATION_UNDEFINED) {
+ // Ensure the app bounds won't overlap with insets.
+ Task.intersectWithInsetsIfFits(outAppBounds, outBounds, mNonDecorInsets[rotation]);
+ }
+ // The horizontal position is centered and it should not cover insets.
+ outBounds.left = outAppBounds.left;
+ }
}
private static class AppSaturationInfo {
@@ -7561,7 +7626,7 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A
return new RemoteAnimationTarget(task.mTaskId, record.getMode(),
record.mAdapter.mCapturedLeash, !fillsParent(),
mainWindow.mWinAnimator.mLastClipRect, insets,
- getPrefixOrderIndex(), record.mAdapter.mPosition,
+ getPrefixOrderIndex(), record.mAdapter.mPosition, record.mAdapter.mLocalBounds,
record.mAdapter.mStackBounds, task.getWindowConfiguration(),
false /*isNotInRecents*/,
record.mThumbnailAdapter != null ? record.mThumbnailAdapter.mCapturedLeash : null,
@@ -7569,6 +7634,11 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A
}
@Override
+ boolean canCreateRemoteAnimationTarget() {
+ return true;
+ }
+
+ @Override
void getAnimationFrames(Rect outFrame, Rect outInsets, Rect outStableInsets,
Rect outSurfaceInsets) {
final WindowState win = findMainWindow();
diff --git a/services/core/java/com/android/server/wm/ActivityStack.java b/services/core/java/com/android/server/wm/ActivityStack.java
index 5ddd7311a004..9bad799b68d1 100644
--- a/services/core/java/com/android/server/wm/ActivityStack.java
+++ b/services/core/java/com/android/server/wm/ActivityStack.java
@@ -90,7 +90,6 @@ import static com.android.server.wm.ActivityTaskManagerDebugConfig.TAG_WITH_CLAS
import static com.android.server.wm.ActivityTaskManagerService.H.FIRST_ACTIVITY_STACK_MSG;
import static com.android.server.wm.ActivityTaskManagerService.RELAUNCH_REASON_FREE_RESIZE;
import static com.android.server.wm.ActivityTaskManagerService.RELAUNCH_REASON_WINDOWING_MODE_RESIZE;
-import static com.android.server.wm.TaskProto.ACTIVITIES;
import static com.android.server.wm.TaskProto.ACTIVITY_TYPE;
import static com.android.server.wm.TaskProto.ANIMATING_BOUNDS;
import static com.android.server.wm.TaskProto.BOUNDS;
@@ -109,7 +108,6 @@ import static com.android.server.wm.TaskProto.RESUMED_ACTIVITY;
import static com.android.server.wm.TaskProto.ROOT_TASK_ID;
import static com.android.server.wm.TaskProto.SURFACE_HEIGHT;
import static com.android.server.wm.TaskProto.SURFACE_WIDTH;
-import static com.android.server.wm.TaskProto.TASKS;
import static com.android.server.wm.TaskProto.WINDOW_CONTAINER;
import static com.android.server.wm.WindowContainer.AnimationFlags.CHILDREN;
import static com.android.server.wm.WindowContainer.AnimationFlags.TRANSITION;
@@ -356,8 +354,7 @@ class ActivityStack extends Task {
final PooledFunction f = PooledLambda.obtainFunction(
EnsureVisibleActivitiesConfigHelper::processActivity, this,
PooledLambda.__(ActivityRecord.class));
- forAllActivities(f, start.getTask(), true /*includeBoundary*/,
- true /*traverseTopToBottom*/);
+ forAllActivities(f, start, true /*includeBoundary*/, true /*traverseTopToBottom*/);
f.recycle();
if (mUpdateConfig) {
@@ -650,14 +647,6 @@ class ActivityStack extends Task {
if (prevWindowingMode != getWindowingMode()) {
mDisplayContent.onStackWindowingModeChanged(this);
-
- if (inSplitScreenSecondaryWindowingMode()) {
- // When the stack is resized due to entering split screen secondary, offset the
- // windows to compensate for the new stack position.
- forAllWindows(w -> {
- w.mWinAnimator.setOffsetPositionForStackResize(true);
- }, true);
- }
}
final DisplayContent display = getDisplay();
@@ -1470,11 +1459,11 @@ class ActivityStack extends Task {
if (resumeNext) {
final ActivityStack topStack = mRootWindowContainer.getTopDisplayFocusedStack();
- if (!topStack.shouldSleepOrShutDownActivities()) {
+ if (topStack != null && !topStack.shouldSleepOrShutDownActivities()) {
mRootWindowContainer.resumeFocusedStacksTopActivities(topStack, prev, null);
} else {
checkReadyForSleep();
- ActivityRecord top = topStack.topRunningActivity();
+ final ActivityRecord top = topStack != null ? topStack.topRunningActivity() : null;
if (top == null || (prev != null && top != prev)) {
// If there are no more activities available to run, do resume anyway to start
// something. Also if the top activity on the stack is not the just paused
@@ -2396,8 +2385,10 @@ class ActivityStack extends Task {
}
Task task = null;
if (!newTask && isOrhasTask) {
+ // Starting activity cannot be occluding activity, otherwise starting window could be
+ // remove immediately without transferring to starting activity.
final ActivityRecord occludingActivity = getActivity(
- (ar) -> !ar.finishing && ar.occludesParent(), true, rTask);
+ (ar) -> !ar.finishing && ar.occludesParent(), true, r);
if (occludingActivity != null) {
// Here it is! Now, if this is not yet visible (occluded by another task) to the
// user, then just add it without starting; it will get started when the user
@@ -3287,7 +3278,7 @@ class ActivityStack extends Task {
if (DisplayContent.alwaysCreateStack(getWindowingMode(), getActivityType())) {
// This stack will only contain one task, so just return itself since all stacks ara now
// tasks and all tasks are now stacks.
- task = reuseAsLeafTask(voiceSession, voiceInteractor, info, activity);
+ task = reuseAsLeafTask(voiceSession, voiceInteractor, intent, info, activity);
} else {
// Create child task since this stack can contain multiple tasks.
final int taskId = activity != null
@@ -3884,9 +3875,10 @@ class ActivityStack extends Task {
return;
}
if (mTile != null) {
- reparentSurfaceControl(getPendingTransaction(), mTile.getSurfaceControl());
+ // don't use reparentSurfaceControl because we need to bypass taskorg check
+ mSurfaceAnimator.reparent(getPendingTransaction(), mTile.getSurfaceControl());
} else if (mTile == null && origTile != null) {
- reparentSurfaceControl(getPendingTransaction(), getParentSurfaceControl());
+ mSurfaceAnimator.reparent(getPendingTransaction(), getParentSurfaceControl());
}
}
@@ -3919,17 +3911,6 @@ class ActivityStack extends Task {
proto.write(DISPLAY_ID, getDisplayId());
proto.write(ROOT_TASK_ID, getRootTaskId());
- for (int i = mChildren.size() - 1; i >= 0; --i) {
- final WindowContainer child = mChildren.get(i);
- if (child instanceof Task) {
- child.dumpDebug(proto, TASKS, logLevel);
- } else if (child instanceof ActivityRecord) {
- child.dumpDebug(proto, ACTIVITIES, logLevel);
- } else {
- throw new IllegalStateException("Unknown child type: " + child);
- }
- }
-
if (mResumedActivity != null) {
mResumedActivity.writeIdentifierToProto(proto, RESUMED_ACTIVITY);
}
@@ -3945,15 +3926,8 @@ class ActivityStack extends Task {
proto.write(MIN_HEIGHT, mMinHeight);
proto.write(FILLS_PARENT, matchParentBounds());
+ getRawBounds().dumpDebug(proto, BOUNDS);
- if (!matchParentBounds()) {
- final Rect bounds = getRequestedOverrideBounds();
- bounds.dumpDebug(proto, BOUNDS);
- } else if (getStack().getTile() != null) {
- // use tile's bounds here for cts.
- final Rect bounds = getStack().getTile().getRequestedOverrideBounds();
- bounds.dumpDebug(proto, BOUNDS);
- }
getOverrideDisplayedBounds().dumpDebug(proto, DISPLAYED_BOUNDS);
if (mLastNonFullscreenBounds != null) {
mLastNonFullscreenBounds.dumpDebug(proto, LAST_NON_FULLSCREEN_BOUNDS);
diff --git a/services/core/java/com/android/server/wm/ActivityStarter.java b/services/core/java/com/android/server/wm/ActivityStarter.java
index 32103048469f..688c9ae705d7 100644
--- a/services/core/java/com/android/server/wm/ActivityStarter.java
+++ b/services/core/java/com/android/server/wm/ActivityStarter.java
@@ -615,12 +615,15 @@ class ActivityStarter {
int res;
synchronized (mService.mGlobalLock) {
- final ActivityStack stack = mRootWindowContainer.getTopDisplayFocusedStack();
- stack.mConfigWillChange = mRequest.globalConfig != null
+ final boolean globalConfigWillChange = mRequest.globalConfig != null
&& mService.getGlobalConfiguration().diff(mRequest.globalConfig) != 0;
+ final ActivityStack stack = mRootWindowContainer.getTopDisplayFocusedStack();
+ if (stack != null) {
+ stack.mConfigWillChange = globalConfigWillChange;
+ }
if (DEBUG_CONFIGURATION) {
Slog.v(TAG_CONFIGURATION, "Starting activity when config will change = "
- + stack.mConfigWillChange);
+ + globalConfigWillChange);
}
final long origId = Binder.clearCallingIdentity();
@@ -633,7 +636,7 @@ class ActivityStarter {
Binder.restoreCallingIdentity(origId);
- if (stack.mConfigWillChange) {
+ if (globalConfigWillChange) {
// If the caller also wants to switch to a new configuration, do so now.
// This allows a clean switch, as we are waiting for the current activity
// to pause (so we will not destroy it), and have not yet started the
@@ -641,7 +644,9 @@ class ActivityStarter {
mService.mAmInternal.enforceCallingPermission(
android.Manifest.permission.CHANGE_CONFIGURATION,
"updateConfiguration()");
- stack.mConfigWillChange = false;
+ if (stack != null) {
+ stack.mConfigWillChange = false;
+ }
if (DEBUG_CONFIGURATION) {
Slog.v(TAG_CONFIGURATION,
"Updating to new configuration after starting activity.");
@@ -1536,9 +1541,11 @@ class ActivityStarter {
// If the activity being launched is the same as the one currently at the top, then
// we need to check if it should only be launched once.
final ActivityStack topStack = mRootWindowContainer.getTopDisplayFocusedStack();
- startResult = deliverToCurrentTopIfNeeded(topStack);
- if (startResult != START_SUCCESS) {
- return startResult;
+ if (topStack != null) {
+ startResult = deliverToCurrentTopIfNeeded(topStack);
+ if (startResult != START_SUCCESS) {
+ return startResult;
+ }
}
if (mTargetStack == null) {
@@ -1563,10 +1570,16 @@ class ActivityStarter {
mService.mUgmInternal.grantUriPermissionFromIntent(mCallingUid, mStartActivity.packageName,
mIntent, mStartActivity.getUriPermissionsLocked(), mStartActivity.mUserId);
- mService.getPackageManagerInternalLocked().grantImplicitAccess(
- mStartActivity.mUserId, mIntent,
- UserHandle.getAppId(mStartActivity.info.applicationInfo.uid), mCallingUid,
- true /*direct*/);
+ if (mStartActivity.resultTo != null && mStartActivity.resultTo.info != null) {
+ // we need to resolve resultTo to a uid as grantImplicitAccess deals explicitly in UIDs
+ final PackageManagerInternal pmInternal =
+ mService.getPackageManagerInternalLocked();
+ final int resultToUid = pmInternal.getPackageUidInternal(
+ mStartActivity.resultTo.info.packageName, 0, mStartActivity.mUserId);
+ pmInternal.grantImplicitAccess(mStartActivity.mUserId, mIntent,
+ UserHandle.getAppId(mStartActivity.info.applicationInfo.uid) /*recipient*/,
+ resultToUid /*visible*/, true /*direct*/);
+ }
if (newTask) {
EventLogTags.writeWmCreateTask(mStartActivity.mUserId,
mStartActivity.getTask().mTaskId);
@@ -2126,10 +2139,13 @@ class ActivityStarter {
if ((startFlags & START_FLAG_ONLY_IF_NEEDED) != 0) {
ActivityRecord checkedCaller = sourceRecord;
if (checkedCaller == null) {
- checkedCaller = mRootWindowContainer.getTopDisplayFocusedStack()
- .topRunningNonDelayedActivityLocked(mNotTop);
+ ActivityStack topFocusedStack = mRootWindowContainer.getTopDisplayFocusedStack();
+ if (topFocusedStack != null) {
+ checkedCaller = topFocusedStack.topRunningNonDelayedActivityLocked(mNotTop);
+ }
}
- if (!checkedCaller.mActivityComponent.equals(r.mActivityComponent)) {
+ if (checkedCaller == null
+ || !checkedCaller.mActivityComponent.equals(r.mActivityComponent)) {
// Caller is not the same as launcher, so always needed.
mStartFlags &= ~START_FLAG_ONLY_IF_NEEDED;
}
diff --git a/services/core/java/com/android/server/wm/ActivityTaskManagerService.java b/services/core/java/com/android/server/wm/ActivityTaskManagerService.java
index 770dabf4f5ca..d3ff912ea327 100644
--- a/services/core/java/com/android/server/wm/ActivityTaskManagerService.java
+++ b/services/core/java/com/android/server/wm/ActivityTaskManagerService.java
@@ -680,12 +680,15 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub {
}
@Override
- public void onChange(boolean selfChange, Uri uri, @UserIdInt int userId) {
- if (mFontScaleUri.equals(uri)) {
- updateFontScaleIfNeeded(userId);
- } else if (mHideErrorDialogsUri.equals(uri)) {
- synchronized (mGlobalLock) {
- updateShouldShowDialogsLocked(getGlobalConfiguration());
+ public void onChange(boolean selfChange, Iterable<Uri> uris, int flags,
+ @UserIdInt int userId) {
+ for (Uri uri : uris) {
+ if (mFontScaleUri.equals(uri)) {
+ updateFontScaleIfNeeded(userId);
+ } else if (mHideErrorDialogsUri.equals(uri)) {
+ synchronized (mGlobalLock) {
+ updateShouldShowDialogsLocked(getGlobalConfiguration());
+ }
}
}
}
@@ -1104,8 +1107,8 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub {
// If this is coming from the currently resumed activity, it is
// effectively saying that app switches are allowed at this point.
final ActivityStack stack = getTopDisplayFocusedStack();
- if (stack.mResumedActivity != null &&
- stack.mResumedActivity.info.applicationInfo.uid == Binder.getCallingUid()) {
+ if (stack != null && stack.mResumedActivity != null
+ && stack.mResumedActivity.info.applicationInfo.uid == Binder.getCallingUid()) {
mAppSwitchesAllowedTime = 0;
}
}
@@ -1951,8 +1954,13 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub {
public boolean isTopActivityImmersive() {
enforceNotIsolatedCaller("isTopActivityImmersive");
synchronized (mGlobalLock) {
- final ActivityRecord r = getTopDisplayFocusedStack().topRunningActivity();
- return (r != null) ? r.immersive : false;
+ final ActivityStack topFocusedStack = getTopDisplayFocusedStack();
+ if (topFocusedStack == null) {
+ return false;
+ }
+
+ final ActivityRecord r = topFocusedStack.topRunningActivity();
+ return r != null && r.immersive;
}
}
@@ -1981,7 +1989,8 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub {
public int getFrontActivityScreenCompatMode() {
enforceNotIsolatedCaller("getFrontActivityScreenCompatMode");
synchronized (mGlobalLock) {
- final ActivityRecord r = getTopDisplayFocusedStack().topRunningActivity();
+ final ActivityStack stack = getTopDisplayFocusedStack();
+ final ActivityRecord r = stack != null ? stack.topRunningActivity() : null;
if (r == null) {
return ActivityManager.COMPAT_MODE_UNKNOWN;
}
@@ -1995,7 +2004,8 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub {
"setFrontActivityScreenCompatMode");
ApplicationInfo ai;
synchronized (mGlobalLock) {
- final ActivityRecord r = getTopDisplayFocusedStack().topRunningActivity();
+ final ActivityStack stack = getTopDisplayFocusedStack();
+ final ActivityRecord r = stack != null ? stack.topRunningActivity() : null;
if (r == null) {
Slog.w(TAG, "setFrontActivityScreenCompatMode failed: no top activity");
return;
@@ -2383,7 +2393,10 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub {
synchronized (mGlobalLock) {
final long origId = Binder.clearCallingIdentity();
try {
- getTopDisplayFocusedStack().unhandledBackLocked();
+ final ActivityStack topFocusedStack = getTopDisplayFocusedStack();
+ if (topFocusedStack != null) {
+ topFocusedStack.unhandledBackLocked();
+ }
} finally {
Binder.restoreCallingIdentity(origId);
}
@@ -2800,14 +2813,8 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub {
userId = handleIncomingUser(Binder.getCallingPid(), callingUid, userId, "getRecentTasks");
final boolean allowed = isGetTasksAllowed("getRecentTasks", Binder.getCallingPid(),
callingUid);
- final boolean detailed = checkGetTasksPermission(
- android.Manifest.permission.GET_DETAILED_TASKS, Binder.getCallingPid(),
- UserHandle.getAppId(callingUid))
- == PackageManager.PERMISSION_GRANTED;
-
synchronized (mGlobalLock) {
- return mRecentTasks.getRecentTasks(maxNum, flags, allowed, detailed, userId,
- callingUid);
+ return mRecentTasks.getRecentTasks(maxNum, flags, allowed, userId, callingUid);
}
}
@@ -3622,7 +3629,8 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub {
"enqueueAssistContext()");
synchronized (mGlobalLock) {
- ActivityRecord activity = getTopDisplayFocusedStack().getTopNonFinishingActivity();
+ final ActivityStack stack = getTopDisplayFocusedStack();
+ ActivityRecord activity = stack != null ? stack.getTopNonFinishingActivity() : null;
if (activity == null) {
Slog.w(TAG, "getAssistContextExtras failed: no top activity");
return null;
@@ -7043,9 +7051,9 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub {
mRootWindowContainer.dumpDisplayConfigs(pw, " ");
}
if (dumpAll) {
- if (dumpPackage == null) {
- pw.println(" mConfigWillChange: "
- + getTopDisplayFocusedStack().mConfigWillChange);
+ final ActivityStack topFocusedStack = getTopDisplayFocusedStack();
+ if (dumpPackage == null && topFocusedStack != null) {
+ pw.println(" mConfigWillChange: " + topFocusedStack.mConfigWillChange);
}
if (mCompatModePackages.getPackages().size() > 0) {
boolean printed = false;
@@ -7126,7 +7134,10 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub {
synchronized (mGlobalLock) {
if (dumpPackage == null) {
getGlobalConfiguration().dumpDebug(proto, GLOBAL_CONFIGURATION);
- proto.write(CONFIG_WILL_CHANGE, getTopDisplayFocusedStack().mConfigWillChange);
+ final ActivityStack topFocusedStack = getTopDisplayFocusedStack();
+ if (topFocusedStack != null) {
+ proto.write(CONFIG_WILL_CHANGE, topFocusedStack.mConfigWillChange);
+ }
writeSleepStateToProto(proto, wakeFullness, testPssMode);
if (mRunningVoice != null) {
final long vrToken = proto.start(
diff --git a/services/core/java/com/android/server/wm/AppTransitionController.java b/services/core/java/com/android/server/wm/AppTransitionController.java
index 0912b2e8b52f..6a47c9e217f8 100644
--- a/services/core/java/com/android/server/wm/AppTransitionController.java
+++ b/services/core/java/com/android/server/wm/AppTransitionController.java
@@ -446,7 +446,7 @@ public class AppTransitionController {
siblings.add(current);
boolean canPromote = true;
- if (parent == null) {
+ if (parent == null || !parent.canCreateRemoteAnimationTarget()) {
canPromote = false;
} else {
// In case a descendant of the parent belongs to the other group, we cannot promote
diff --git a/services/core/java/com/android/server/wm/BLASTSyncEngine.java b/services/core/java/com/android/server/wm/BLASTSyncEngine.java
index 94decc792fd3..c18ed7d588d8 100644
--- a/services/core/java/com/android/server/wm/BLASTSyncEngine.java
+++ b/services/core/java/com/android/server/wm/BLASTSyncEngine.java
@@ -114,7 +114,6 @@ class BLASTSyncEngine {
return st.addToSync(wc);
}
- // TODO(b/148476626): TIMEOUTS!
void setReady(int id) {
final SyncState st = mPendingSyncs.get(id);
st.setReady();
diff --git a/services/core/java/com/android/server/wm/DisplayArea.java b/services/core/java/com/android/server/wm/DisplayArea.java
index 0d365b16e228..d9e41afa9141 100644
--- a/services/core/java/com/android/server/wm/DisplayArea.java
+++ b/services/core/java/com/android/server/wm/DisplayArea.java
@@ -23,13 +23,10 @@ import static android.view.WindowManager.TRANSIT_KEYGUARD_UNOCCLUDE;
import static android.view.WindowManagerPolicyConstants.APPLICATION_LAYER;
import static com.android.internal.util.Preconditions.checkState;
-import static com.android.server.wm.DisplayAreaChildProto.DISPLAY_AREA;
-import static com.android.server.wm.DisplayAreaChildProto.UNKNOWN;
-import static com.android.server.wm.DisplayAreaChildProto.WINDOW;
-import static com.android.server.wm.DisplayAreaProto.CHILDREN;
import static com.android.server.wm.DisplayAreaProto.NAME;
import static com.android.server.wm.DisplayAreaProto.WINDOW_CONTAINER;
import static com.android.server.wm.ProtoLogGroup.WM_DEBUG_ORIENTATION;
+import static com.android.server.wm.WindowContainerChildProto.DISPLAY_AREA;
import android.graphics.Rect;
import android.util.proto.ProtoOutputStream;
@@ -111,24 +108,14 @@ public class DisplayArea<T extends WindowContainer> extends WindowContainer<T> {
final long token = proto.start(fieldId);
super.dumpDebug(proto, WINDOW_CONTAINER, logLevel);
proto.write(NAME, mName);
- for (int i = 0; i < getChildCount(); i++) {
- final long childToken = proto.start(CHILDREN);
- final T child = getChildAt(i);
- if (child instanceof ActivityStack) {
- // TODO(display-area): Dump stacks & tasks here, instead of in DisplayContent's
- // dumpDebug. For now, skip them here to avoid dumping them as UNKNOWN.
- } else if (child instanceof WindowToken) {
- ((WindowToken) child).dumpDebug(proto, WINDOW, logLevel);
- } else if (child instanceof DisplayArea) {
- child.dumpDebug(proto, DISPLAY_AREA, logLevel);
- } else {
- proto.write(UNKNOWN, child.getClass().getSimpleName());
- }
- proto.end(childToken);
- }
proto.end(token);
}
+ @Override
+ long getProtoFieldId() {
+ return DISPLAY_AREA;
+ }
+
/**
* DisplayArea that contains WindowTokens, and orders them according to their type.
*/
diff --git a/services/core/java/com/android/server/wm/DisplayContent.java b/services/core/java/com/android/server/wm/DisplayContent.java
index e74af5c9c6a2..3352bd5b0096 100644
--- a/services/core/java/com/android/server/wm/DisplayContent.java
+++ b/services/core/java/com/android/server/wm/DisplayContent.java
@@ -94,6 +94,7 @@ import static com.android.server.wm.DisplayContentProto.APP_TRANSITION;
import static com.android.server.wm.DisplayContentProto.CLOSING_APPS;
import static com.android.server.wm.DisplayContentProto.DISPLAY_FRAMES;
import static com.android.server.wm.DisplayContentProto.DISPLAY_INFO;
+import static com.android.server.wm.DisplayContentProto.DISPLAY_READY;
import static com.android.server.wm.DisplayContentProto.DPI;
import static com.android.server.wm.DisplayContentProto.FOCUSED_APP;
import static com.android.server.wm.DisplayContentProto.FOCUSED_ROOT_TASK_ID;
@@ -105,7 +106,6 @@ import static com.android.server.wm.DisplayContentProto.ROOT_DISPLAY_AREA;
import static com.android.server.wm.DisplayContentProto.ROTATION;
import static com.android.server.wm.DisplayContentProto.SCREEN_ROTATION_ANIMATION;
import static com.android.server.wm.DisplayContentProto.SINGLE_TASK_INSTANCE;
-import static com.android.server.wm.DisplayContentProto.TASKS;
import static com.android.server.wm.DisplayContentProto.WINDOW_CONTAINER;
import static com.android.server.wm.ProtoLogGroup.WM_DEBUG_ADD_REMOVE;
import static com.android.server.wm.ProtoLogGroup.WM_DEBUG_APP_TRANSITIONS;
@@ -117,6 +117,7 @@ import static com.android.server.wm.ProtoLogGroup.WM_SHOW_TRANSACTIONS;
import static com.android.server.wm.RootWindowContainer.TAG_STATES;
import static com.android.server.wm.WindowContainer.AnimationFlags.PARENTS;
import static com.android.server.wm.WindowContainer.AnimationFlags.TRANSITION;
+import static com.android.server.wm.WindowContainerChildProto.DISPLAY_CONTENT;
import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_DISPLAY;
import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_INPUT_METHOD;
import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_LAYOUT;
@@ -1657,6 +1658,11 @@ class DisplayContent extends WindowContainer<DisplayContent.DisplayChildWindowCo
mIgnoreRotationForApps = isNonDecorDisplayCloseToSquare(Surface.ROTATION_0, width, height);
}
+ /** @return {@code true} if the orientation requested from application will be ignored. */
+ boolean ignoreRotationForApps() {
+ return mIgnoreRotationForApps;
+ }
+
private boolean isNonDecorDisplayCloseToSquare(int rotation, int width, int height) {
final DisplayCutout displayCutout =
calculateDisplayCutoutForRotation(rotation).getDisplayCutout();
@@ -2832,10 +2838,6 @@ class DisplayContent extends WindowContainer<DisplayContent.DisplayChildWindowCo
proto.write(ID, mDisplayId);
mRootDisplayArea.dumpDebug(proto, ROOT_DISPLAY_AREA, logLevel);
- for (int i = mTaskContainers.getChildCount() - 1; i >= 0; --i) {
- final ActivityStack stack = mTaskContainers.getChildAt(i);
- stack.dumpDebug(proto, TASKS, logLevel);
- }
for (int i = mOverlayContainers.getChildCount() - 1; i >= 0; --i) {
final WindowToken windowToken = mOverlayContainers.getChildAt(i);
windowToken.dumpDebug(proto, OVERLAY_WINDOWS, logLevel);
@@ -2870,11 +2872,17 @@ class DisplayContent extends WindowContainer<DisplayContent.DisplayChildWindowCo
} else {
proto.write(FOCUSED_ROOT_TASK_ID, INVALID_TASK_ID);
}
+ proto.write(DISPLAY_READY, isReady());
proto.end(token);
}
@Override
+ long getProtoFieldId() {
+ return DISPLAY_CONTENT;
+ }
+
+ @Override
public void dump(PrintWriter pw, String prefix, boolean dumpAll) {
super.dump(pw, prefix, dumpAll);
pw.print(prefix);
diff --git a/services/core/java/com/android/server/wm/DisplayPolicy.java b/services/core/java/com/android/server/wm/DisplayPolicy.java
index 00f892f08e09..d5a0d05b0f84 100644
--- a/services/core/java/com/android/server/wm/DisplayPolicy.java
+++ b/services/core/java/com/android/server/wm/DisplayPolicy.java
@@ -42,7 +42,10 @@ import static android.view.View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION;
import static android.view.ViewGroup.LayoutParams.MATCH_PARENT;
import static android.view.ViewRootImpl.NEW_INSETS_MODE_FULL;
import static android.view.ViewRootImpl.NEW_INSETS_MODE_NONE;
+import static android.view.WindowInsetsController.APPEARANCE_LIGHT_NAVIGATION_BARS;
import static android.view.WindowInsetsController.APPEARANCE_LIGHT_STATUS_BARS;
+import static android.view.WindowInsetsController.APPEARANCE_OPAQUE_NAVIGATION_BARS;
+import static android.view.WindowInsetsController.APPEARANCE_OPAQUE_STATUS_BARS;
import static android.view.WindowInsetsController.BEHAVIOR_SHOW_BARS_BY_SWIPE;
import static android.view.WindowInsetsController.BEHAVIOR_SHOW_TRANSIENT_BARS_BY_SWIPE;
import static android.view.WindowManager.INPUT_CONSUMER_NAVIGATION;
@@ -3269,11 +3272,19 @@ public class DisplayPolicy {
mService.getStackBounds(inSplitScreen ? WINDOWING_MODE_SPLIT_SCREEN_SECONDARY
: WINDOWING_MODE_FULLSCREEN,
ACTIVITY_TYPE_UNDEFINED, mNonDockedStackBounds);
- final Pair<Integer, Boolean> result =
+ final Pair<Integer, WindowState> result =
updateSystemBarsLw(win, mLastSystemUiFlags, tmpVisibility);
final int visibility = result.first;
- final int appearance = win.mAttrs.insetsFlags.appearance
- | InsetsFlags.getAppearance(visibility);
+ final WindowState navColorWin = result.second;
+ final boolean isNavbarColorManagedByIme =
+ navColorWin != null && navColorWin == mDisplayContent.mInputMethodWindow;
+ final int opaqueAppearance = InsetsFlags.getAppearance(visibility)
+ & (APPEARANCE_OPAQUE_STATUS_BARS | APPEARANCE_OPAQUE_NAVIGATION_BARS);
+ final int appearance = ViewRootImpl.sNewInsetsMode == NEW_INSETS_MODE_FULL
+ ? updateLightNavigationBarAppearanceLw(win.mAttrs.insetsFlags.appearance,
+ mTopFullscreenOpaqueWindowState, mTopFullscreenOpaqueOrDimmingWindowState,
+ mDisplayContent.mInputMethodWindow, navColorWin) | opaqueAppearance
+ : InsetsFlags.getAppearance(visibility);
final int diff = visibility ^ mLastSystemUiFlags;
final InsetsPolicy insetsPolicy = getInsetsPolicy();
final boolean isFullscreen = (visibility & (View.SYSTEM_UI_FLAG_FULLSCREEN
@@ -3320,7 +3331,6 @@ public class DisplayPolicy {
new AppearanceRegion(dockedAppearance, dockedStackBounds)}
: new AppearanceRegion[]{
new AppearanceRegion(fullscreenAppearance, fullscreenStackBounds)};
- final boolean isNavbarColorManagedByIme = result.second;
String cause = win.toString();
mHandler.post(() -> {
StatusBarManagerInternal statusBar = getStatusBarManagerInternal();
@@ -3448,7 +3458,25 @@ public class DisplayPolicy {
return vis;
}
- private Pair<Integer, Boolean> updateSystemBarsLw(WindowState win, int oldVis, int vis) {
+ @VisibleForTesting
+ static int updateLightNavigationBarAppearanceLw(int appearance, WindowState opaque,
+ WindowState opaqueOrDimming, WindowState imeWindow, WindowState navColorWin) {
+
+ if (navColorWin != null) {
+ if (navColorWin == imeWindow || navColorWin == opaque) {
+ // Respect the light flag.
+ appearance &= ~APPEARANCE_LIGHT_NAVIGATION_BARS;
+ appearance |= navColorWin.mAttrs.insetsFlags.appearance
+ & APPEARANCE_LIGHT_NAVIGATION_BARS;
+ } else if (navColorWin == opaqueOrDimming && navColorWin.isDimming()) {
+ // Clear the light flag for dimming window.
+ appearance &= ~APPEARANCE_LIGHT_NAVIGATION_BARS;
+ }
+ }
+ return appearance;
+ }
+
+ private Pair<Integer, WindowState> updateSystemBarsLw(WindowState win, int oldVis, int vis) {
final boolean dockedStackVisible =
mDisplayContent.isStackVisible(WINDOWING_MODE_SPLIT_SCREEN_PRIMARY);
final boolean freeformStackVisible =
@@ -3587,11 +3615,8 @@ public class DisplayPolicy {
vis = updateLightNavigationBarLw(vis, mTopFullscreenOpaqueWindowState,
mTopFullscreenOpaqueOrDimmingWindowState,
mDisplayContent.mInputMethodWindow, navColorWin);
- // Navbar color is controlled by the IME.
- final boolean isManagedByIme =
- navColorWin != null && navColorWin == mDisplayContent.mInputMethodWindow;
- return Pair.create(vis, isManagedByIme);
+ return Pair.create(vis, navColorWin);
}
private boolean drawsBarBackground(int vis, WindowState win, BarController controller,
diff --git a/services/core/java/com/android/server/wm/EmbeddedWindowController.java b/services/core/java/com/android/server/wm/EmbeddedWindowController.java
index 884f7694d648..484a5a8b53b8 100644
--- a/services/core/java/com/android/server/wm/EmbeddedWindowController.java
+++ b/services/core/java/com/android/server/wm/EmbeddedWindowController.java
@@ -17,11 +17,15 @@
package com.android.server.wm;
+import static com.android.server.wm.WindowManagerDebugConfig.TAG_WITH_CLASS_NAME;
+import static com.android.server.wm.WindowManagerDebugConfig.TAG_WM;
+
import android.annotation.Nullable;
import android.os.IBinder;
import android.os.RemoteException;
import android.os.UserHandle;
import android.util.ArrayMap;
+import android.util.Slog;
import android.view.IWindow;
import android.view.InputApplicationHandle;
@@ -33,12 +37,15 @@ import android.view.InputApplicationHandle;
* the host window to send pointerDownOutsideFocus.
*/
class EmbeddedWindowController {
+ private static final String TAG = TAG_WITH_CLASS_NAME ? "EmbeddedWindowController" : TAG_WM;
/* maps input token to an embedded window */
private ArrayMap<IBinder /*input token */, EmbeddedWindow> mWindows = new ArrayMap<>();
- private final Object mWmLock;
+ private final Object mGlobalLock;
+ private final ActivityTaskManagerService mAtmService;
- EmbeddedWindowController(Object wmLock) {
- mWmLock = wmLock;
+ EmbeddedWindowController(ActivityTaskManagerService atmService) {
+ mAtmService = atmService;
+ mGlobalLock = atmService.getGlobalLock();
}
/**
@@ -46,13 +53,14 @@ class EmbeddedWindowController {
*
* @param inputToken input channel token passed in by the embedding process when it requests
* the server to add an input channel to the embedded surface.
- * @param embeddedWindow An {@link EmbeddedWindow} object to add to this controller.
+ * @param window An {@link EmbeddedWindow} object to add to this controller.
*/
- void add(IBinder inputToken, EmbeddedWindow embeddedWindow) {
+ void add(IBinder inputToken, EmbeddedWindow window) {
try {
- mWindows.put(inputToken, embeddedWindow);
- embeddedWindow.mClient.asBinder().linkToDeath(()-> {
- synchronized (mWmLock) {
+ mWindows.put(inputToken, window);
+ updateProcessController(window);
+ window.mClient.asBinder().linkToDeath(()-> {
+ synchronized (mGlobalLock) {
mWindows.remove(inputToken);
}
}, 0);
@@ -62,6 +70,23 @@ class EmbeddedWindowController {
}
}
+ /**
+ * Track the host activity in the embedding process so we can determine if the
+ * process is currently showing any UI to the user.
+ */
+ private void updateProcessController(EmbeddedWindow window) {
+ if (window.mHostActivityRecord == null) {
+ return;
+ }
+ final WindowProcessController processController =
+ mAtmService.getProcessController(window.mOwnerPid, window.mOwnerUid);
+ if (processController == null) {
+ Slog.w(TAG, "Could not find the embedding process.");
+ } else {
+ processController.addHostActivity(window.mHostActivityRecord);
+ }
+ }
+
WindowState getHostWindow(IBinder inputToken) {
EmbeddedWindow embeddedWindow = mWindows.get(inputToken);
return embeddedWindow != null ? embeddedWindow.mHostWindowState : null;
@@ -76,7 +101,7 @@ class EmbeddedWindowController {
}
}
- void removeWindowsWithHost(WindowState host) {
+ void onWindowRemoved(WindowState host) {
for (int i = mWindows.size() - 1; i >= 0; i--) {
if (mWindows.valueAt(i).mHostWindowState == host) {
mWindows.removeAt(i);
@@ -88,9 +113,23 @@ class EmbeddedWindowController {
return mWindows.get(inputToken);
}
+ void onActivityRemoved(ActivityRecord activityRecord) {
+ for (int i = mWindows.size() - 1; i >= 0; i--) {
+ final EmbeddedWindow window = mWindows.valueAt(i);
+ if (window.mHostActivityRecord == activityRecord) {
+ final WindowProcessController processController =
+ mAtmService.getProcessController(window.mOwnerPid, window.mOwnerUid);
+ if (processController != null) {
+ processController.removeHostActivity(activityRecord);
+ }
+ }
+ }
+ }
+
static class EmbeddedWindow {
final IWindow mClient;
@Nullable final WindowState mHostWindowState;
+ @Nullable final ActivityRecord mHostActivityRecord;
final int mOwnerUid;
final int mOwnerPid;
@@ -107,6 +146,8 @@ class EmbeddedWindowController {
int ownerPid) {
mClient = clientToken;
mHostWindowState = hostWindowState;
+ mHostActivityRecord = (mHostWindowState != null) ? mHostWindowState.mActivityRecord
+ : null;
mOwnerUid = ownerUid;
mOwnerPid = ownerPid;
}
diff --git a/services/core/java/com/android/server/wm/ImeInsetsSourceProvider.java b/services/core/java/com/android/server/wm/ImeInsetsSourceProvider.java
index 725596819b79..7491376cd152 100644
--- a/services/core/java/com/android/server/wm/ImeInsetsSourceProvider.java
+++ b/services/core/java/com/android/server/wm/ImeInsetsSourceProvider.java
@@ -64,13 +64,14 @@ class ImeInsetsSourceProvider extends InsetsSourceProvider {
ProtoLog.d(WM_DEBUG_IME, "Run showImeRunner");
// Target should still be the same.
if (isImeTargetFromDisplayContentAndImeSame()) {
+ final InsetsControlTarget target = mDisplayContent.mInputMethodControlTarget;
ProtoLog.d(WM_DEBUG_IME, "call showInsets(ime) on %s",
- mDisplayContent.mInputMethodControlTarget.getWindow().getName());
- mDisplayContent.mInputMethodControlTarget.showInsets(
- WindowInsets.Type.ime(), true /* fromIme */);
+ target.getWindow() != null ? target.getWindow().getName() : "");
+ target.showInsets(WindowInsets.Type.ime(), true /* fromIme */);
}
abortShowImePostLayout();
};
+ mDisplayContent.mWmService.requestTraversal();
}
void checkShowImePostLayout() {
diff --git a/services/core/java/com/android/server/wm/InsetsControlTarget.java b/services/core/java/com/android/server/wm/InsetsControlTarget.java
index 20e8f2ba485a..bbc6c2bd4bcd 100644
--- a/services/core/java/com/android/server/wm/InsetsControlTarget.java
+++ b/services/core/java/com/android/server/wm/InsetsControlTarget.java
@@ -23,7 +23,12 @@ import android.view.WindowInsets.Type.InsetsType;
* Generalization of an object that can control insets state.
*/
interface InsetsControlTarget {
- void notifyInsetsControlChanged();
+
+ /**
+ * Notifies the control target that the insets control has changed.
+ */
+ default void notifyInsetsControlChanged() {
+ };
/**
* @return {@link WindowState} of this target, if any.
diff --git a/services/core/java/com/android/server/wm/InsetsPolicy.java b/services/core/java/com/android/server/wm/InsetsPolicy.java
index f6bf39739cb8..01f98888c777 100644
--- a/services/core/java/com/android/server/wm/InsetsPolicy.java
+++ b/services/core/java/com/android/server/wm/InsetsPolicy.java
@@ -57,9 +57,11 @@ class InsetsPolicy {
private final InsetsStateController mStateController;
private final DisplayContent mDisplayContent;
private final DisplayPolicy mPolicy;
- private final TransientControlTarget mTransientControlTarget = new TransientControlTarget();
private final IntArray mShowingTransientTypes = new IntArray();
+ /** For resetting visibilities of insets sources. */
+ private final InsetsControlTarget mDummyControlTarget = new InsetsControlTarget() { };
+
private WindowState mFocusedWin;
private BarWindow mStatusBar = new BarWindow(StatusBarManager.WINDOW_STATUS_BAR);
private BarWindow mNavBar = new BarWindow(StatusBarManager.WINDOW_NAVIGATION_BAR);
@@ -143,12 +145,15 @@ class InsetsPolicy {
*/
InsetsState getInsetsForDispatch(WindowState target) {
InsetsState state = mStateController.getInsetsForDispatch(target);
- if (mShowingTransientTypes.size() == 0) {
- return state;
- }
for (int i = mShowingTransientTypes.size() - 1; i >= 0; i--) {
state.setSourceVisible(mShowingTransientTypes.get(i), false);
}
+ if (mFocusedWin != null && getStatusControlTarget(mFocusedWin) == mDummyControlTarget) {
+ state.setSourceVisible(ITYPE_STATUS_BAR, mFocusedWin.getRequestedInsetsState());
+ }
+ if (mFocusedWin != null && getNavControlTarget(mFocusedWin) == mDummyControlTarget) {
+ state.setSourceVisible(ITYPE_NAVIGATION_BAR, mFocusedWin.getRequestedInsetsState());
+ }
return state;
}
@@ -194,71 +199,71 @@ class InsetsPolicy {
private @Nullable InsetsControlTarget getFakeStatusControlTarget(
@Nullable WindowState focused) {
- if (mShowingTransientTypes.indexOf(ITYPE_STATUS_BAR) != -1) {
- return focused;
- }
- return null;
+ return getStatusControlTarget(focused) == mDummyControlTarget ? focused : null;
}
private @Nullable InsetsControlTarget getFakeNavControlTarget(@Nullable WindowState focused) {
- if (mShowingTransientTypes.indexOf(ITYPE_NAVIGATION_BAR) != -1) {
- return focused;
- }
- return null;
+ return getNavControlTarget(focused) == mDummyControlTarget ? focused : null;
}
private @Nullable InsetsControlTarget getStatusControlTarget(@Nullable WindowState focusedWin) {
if (mShowingTransientTypes.indexOf(ITYPE_STATUS_BAR) != -1) {
- return mTransientControlTarget;
+ return mDummyControlTarget;
}
if (focusedWin == mPolicy.getNotificationShade()) {
// Notification shade has control anyways, no reason to force anything.
return focusedWin;
}
- if (areSystemBarsForciblyVisible() || isKeyguardOrStatusBarForciblyVisible()) {
+ if (forceShowsSystemBarsForWindowingMode()) {
+ // Status bar is forcibly shown for the windowing mode which is a steady state.
+ // We don't want the client to control the status bar, and we will dispatch the real
+ // visibility of status bar to the client.
return null;
}
+ if (forceShowsStatusBarTransiently()) {
+ // Status bar is forcibly shown transiently, and its new visibility won't be
+ // dispatched to the client so that we can keep the layout stable. We will dispatch the
+ // fake control to the client, so that it can re-show the bar during this scenario.
+ return mDummyControlTarget;
+ }
return focusedWin;
}
private @Nullable InsetsControlTarget getNavControlTarget(@Nullable WindowState focusedWin) {
if (mShowingTransientTypes.indexOf(ITYPE_NAVIGATION_BAR) != -1) {
- return mTransientControlTarget;
+ return mDummyControlTarget;
}
if (focusedWin == mPolicy.getNotificationShade()) {
// Notification shade has control anyways, no reason to force anything.
return focusedWin;
}
- if (areSystemBarsForciblyVisible() || isNavBarForciblyVisible()) {
+ if (forceShowsSystemBarsForWindowingMode()) {
+ // Navigation bar is forcibly shown for the windowing mode which is a steady state.
+ // We don't want the client to control the navigation bar, and we will dispatch the real
+ // visibility of navigation bar to the client.
return null;
}
+ if (forceShowsNavigationBarTransiently()) {
+ // Navigation bar is forcibly shown transiently, and its new visibility won't be
+ // dispatched to the client so that we can keep the layout stable. We will dispatch the
+ // fake control to the client, so that it can re-show the bar during this scenario.
+ return mDummyControlTarget;
+ }
return focusedWin;
}
- private boolean isKeyguardOrStatusBarForciblyVisible() {
- final WindowState statusBar = mPolicy.getStatusBar();
- if (statusBar != null) {
- // TODO(b/118118435): Pretend to the app that it's still able to control it?
- if ((statusBar.mAttrs.privateFlags & PRIVATE_FLAG_FORCE_SHOW_STATUS_BAR) != 0) {
- return true;
- }
- }
- return false;
+ private boolean forceShowsStatusBarTransiently() {
+ final WindowState win = mPolicy.getStatusBar();
+ return win != null && (win.mAttrs.privateFlags & PRIVATE_FLAG_FORCE_SHOW_STATUS_BAR) != 0;
}
- private boolean isNavBarForciblyVisible() {
- final WindowState notificationShade = mPolicy.getNotificationShade();
- if (notificationShade == null) {
- return false;
- }
- if ((notificationShade.mAttrs.privateFlags
- & PRIVATE_FLAG_STATUS_FORCE_SHOW_NAVIGATION) != 0) {
- return true;
- }
- return false;
+ private boolean forceShowsNavigationBarTransiently() {
+ final WindowState win = mPolicy.getNotificationShade();
+ return win != null
+ && (win.mAttrs.privateFlags & PRIVATE_FLAG_STATUS_FORCE_SHOW_NAVIGATION) != 0;
}
- private boolean areSystemBarsForciblyVisible() {
+ private boolean forceShowsSystemBarsForWindowingMode() {
final boolean isDockedStackVisible =
mDisplayContent.isStackVisible(WINDOWING_MODE_SPLIT_SCREEN_PRIMARY);
final boolean isFreeformStackVisible =
@@ -279,7 +284,7 @@ class InsetsPolicy {
for (int i = showingTransientTypes.size() - 1; i >= 0; i--) {
InsetsSourceProvider provider =
mStateController.getSourceProvider(showingTransientTypes.get(i));
- InsetsSourceControl control = provider.getControl(mTransientControlTarget);
+ InsetsSourceControl control = provider.getControl(mDummyControlTarget);
if (control == null || control.getLeash() == null) {
continue;
}
@@ -412,11 +417,4 @@ class InsetsPolicy {
}
}
}
-
- private class TransientControlTarget implements InsetsControlTarget {
-
- @Override
- public void notifyInsetsControlChanged() {
- }
- }
}
diff --git a/services/core/java/com/android/server/wm/InsetsSourceProvider.java b/services/core/java/com/android/server/wm/InsetsSourceProvider.java
index 58aefdc0e547..ada6d4710967 100644
--- a/services/core/java/com/android/server/wm/InsetsSourceProvider.java
+++ b/services/core/java/com/android/server/wm/InsetsSourceProvider.java
@@ -274,7 +274,7 @@ class InsetsSourceProvider {
// window crop of the surface controls (including the leash) until the client finishes
// drawing the new frame of the new orientation. Although we cannot defer the reparent
// operation, it is fine, because reparent won't cause any visual effect.
- final SurfaceControl barrier = mWin.getDeferTransactionBarrier();
+ final SurfaceControl barrier = mWin.getClientViewRootSurface();
t.deferTransactionUntil(mWin.getSurfaceControl(), barrier, frameNumber);
t.deferTransactionUntil(leash, barrier, frameNumber);
}
diff --git a/services/core/java/com/android/server/wm/InsetsStateController.java b/services/core/java/com/android/server/wm/InsetsStateController.java
index b3890cd84196..6ff029bfaea1 100644
--- a/services/core/java/com/android/server/wm/InsetsStateController.java
+++ b/services/core/java/com/android/server/wm/InsetsStateController.java
@@ -18,10 +18,14 @@ package com.android.server.wm;
import static android.view.InsetsState.ITYPE_CAPTION_BAR;
import static android.view.InsetsState.ITYPE_IME;
+import static android.view.InsetsState.ITYPE_INVALID;
import static android.view.InsetsState.ITYPE_NAVIGATION_BAR;
import static android.view.InsetsState.ITYPE_STATUS_BAR;
import static android.view.ViewRootImpl.NEW_INSETS_MODE_FULL;
import static android.view.ViewRootImpl.sNewInsetsMode;
+import static android.view.WindowManager.LayoutParams.TYPE_INPUT_METHOD;
+import static android.view.WindowManager.LayoutParams.TYPE_NAVIGATION_BAR;
+import static android.view.WindowManager.LayoutParams.TYPE_STATUS_BAR;
import android.annotation.NonNull;
import android.annotation.Nullable;
@@ -32,6 +36,7 @@ import android.view.InsetsSource;
import android.view.InsetsSourceControl;
import android.view.InsetsState;
import android.view.InsetsState.InternalInsetsType;
+import android.view.WindowManager;
import java.io.PrintWriter;
import java.util.ArrayList;
@@ -61,8 +66,7 @@ class InsetsStateController {
w.notifyInsetsChanged();
}
};
- private final InsetsControlTarget mEmptyImeControlTarget = () -> {
- };
+ private final InsetsControlTarget mEmptyImeControlTarget = new InsetsControlTarget() { };
InsetsStateController(DisplayContent displayContent) {
mDisplayContent = displayContent;
@@ -75,15 +79,40 @@ class InsetsStateController {
* @param target The client we dispatch the state to.
* @return The state stripped of the necessary information.
*/
- InsetsState getInsetsForDispatch(WindowState target) {
+ InsetsState getInsetsForDispatch(@NonNull WindowState target) {
final InsetsSourceProvider provider = target.getControllableInsetProvider();
if (provider == null) {
return mState;
}
+ final @InternalInsetsType int type = provider.getSource().getType();
+ return getInsetsForType(type);
+ }
+
+ InsetsState getInsetsForWindowMetrics(@NonNull WindowManager.LayoutParams attrs) {
+ final @InternalInsetsType int type = getInsetsTypeForWindowType(attrs.type);
+ if (type == ITYPE_INVALID) {
+ return mState;
+ }
+ return getInsetsForType(type);
+ }
+
+ @InternalInsetsType
+ private static int getInsetsTypeForWindowType(int type) {
+ switch(type) {
+ case TYPE_STATUS_BAR:
+ return ITYPE_STATUS_BAR;
+ case TYPE_NAVIGATION_BAR:
+ return ITYPE_NAVIGATION_BAR;
+ case TYPE_INPUT_METHOD:
+ return ITYPE_IME;
+ default:
+ return ITYPE_INVALID;
+ }
+ }
+ private InsetsState getInsetsForType(@InternalInsetsType int type) {
final InsetsState state = new InsetsState();
state.set(mState);
- final int type = provider.getSource().getType();
state.removeSource(type);
// Navigation bar doesn't get influenced by anything else
diff --git a/services/core/java/com/android/server/wm/RecentTasks.java b/services/core/java/com/android/server/wm/RecentTasks.java
index 3771b3ee9dc9..fc358ce7675f 100644
--- a/services/core/java/com/android/server/wm/RecentTasks.java
+++ b/services/core/java/com/android/server/wm/RecentTasks.java
@@ -56,7 +56,6 @@ import android.content.pm.ParceledListSlice;
import android.content.pm.UserInfo;
import android.content.res.Resources;
import android.graphics.Bitmap;
-import android.os.Bundle;
import android.os.Environment;
import android.os.IBinder;
import android.os.RemoteException;
@@ -874,16 +873,16 @@ class RecentTasks {
* @return the list of recent tasks for presentation.
*/
ParceledListSlice<ActivityManager.RecentTaskInfo> getRecentTasks(int maxNum, int flags,
- boolean getTasksAllowed, boolean getDetailedTasks, int userId, int callingUid) {
+ boolean getTasksAllowed, int userId, int callingUid) {
return new ParceledListSlice<>(getRecentTasksImpl(maxNum, flags, getTasksAllowed,
- getDetailedTasks, userId, callingUid));
+ userId, callingUid));
}
/**
* @return the list of recent tasks for presentation.
*/
private ArrayList<ActivityManager.RecentTaskInfo> getRecentTasksImpl(int maxNum, int flags,
- boolean getTasksAllowed, boolean getDetailedTasks, int userId, int callingUid) {
+ boolean getTasksAllowed, int userId, int callingUid) {
final boolean withExcluded = (flags & RECENT_WITH_EXCLUDED) != 0;
if (!isUserRunning(userId, FLAG_AND_UNLOCKED)) {
@@ -961,12 +960,7 @@ class RecentTasks {
continue;
}
- final ActivityManager.RecentTaskInfo rti = createRecentTaskInfo(task);
- if (!getDetailedTasks) {
- rti.baseIntent.replaceExtras((Bundle) null);
- }
-
- res.add(rti);
+ res.add(createRecentTaskInfo(task));
}
return res;
}
@@ -1745,8 +1739,7 @@ class RecentTasks {
// Reset the header flag for the next block
printedHeader = false;
ArrayList<ActivityManager.RecentTaskInfo> tasks = getRecentTasksImpl(Integer.MAX_VALUE,
- 0, true /* getTasksAllowed */, false /* getDetailedTasks */,
- mService.getCurrentUserId(), SYSTEM_UID);
+ 0, true /* getTasksAllowed */, mService.getCurrentUserId(), SYSTEM_UID);
for (int i = 0; i < tasks.size(); i++) {
final ActivityManager.RecentTaskInfo taskInfo = tasks.get(i);
if (!printedHeader) {
diff --git a/services/core/java/com/android/server/wm/RecentsAnimationController.java b/services/core/java/com/android/server/wm/RecentsAnimationController.java
index 5cd016922e68..3e5cb50d6101 100644
--- a/services/core/java/com/android/server/wm/RecentsAnimationController.java
+++ b/services/core/java/com/android/server/wm/RecentsAnimationController.java
@@ -820,15 +820,19 @@ public class RecentsAnimationController implements DeathRecipient {
private @AnimationType int mLastAnimationType;
private final boolean mIsRecentTaskInvisible;
private RemoteAnimationTarget mTarget;
- private final Point mPosition = new Point();
private final Rect mBounds = new Rect();
+ // The bounds of the target relative to its parent.
+ private Rect mLocalBounds = new Rect();
TaskAnimationAdapter(Task task, boolean isRecentTaskInvisible) {
mTask = task;
mIsRecentTaskInvisible = isRecentTaskInvisible;
- final WindowContainer container = mTask.getParent();
- mBounds.set(container.getDisplayedBounds());
- mPosition.set(mBounds.left, mBounds.top);
+ mBounds.set(mTask.getDisplayedBounds());
+
+ mLocalBounds.set(mBounds);
+ Point tmpPos = new Point();
+ mTask.getRelativeDisplayedPosition(tmpPos);
+ mLocalBounds.offsetTo(tmpPos.x, tmpPos.y);
}
RemoteAnimationTarget createRemoteAnimationTarget() {
@@ -847,8 +851,9 @@ public class RecentsAnimationController implements DeathRecipient {
: MODE_CLOSING;
mTarget = new RemoteAnimationTarget(mTask.mTaskId, mode, mCapturedLeash,
!topApp.fillsParent(), mainWindow.mWinAnimator.mLastClipRect,
- insets, mTask.getPrefixOrderIndex(), mPosition, mBounds,
- mTask.getWindowConfiguration(), mIsRecentTaskInvisible, null, null);
+ insets, mTask.getPrefixOrderIndex(), new Point(mBounds.left, mBounds.top),
+ mLocalBounds, mBounds, mTask.getWindowConfiguration(),
+ mIsRecentTaskInvisible, null, null);
return mTarget;
}
@@ -862,8 +867,8 @@ public class RecentsAnimationController implements DeathRecipient {
@AnimationType int type, OnAnimationFinishedCallback finishCallback) {
// Restore z-layering, position and stack crop until client has a chance to modify it.
t.setLayer(animationLeash, mTask.getPrefixOrderIndex());
- t.setPosition(animationLeash, mPosition.x, mPosition.y);
- mTmpRect.set(mBounds);
+ t.setPosition(animationLeash, mLocalBounds.left, mLocalBounds.top);
+ mTmpRect.set(mLocalBounds);
mTmpRect.offsetTo(0, 0);
t.setWindowCrop(animationLeash, mTmpRect);
mCapturedLeash = animationLeash;
@@ -897,7 +902,7 @@ public class RecentsAnimationController implements DeathRecipient {
pw.print(prefix); pw.println("Target: null");
}
pw.println("mIsRecentTaskInvisible=" + mIsRecentTaskInvisible);
- pw.println("mPosition=" + mPosition);
+ pw.println("mLocalBounds=" + mLocalBounds);
pw.println("mBounds=" + mBounds);
pw.println("mIsRecentTaskInvisible=" + mIsRecentTaskInvisible);
}
diff --git a/services/core/java/com/android/server/wm/RemoteAnimationController.java b/services/core/java/com/android/server/wm/RemoteAnimationController.java
index 0eb9daf26d47..35f8d343acc1 100644
--- a/services/core/java/com/android/server/wm/RemoteAnimationController.java
+++ b/services/core/java/com/android/server/wm/RemoteAnimationController.java
@@ -80,16 +80,17 @@ class RemoteAnimationController implements DeathRecipient {
*
* @param windowContainer The windows to animate.
* @param position The position app bounds, in screen coordinates.
+ * @param localBounds The bounds of the app relative to its parent.
* @param stackBounds The stack bounds of the app relative to position.
* @param startBounds The stack bounds before the transition, in screen coordinates
* @return The record representing animation(s) to run on the app.
*/
RemoteAnimationRecord createRemoteAnimationRecord(WindowContainer windowContainer,
- Point position, Rect stackBounds, Rect startBounds) {
+ Point position, Rect localBounds, Rect stackBounds, Rect startBounds) {
ProtoLog.d(WM_DEBUG_REMOTE_ANIMATIONS, "createAnimationAdapter(): container=%s",
windowContainer);
- final RemoteAnimationRecord adapters =
- new RemoteAnimationRecord(windowContainer, position, stackBounds, startBounds);
+ final RemoteAnimationRecord adapters = new RemoteAnimationRecord(windowContainer, position,
+ localBounds, stackBounds, startBounds);
mPendingAnimations.add(adapters);
return adapters;
}
@@ -355,17 +356,18 @@ class RemoteAnimationController implements DeathRecipient {
final WindowContainer mWindowContainer;
final Rect mStartBounds;
- RemoteAnimationRecord(WindowContainer windowContainer, Point endPos, Rect endBounds,
- Rect startBounds) {
+ RemoteAnimationRecord(WindowContainer windowContainer, Point endPos, Rect localBounds,
+ Rect endBounds, Rect startBounds) {
mWindowContainer = windowContainer;
- mAdapter = new RemoteAnimationAdapterWrapper(this, endPos, endBounds);
+ mAdapter = new RemoteAnimationAdapterWrapper(this, endPos, localBounds, endBounds);
if (startBounds != null) {
mStartBounds = new Rect(startBounds);
mTmpRect.set(startBounds);
mTmpRect.offsetTo(0, 0);
if (mRemoteAnimationAdapter.getChangeNeedsSnapshot()) {
mThumbnailAdapter =
- new RemoteAnimationAdapterWrapper(this, new Point(0, 0), mTmpRect);
+ new RemoteAnimationAdapterWrapper(this, new Point(0, 0), localBounds,
+ mTmpRect);
}
} else {
mStartBounds = null;
@@ -401,12 +403,14 @@ class RemoteAnimationController implements DeathRecipient {
private OnAnimationFinishedCallback mCapturedFinishCallback;
private @AnimationType int mAnimationType;
final Point mPosition = new Point();
+ final Rect mLocalBounds;
final Rect mStackBounds = new Rect();
RemoteAnimationAdapterWrapper(RemoteAnimationRecord record, Point position,
- Rect stackBounds) {
+ Rect localBounds, Rect stackBounds) {
mRecord = record;
mPosition.set(position.x, position.y);
+ mLocalBounds = localBounds;
mStackBounds.set(stackBounds);
}
diff --git a/services/core/java/com/android/server/wm/RootWindowContainer.java b/services/core/java/com/android/server/wm/RootWindowContainer.java
index ada5685e6817..15a49a791216 100644
--- a/services/core/java/com/android/server/wm/RootWindowContainer.java
+++ b/services/core/java/com/android/server/wm/RootWindowContainer.java
@@ -66,11 +66,9 @@ import static com.android.server.wm.ProtoLogGroup.WM_DEBUG_KEEP_SCREEN_ON;
import static com.android.server.wm.ProtoLogGroup.WM_DEBUG_ORIENTATION;
import static com.android.server.wm.ProtoLogGroup.WM_SHOW_SURFACE_ALLOC;
import static com.android.server.wm.ProtoLogGroup.WM_SHOW_TRANSACTIONS;
-import static com.android.server.wm.RootWindowContainerProto.DISPLAYS;
import static com.android.server.wm.RootWindowContainerProto.IS_HOME_RECENTS_COMPONENT;
import static com.android.server.wm.RootWindowContainerProto.KEYGUARD_CONTROLLER;
import static com.android.server.wm.RootWindowContainerProto.PENDING_ACTIVITIES;
-import static com.android.server.wm.RootWindowContainerProto.WINDOWS;
import static com.android.server.wm.RootWindowContainerProto.WINDOW_CONTAINER;
import static com.android.server.wm.Task.REPARENT_LEAVE_STACK_IN_PLACE;
import static com.android.server.wm.Task.REPARENT_MOVE_STACK_TO_FRONT;
@@ -1278,18 +1276,6 @@ class RootWindowContainer extends WindowContainer<DisplayContent>
final long token = proto.start(fieldId);
super.dumpDebug(proto, WINDOW_CONTAINER, logLevel);
- if (mWmService.mDisplayReady) {
- final int count = mChildren.size();
- for (int i = 0; i < count; ++i) {
- final DisplayContent displayContent = mChildren.get(i);
- displayContent.dumpDebug(proto, DISPLAYS, logLevel);
- }
- }
- if (logLevel == WindowTraceLogLevel.ALL) {
- forAllWindows((w) -> {
- w.dumpDebug(proto, WINDOWS, logLevel);
- }, true);
- }
mStackSupervisor.getKeyguardController().dumpDebug(proto, KEYGUARD_CONTROLLER);
proto.write(IS_HOME_RECENTS_COMPONENT,
@@ -1980,7 +1966,9 @@ class RootWindowContainer extends WindowContainer<DisplayContent>
}
boolean switchUser(int userId, UserState uss) {
- final int focusStackId = getTopDisplayFocusedStack().getRootTaskId();
+ final ActivityStack topFocusedStack = getTopDisplayFocusedStack();
+ final int focusStackId = topFocusedStack != null
+ ? topFocusedStack.getRootTaskId() : INVALID_TASK_ID;
// We dismiss the docked stack whenever we switch users.
final ActivityStack dockedStack = getDefaultDisplay().getRootSplitScreenPrimaryTask();
if (dockedStack != null) {
@@ -2263,8 +2251,8 @@ class RootWindowContainer extends WindowContainer<DisplayContent>
final ActivityStack focusedStack = display.getFocusedStack();
if (focusedStack != null) {
result |= focusedStack.resumeTopActivityUncheckedLocked(target, targetOptions);
- } else if (targetStack == null && display.getStackCount() == 0) {
- result |= resumeHomeActivity(null /* prev */, "empty-display",
+ } else if (targetStack == null) {
+ result |= resumeHomeActivity(null /* prev */, "no-focusable-task",
display.mDisplayId);
}
}
@@ -3455,7 +3443,12 @@ class RootWindowContainer extends WindowContainer<DisplayContent>
ArrayList<ActivityRecord> getDumpActivities(String name, boolean dumpVisibleStacksOnly,
boolean dumpFocusedStackOnly) {
if (dumpFocusedStackOnly) {
- return getTopDisplayFocusedStack().getDumpActivitiesLocked(name);
+ final ActivityStack topFocusedStack = getTopDisplayFocusedStack();
+ if (topFocusedStack != null) {
+ return topFocusedStack.getDumpActivitiesLocked(name);
+ } else {
+ return new ArrayList<>();
+ }
} else {
ArrayList<ActivityRecord> activities = new ArrayList<>();
int numDisplays = getChildCount();
diff --git a/services/core/java/com/android/server/wm/RunningTasks.java b/services/core/java/com/android/server/wm/RunningTasks.java
index 9593ea070509..02077fbf453e 100644
--- a/services/core/java/com/android/server/wm/RunningTasks.java
+++ b/services/core/java/com/android/server/wm/RunningTasks.java
@@ -28,7 +28,6 @@ import android.util.ArraySet;
import com.android.internal.util.function.pooled.PooledConsumer;
import com.android.internal.util.function.pooled.PooledLambda;
-import java.util.ArrayList;
import java.util.Comparator;
import java.util.Iterator;
import java.util.List;
@@ -44,7 +43,6 @@ class RunningTasks {
(o1, o2) -> Long.signum(o2.lastActiveTime - o1.lastActiveTime);
private final TreeSet<Task> mTmpSortedSet = new TreeSet<>(LAST_ACTIVE_TIME_COMPARATOR);
- private final ArrayList<Task> mTmpStackTasks = new ArrayList<>();
private int mCallingUid;
private int mUserId;
@@ -132,8 +130,7 @@ class RunningTasks {
/** Constructs a {@link RunningTaskInfo} from a given {@param task}. */
private RunningTaskInfo createRunningTaskInfo(Task task) {
- final RunningTaskInfo rti = new RunningTaskInfo();
- task.fillTaskInfo(rti);
+ final RunningTaskInfo rti = task.getTaskInfo();
// Fill in some deprecated values
rti.id = rti.taskId;
return rti;
diff --git a/services/core/java/com/android/server/wm/SeamlessRotator.java b/services/core/java/com/android/server/wm/SeamlessRotator.java
index 024da888248d..8e1c6329f39d 100644
--- a/services/core/java/com/android/server/wm/SeamlessRotator.java
+++ b/services/core/java/com/android/server/wm/SeamlessRotator.java
@@ -118,9 +118,9 @@ public class SeamlessRotator {
finish(t, win);
if (win.mWinAnimator.mSurfaceController != null && !timeout) {
t.deferTransactionUntil(win.mSurfaceControl,
- win.getDeferTransactionBarrier(), win.getFrameNumber());
+ win.getClientViewRootSurface(), win.getFrameNumber());
t.deferTransactionUntil(win.mWinAnimator.mSurfaceController.mSurfaceControl,
- win.getDeferTransactionBarrier(), win.getFrameNumber());
+ win.getClientViewRootSurface(), win.getFrameNumber());
}
}
diff --git a/services/core/java/com/android/server/wm/SurfaceAnimator.java b/services/core/java/com/android/server/wm/SurfaceAnimator.java
index 3b3234a4bec0..19f8ca912449 100644
--- a/services/core/java/com/android/server/wm/SurfaceAnimator.java
+++ b/services/core/java/com/android/server/wm/SurfaceAnimator.java
@@ -379,10 +379,8 @@ class SurfaceAnimator {
final SurfaceControl.Builder builder = animatable.makeAnimationLeash()
.setParent(animatable.getAnimationLeashParent())
.setHidden(hidden)
- .setName(surface + " - animation-leash")
- .setColorLayer();
+ .setName(surface + " - animation-leash");
final SurfaceControl leash = builder.build();
- t.unsetColor(leash);
t.setWindowCrop(leash, width, height);
t.setPosition(leash, x, y);
t.show(leash);
diff --git a/services/core/java/com/android/server/wm/Task.java b/services/core/java/com/android/server/wm/Task.java
index 92cefeed39a9..b2db99b06cde 100644
--- a/services/core/java/com/android/server/wm/Task.java
+++ b/services/core/java/com/android/server/wm/Task.java
@@ -85,6 +85,7 @@ import static com.android.server.wm.IdentifierProto.USER_ID;
import static com.android.server.wm.ProtoLogGroup.WM_DEBUG_ADD_REMOVE;
import static com.android.server.wm.WindowContainer.AnimationFlags.CHILDREN;
import static com.android.server.wm.WindowContainer.AnimationFlags.TRANSITION;
+import static com.android.server.wm.WindowContainerChildProto.TASK;
import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_STACK;
import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_TASK_MOVEMENT;
import static com.android.server.wm.WindowManagerDebugConfig.TAG_WM;
@@ -581,10 +582,10 @@ class Task extends WindowContainer<WindowContainer> {
}
Task reuseAsLeafTask(IVoiceInteractionSession _voiceSession, IVoiceInteractor _voiceInteractor,
- ActivityInfo info, ActivityRecord activity) {
+ Intent intent, ActivityInfo info, ActivityRecord activity) {
voiceSession = _voiceSession;
voiceInteractor = _voiceInteractor;
- setIntent(activity);
+ setIntent(activity, intent, info);
setMinDimensions(info);
return this;
}
@@ -919,12 +920,23 @@ class Task extends WindowContainer<WindowContainer> {
return SystemClock.elapsedRealtime() - lastActiveTime;
}
- /** Sets the original intent, and the calling uid and package. */
+ /** @see #setIntent(ActivityRecord, Intent, ActivityInfo) */
void setIntent(ActivityRecord r) {
+ setIntent(r, null /* intent */, null /* info */);
+ }
+
+ /**
+ * Sets the original intent, and the calling uid and package.
+ *
+ * @param r The activity that started the task
+ * @param intent The task info which could be different from {@code r.intent} if set.
+ * @param info The activity info which could be different from {@code r.info} if set.
+ */
+ void setIntent(ActivityRecord r, @Nullable Intent intent, @Nullable ActivityInfo info) {
mCallingUid = r.launchedFromUid;
mCallingPackage = r.launchedFromPackage;
mCallingFeatureId = r.launchedFromFeatureId;
- setIntent(r.intent, r.info);
+ setIntent(intent != null ? intent : r.intent, info != null ? info : r.info);
setLockTaskAuth(r);
final WindowContainer parent = getParent();
@@ -2109,8 +2121,29 @@ class Task extends WindowContainer<WindowContainer> {
}
void computeConfigResourceOverrides(@NonNull Configuration inOutConfig,
+ @NonNull Configuration parentConfig, @Nullable DisplayInfo overrideDisplayInfo) {
+ if (overrideDisplayInfo != null) {
+ // Make sure the screen related configs can be computed by the provided display info.
+ inOutConfig.windowConfiguration.setAppBounds(null);
+ inOutConfig.screenLayout = Configuration.SCREENLAYOUT_UNDEFINED;
+ inOutConfig.screenWidthDp = Configuration.SCREEN_WIDTH_DP_UNDEFINED;
+ inOutConfig.screenHeightDp = Configuration.SCREEN_HEIGHT_DP_UNDEFINED;
+ }
+ computeConfigResourceOverrides(inOutConfig, parentConfig, overrideDisplayInfo,
+ null /* compatInsets */);
+ }
+
+ void computeConfigResourceOverrides(@NonNull Configuration inOutConfig,
@NonNull Configuration parentConfig) {
- computeConfigResourceOverrides(inOutConfig, parentConfig, null /* compatInsets */);
+ computeConfigResourceOverrides(inOutConfig, parentConfig, null /* overrideDisplayInfo */,
+ null /* compatInsets */);
+ }
+
+ void computeConfigResourceOverrides(@NonNull Configuration inOutConfig,
+ @NonNull Configuration parentConfig,
+ @Nullable ActivityRecord.CompatDisplayInsets compatInsets) {
+ computeConfigResourceOverrides(inOutConfig, parentConfig, null /* overrideDisplayInfo */,
+ compatInsets);
}
/**
@@ -2122,7 +2155,7 @@ class Task extends WindowContainer<WindowContainer> {
* just be inherited from the parent configuration.
**/
void computeConfigResourceOverrides(@NonNull Configuration inOutConfig,
- @NonNull Configuration parentConfig,
+ @NonNull Configuration parentConfig, @Nullable DisplayInfo overrideDisplayInfo,
@Nullable ActivityRecord.CompatDisplayInsets compatInsets) {
int windowingMode = inOutConfig.windowConfiguration.getWindowingMode();
if (windowingMode == WINDOWING_MODE_UNDEFINED) {
@@ -2165,9 +2198,11 @@ class Task extends WindowContainer<WindowContainer> {
if (insideParentBounds && WindowConfiguration.isFloating(windowingMode)) {
mTmpNonDecorBounds.set(mTmpFullBounds);
mTmpStableBounds.set(mTmpFullBounds);
- } else if (insideParentBounds && getDisplayContent() != null) {
- final DisplayInfo di = new DisplayInfo();
- getDisplayContent().mDisplay.getDisplayInfo(di);
+ } else if (insideParentBounds
+ && (overrideDisplayInfo != null || getDisplayContent() != null)) {
+ final DisplayInfo di = overrideDisplayInfo != null
+ ? overrideDisplayInfo
+ : getDisplayContent().getDisplayInfo();
// For calculating screenWidthDp, screenWidthDp, we use the stable inset screen
// area, i.e. the screen area without the system bars.
@@ -2184,7 +2219,7 @@ class Task extends WindowContainer<WindowContainer> {
if (rotation != ROTATION_UNDEFINED && compatInsets != null) {
mTmpNonDecorBounds.set(mTmpFullBounds);
mTmpStableBounds.set(mTmpFullBounds);
- compatInsets.getDisplayBoundsByRotation(mTmpBounds, rotation);
+ compatInsets.getBoundsByRotation(mTmpBounds, rotation);
intersectWithInsetsIfFits(mTmpNonDecorBounds, mTmpBounds,
compatInsets.mNonDecorInsets[rotation]);
intersectWithInsetsIfFits(mTmpStableBounds, mTmpBounds,
@@ -3087,6 +3122,11 @@ class Task extends WindowContainer<WindowContainer> {
return activity != null ? activity.createRemoteAnimationTarget(record) : null;
}
+ @Override
+ boolean canCreateRemoteAnimationTarget() {
+ return true;
+ }
+
WindowState getTopVisibleAppMainWindow() {
final ActivityRecord activity = getTopVisibleActivity();
return activity != null ? activity.findMainWindow() : null;
@@ -3281,8 +3321,8 @@ class Task extends WindowContainer<WindowContainer> {
}
/**
- * Fills in a {@link TaskInfo} with information from this task.
- * @param info the {@link TaskInfo} to fill in
+ * Fills in a {@link TaskInfo} with information from this task. Note that the base intent in the
+ * task info will not include any extras or clip data.
*/
void fillTaskInfo(TaskInfo info) {
getNumRunningActivities(mReuseActivitiesReport);
@@ -3294,7 +3334,7 @@ class Task extends WindowContainer<WindowContainer> {
final Intent baseIntent = getBaseIntent();
// Make a copy of base intent because this is like a snapshot info.
// Besides, {@link RecentTasks#getRecentTasksImpl} may modify it.
- info.baseIntent = baseIntent == null ? new Intent() : new Intent(baseIntent);
+ info.baseIntent = baseIntent == null ? new Intent() : baseIntent.cloneFilter();
info.baseActivity = mReuseActivitiesReport.base != null
? mReuseActivitiesReport.base.intent.getComponent()
: null;
@@ -3931,12 +3971,12 @@ class Task extends WindowContainer<WindowContainer> {
boolean isControlledByTaskOrganizer() {
final Task rootTask = getRootTask();
- return rootTask == this && rootTask.mTaskOrganizer != null
- // TODO(task-hierarchy): Figure out how to control nested tasks.
- // For now, if this is in a tile let WM drive.
- && !(rootTask instanceof TaskTile)
- && !(rootTask instanceof ActivityStack
- && ((ActivityStack) rootTask).getTile() != null);
+ // if the rootTask is a "child" of a tile, then don't consider it a root task.
+ // TODO: remove this along with removing tile.
+ if (((ActivityStack) rootTask).getTile() != null) {
+ return false;
+ }
+ return rootTask == this && rootTask.mTaskOrganizer != null;
}
@Override
@@ -4082,4 +4122,9 @@ class Task extends WindowContainer<WindowContainer> {
SurfaceControl.Transaction getMainWindowSizeChangeTransaction() {
return mMainWindowSizeChangeTransaction;
}
+
+ @Override
+ long getProtoFieldId() {
+ return TASK;
+ }
}
diff --git a/services/core/java/com/android/server/wm/TaskOrganizerController.java b/services/core/java/com/android/server/wm/TaskOrganizerController.java
index 0f1e623a38f1..b38c18bf15f3 100644
--- a/services/core/java/com/android/server/wm/TaskOrganizerController.java
+++ b/services/core/java/com/android/server/wm/TaskOrganizerController.java
@@ -253,8 +253,7 @@ class TaskOrganizerController extends ITaskOrganizerController.Stub
final int nextId = display.getNextStackId();
TaskTile tile = new TaskTile(mService, nextId, windowingMode);
display.addTile(tile);
- RunningTaskInfo out = new RunningTaskInfo();
- tile.fillTaskInfo(out);
+ RunningTaskInfo out = tile.getTaskInfo();
mLastSentTaskInfos.put(tile, out);
return out;
}
@@ -412,9 +411,7 @@ class TaskOrganizerController extends ITaskOrganizerController.Stub
&& !ArrayUtils.contains(activityTypes, as.getActivityType())) {
continue;
}
- final RunningTaskInfo info = new RunningTaskInfo();
- as.fillTaskInfo(info);
- out.add(info);
+ out.add(as.getTaskInfo());
}
}
return out;
@@ -447,9 +444,7 @@ class TaskOrganizerController extends ITaskOrganizerController.Stub
&& !ArrayUtils.contains(activityTypes, task.getActivityType())) {
continue;
}
- final RunningTaskInfo info = new RunningTaskInfo();
- task.fillTaskInfo(info);
- out.add(info);
+ out.add(task.getTaskInfo());
}
return out;
}
@@ -468,8 +463,9 @@ class TaskOrganizerController extends ITaskOrganizerController.Stub
int configMask = change.getConfigSetMask();
int windowMask = change.getWindowSetMask();
configMask &= ActivityInfo.CONFIG_WINDOW_CONFIGURATION
- | ActivityInfo.CONFIG_SMALLEST_SCREEN_SIZE;
- windowMask &= WindowConfiguration.WINDOW_CONFIG_BOUNDS;
+ | ActivityInfo.CONFIG_SMALLEST_SCREEN_SIZE | ActivityInfo.CONFIG_SCREEN_SIZE;
+ windowMask &= (WindowConfiguration.WINDOW_CONFIG_BOUNDS
+ | WindowConfiguration.WINDOW_CONFIG_APP_BOUNDS);
int effects = 0;
if (configMask != 0) {
Configuration c = new Configuration(container.getRequestedOverrideConfiguration());
diff --git a/services/core/java/com/android/server/wm/TaskPositioner.java b/services/core/java/com/android/server/wm/TaskPositioner.java
index b5892b9b4dc6..f046e8adc478 100644
--- a/services/core/java/com/android/server/wm/TaskPositioner.java
+++ b/services/core/java/com/android/server/wm/TaskPositioner.java
@@ -35,7 +35,6 @@ import static com.android.server.wm.WindowState.MINIMUM_VISIBLE_HEIGHT_IN_DP;
import static com.android.server.wm.WindowState.MINIMUM_VISIBLE_WIDTH_IN_DP;
import android.annotation.NonNull;
-import android.app.IActivityTaskManager;
import android.graphics.Point;
import android.graphics.Rect;
import android.os.Binder;
@@ -48,7 +47,6 @@ import android.util.DisplayMetrics;
import android.util.Slog;
import android.view.BatchedInputEventReceiver;
import android.view.Choreographer;
-import android.view.Display;
import android.view.InputApplicationHandle;
import android.view.InputChannel;
import android.view.InputDevice;
@@ -75,10 +73,8 @@ class TaskPositioner implements IBinder.DeathRecipient {
public static final int RESIZING_HINT_DURATION_MS = 0;
private final WindowManagerService mService;
- private final IActivityTaskManager mActivityManager;
private WindowPositionerEventReceiver mInputEventReceiver;
private DisplayContent mDisplayContent;
- private final DisplayMetrics mDisplayMetrics = new DisplayMetrics();
private Rect mTmpRect = new Rect();
private int mMinVisibleWidth;
private int mMinVisibleHeight;
@@ -151,11 +147,8 @@ class TaskPositioner implements IBinder.DeathRecipient {
if (!mTmpRect.equals(mWindowDragBounds)) {
Trace.traceBegin(TRACE_TAG_WINDOW_MANAGER,
"wm.TaskPositioner.resizeTask");
- try {
- mActivityManager.resizeTask(
- mTask.mTaskId, mWindowDragBounds, RESIZE_MODE_USER);
- } catch (RemoteException e) {
- }
+ mService.mAtmService.resizeTask(
+ mTask.mTaskId, mWindowDragBounds, RESIZE_MODE_USER);
Trace.traceEnd(Trace.TRACE_TAG_WINDOW_MANAGER);
}
} break;
@@ -181,14 +174,12 @@ class TaskPositioner implements IBinder.DeathRecipient {
endDragLocked();
mTask.getDimBounds(mTmpRect);
}
- try {
- if (wasResizing && !mTmpRect.equals(mWindowDragBounds)) {
- // We were using fullscreen surface during resizing. Request
- // resizeTask() one last time to restore surface to window size.
- mActivityManager.resizeTask(
- mTask.mTaskId, mWindowDragBounds, RESIZE_MODE_USER_FORCED);
- }
- } catch(RemoteException e) {}
+ if (wasResizing && !mTmpRect.equals(mWindowDragBounds)) {
+ // We were using fullscreen surface during resizing. Request
+ // resizeTask() one last time to restore surface to window size.
+ mService.mAtmService.resizeTask(
+ mTask.mTaskId, mWindowDragBounds, RESIZE_MODE_USER_FORCED);
+ }
// Post back to WM to handle clean-ups. We still need the input
// event handler for the last finishInputEvent()!
@@ -203,15 +194,10 @@ class TaskPositioner implements IBinder.DeathRecipient {
}
}
+ /** Use {@link #create(WindowManagerService)} instead. */
@VisibleForTesting
- TaskPositioner(WindowManagerService service, IActivityTaskManager activityManager) {
- mService = service;
- mActivityManager = activityManager;
- }
-
- /** Use {@link #create(WindowManagerService)} instead **/
TaskPositioner(WindowManagerService service) {
- this(service, service.mActivityTaskManager);
+ mService = service;
}
@VisibleForTesting
@@ -224,8 +210,6 @@ class TaskPositioner implements IBinder.DeathRecipient {
* @param win The window which will be dragged.
*/
void register(DisplayContent displayContent, @NonNull WindowState win) {
- final Display display = displayContent.getDisplay();
-
if (DEBUG_TASK_POSITIONING) {
Slog.d(TAG, "Registering task positioner");
}
@@ -236,7 +220,6 @@ class TaskPositioner implements IBinder.DeathRecipient {
}
mDisplayContent = displayContent;
- display.getMetrics(mDisplayMetrics);
final InputChannel[] channels = InputChannel.openInputChannelPair(TAG);
mServerChannel = channels[0];
mClientChannel = channels[1];
@@ -251,7 +234,8 @@ class TaskPositioner implements IBinder.DeathRecipient {
mDragApplicationHandle.dispatchingTimeoutNanos =
WindowManagerService.DEFAULT_INPUT_DISPATCHING_TIMEOUT_NANOS;
- mDragWindowHandle = new InputWindowHandle(mDragApplicationHandle, display.getDisplayId());
+ mDragWindowHandle = new InputWindowHandle(mDragApplicationHandle,
+ displayContent.getDisplayId());
mDragWindowHandle.name = TAG;
mDragWindowHandle.token = mServerChannel.getToken();
mDragWindowHandle.layoutParamsFlags = 0;
@@ -271,13 +255,13 @@ class TaskPositioner implements IBinder.DeathRecipient {
// The drag window cannot receive new touches.
mDragWindowHandle.touchableRegion.setEmpty();
- // The drag window covers the entire display
- mDragWindowHandle.frameLeft = 0;
- mDragWindowHandle.frameTop = 0;
- final Point p = new Point();
- display.getRealSize(p);
- mDragWindowHandle.frameRight = p.x;
- mDragWindowHandle.frameBottom = p.y;
+ // The drag window covers the entire display.
+ final Rect displayBounds = mTmpRect;
+ displayContent.getBounds(mTmpRect);
+ mDragWindowHandle.frameLeft = displayBounds.left;
+ mDragWindowHandle.frameTop = displayBounds.top;
+ mDragWindowHandle.frameRight = displayBounds.right;
+ mDragWindowHandle.frameBottom = displayBounds.bottom;
// Pause rotations before a drag.
ProtoLog.d(WM_DEBUG_ORIENTATION, "Pausing rotation during re-position");
@@ -287,9 +271,10 @@ class TaskPositioner implements IBinder.DeathRecipient {
mDisplayContent.getInputMonitor().updateInputWindowsImmediately();
new SurfaceControl.Transaction().syncInputWindows().apply(true);
- mMinVisibleWidth = dipToPixel(MINIMUM_VISIBLE_WIDTH_IN_DP, mDisplayMetrics);
- mMinVisibleHeight = dipToPixel(MINIMUM_VISIBLE_HEIGHT_IN_DP, mDisplayMetrics);
- display.getRealSize(mMaxVisibleSize);
+ final DisplayMetrics displayMetrics = displayContent.getDisplayMetrics();
+ mMinVisibleWidth = dipToPixel(MINIMUM_VISIBLE_WIDTH_IN_DP, displayMetrics);
+ mMinVisibleHeight = dipToPixel(MINIMUM_VISIBLE_HEIGHT_IN_DP, displayMetrics);
+ mMaxVisibleSize.set(displayBounds.width(), displayBounds.height());
mDragEnded = false;
@@ -341,8 +326,11 @@ class TaskPositioner implements IBinder.DeathRecipient {
mWindow = null;
}
- void startDrag(boolean resize, boolean preserveOrientation, float startX,
- float startY) {
+ /**
+ * Starts moving or resizing the task. This method should be only called from
+ * {@link TaskPositioningController#startPositioningLocked} or unit tests.
+ */
+ void startDrag(boolean resize, boolean preserveOrientation, float startX, float startY) {
if (DEBUG_TASK_POSITIONING) {
Slog.d(TAG, "startDrag: win=" + mWindow + ", resize=" + resize
+ ", preserveOrientation=" + preserveOrientation + ", {" + startX + ", "
@@ -351,12 +339,9 @@ class TaskPositioner implements IBinder.DeathRecipient {
// Use the bounds of the task which accounts for
// multiple app windows. Don't use any bounds from win itself as it
// may not be the same size as the task.
- mTask.getBounds(mTmpRect);
- startDrag(resize, preserveOrientation, startX, startY, mTmpRect);
- }
+ final Rect startBounds = mTmpRect;
+ mTask.getBounds(startBounds);
- protected void startDrag(boolean resize, boolean preserveOrientation,
- float startX, float startY, Rect startBounds) {
mCtrlType = CTRL_NONE;
mStartDragX = startX;
mStartDragY = startY;
@@ -389,20 +374,13 @@ class TaskPositioner implements IBinder.DeathRecipient {
// bounds yet. This will guarantee that the app starts the backdrop renderer before
// configuration changes which could cause an activity restart.
if (mResizing) {
- synchronized (mService.mGlobalLock) {
- notifyMoveLocked(startX, startY);
- }
+ notifyMoveLocked(startX, startY);
- // Perform the resize on the WMS handler thread when we don't have the WMS lock held
- // to ensure that we don't deadlock WMS and AMS. Note that WindowPositionerEventReceiver
- // callbacks are delivered on the same handler so this initial resize is always
- // guaranteed to happen before subsequent drag resizes.
+ // The WindowPositionerEventReceiver callbacks are delivered on the same handler so this
+ // initial resize is always guaranteed to happen before subsequent drag resizes.
mService.mH.post(() -> {
- try {
- mActivityManager.resizeTask(
- mTask.mTaskId, startBounds, RESIZE_MODE_USER_FORCED);
- } catch (RemoteException e) {
- }
+ mService.mAtmService.resizeTask(
+ mTask.mTaskId, startBounds, RESIZE_MODE_USER_FORCED);
});
}
@@ -417,7 +395,8 @@ class TaskPositioner implements IBinder.DeathRecipient {
}
/** Returns true if the move operation should be ended. */
- private boolean notifyMoveLocked(float x, float y) {
+ @VisibleForTesting
+ boolean notifyMoveLocked(float x, float y) {
if (DEBUG_TASK_POSITIONING) {
Slog.d(TAG, "notifyMoveLocked: {" + x + "," + y + "}");
}
@@ -429,12 +408,11 @@ class TaskPositioner implements IBinder.DeathRecipient {
}
// This is a moving or scrolling operation.
- mTask.getStack().getDimBounds(mTmpRect);
- // If a target window is covered by system bar, there is no way to move it again by touch.
- // So we exclude them from stack bounds. and then it will be shown inside stable area.
- Rect stableBounds = new Rect();
- mDisplayContent.getStableRect(stableBounds);
- mTmpRect.intersect(stableBounds);
+ // Only allow to move in stable area so the target window won't be covered by system bar.
+ // Though {@link Task#resolveOverrideConfiguration} should also avoid the case.
+ mDisplayContent.getStableRect(mTmpRect);
+ // The task may be put in a limited display area.
+ mTmpRect.intersect(mTask.getRootTask().getParent().getBounds());
int nX = (int) x;
int nY = (int) y;
diff --git a/services/core/java/com/android/server/wm/TaskTile.java b/services/core/java/com/android/server/wm/TaskTile.java
index 74d5c338a68d..205b423a38dd 100644
--- a/services/core/java/com/android/server/wm/TaskTile.java
+++ b/services/core/java/com/android/server/wm/TaskTile.java
@@ -147,7 +147,7 @@ public class TaskTile extends ActivityStack {
*/
void updateResolvedConfig(Configuration inOutResolvedConfig) {
Rect resolveBounds = inOutResolvedConfig.windowConfiguration.getBounds();
- if (resolveBounds == null || resolveBounds.isEmpty()) {
+ if (resolveBounds.isEmpty()) {
resolveBounds.set(getRequestedOverrideBounds());
}
int stackMode = inOutResolvedConfig.windowConfiguration.getWindowingMode();
@@ -162,6 +162,17 @@ public class TaskTile extends ActivityStack {
inOutResolvedConfig.smallestScreenWidthDp =
getRequestedOverrideConfiguration().smallestScreenWidthDp;
}
+ if (inOutResolvedConfig.screenWidthDp == Configuration.SCREEN_WIDTH_DP_UNDEFINED) {
+ inOutResolvedConfig.screenWidthDp = getRequestedOverrideConfiguration().screenWidthDp;
+ }
+ if (inOutResolvedConfig.screenHeightDp == Configuration.SCREEN_HEIGHT_DP_UNDEFINED) {
+ inOutResolvedConfig.screenHeightDp = getRequestedOverrideConfiguration().screenHeightDp;
+ }
+ Rect resolveAppBounds = inOutResolvedConfig.windowConfiguration.getAppBounds();
+ if (resolveAppBounds == null || resolveAppBounds.isEmpty()) {
+ inOutResolvedConfig.windowConfiguration.setAppBounds(
+ getRequestedOverrideConfiguration().windowConfiguration.getAppBounds());
+ }
}
@Override
@@ -184,7 +195,6 @@ public class TaskTile extends ActivityStack {
boolean isResizable = topTask == null || topTask.isResizeable();
info.resizeMode = isResizable ? RESIZE_MODE_RESIZEABLE : RESIZE_MODE_UNRESIZEABLE;
info.topActivityType = top == null ? ACTIVITY_TYPE_UNDEFINED : top.getActivityType();
- info.configuration.setTo(getRequestedOverrideConfiguration());
}
@Override
diff --git a/services/core/java/com/android/server/wm/WallpaperAnimationAdapter.java b/services/core/java/com/android/server/wm/WallpaperAnimationAdapter.java
index bd705998f49a..f46701536cf8 100644
--- a/services/core/java/com/android/server/wm/WallpaperAnimationAdapter.java
+++ b/services/core/java/com/android/server/wm/WallpaperAnimationAdapter.java
@@ -92,7 +92,7 @@ class WallpaperAnimationAdapter implements AnimationAdapter {
*/
RemoteAnimationTarget createRemoteAnimationTarget() {
mTarget = new RemoteAnimationTarget(-1, -1, getLeash(), false, null, null,
- mWallpaperToken.getPrefixOrderIndex(), new Point(), null,
+ mWallpaperToken.getPrefixOrderIndex(), new Point(), null, null,
mWallpaperToken.getWindowConfiguration(), true, null, null);
return mTarget;
}
diff --git a/services/core/java/com/android/server/wm/WindowAnimator.java b/services/core/java/com/android/server/wm/WindowAnimator.java
index b6be386fa181..a60db94ad1e3 100644
--- a/services/core/java/com/android/server/wm/WindowAnimator.java
+++ b/services/core/java/com/android/server/wm/WindowAnimator.java
@@ -164,6 +164,8 @@ public class WindowAnimator {
}
}
+ cancelAnimation();
+
if (mService.mWatermark != null) {
mService.mWatermark.drawIfNeeded();
}
diff --git a/services/core/java/com/android/server/wm/WindowContainer.java b/services/core/java/com/android/server/wm/WindowContainer.java
index b12c6980ccce..e8897e1dbbe2 100644
--- a/services/core/java/com/android/server/wm/WindowContainer.java
+++ b/services/core/java/com/android/server/wm/WindowContainer.java
@@ -40,6 +40,7 @@ import static com.android.server.wm.SurfaceAnimator.ANIMATION_TYPE_APP_TRANSITIO
import static com.android.server.wm.WindowContainer.AnimationFlags.CHILDREN;
import static com.android.server.wm.WindowContainer.AnimationFlags.PARENTS;
import static com.android.server.wm.WindowContainer.AnimationFlags.TRANSITION;
+import static com.android.server.wm.WindowContainerChildProto.WINDOW_CONTAINER;
import static com.android.server.wm.WindowContainerProto.CONFIGURATION_CONTAINER;
import static com.android.server.wm.WindowContainerProto.ORIENTATION;
import static com.android.server.wm.WindowContainerProto.SURFACE_ANIMATOR;
@@ -1819,9 +1820,25 @@ class WindowContainer<E extends WindowContainer> extends ConfigurationContainer<
if (mSurfaceAnimator.isAnimating()) {
mSurfaceAnimator.dumpDebug(proto, SURFACE_ANIMATOR);
}
+
+ // add children to proto
+ for (int i = 0; i < getChildCount(); i++) {
+ final long childToken = proto.start(WindowContainerProto.CHILDREN);
+ final E child = getChildAt(i);
+ child.dumpDebug(proto, child.getProtoFieldId(), logLevel);
+ proto.end(childToken);
+ }
proto.end(token);
}
+ /**
+ * @return a proto field id to identify where to add the derived class to the generic window
+ * container proto.
+ */
+ long getProtoFieldId() {
+ return WINDOW_CONTAINER;
+ }
+
private ForAllWindowsConsumerWrapper obtainConsumerWrapper(Consumer<WindowState> consumer) {
ForAllWindowsConsumerWrapper wrapper = mConsumerWrapperPool.acquire();
if (wrapper == null) {
@@ -2086,9 +2103,11 @@ class WindowContainer<E extends WindowContainer> extends ConfigurationContainer<
// Delaying animation start isn't compatible with remote animations at all.
if (controller != null && !mSurfaceAnimator.isAnimationStartDelayed()) {
+ final Rect localBounds = new Rect(mTmpRect);
+ localBounds.offsetTo(mTmpPoint.x, mTmpPoint.y);
final RemoteAnimationController.RemoteAnimationRecord adapters =
- controller.createRemoteAnimationRecord(this, mTmpPoint, mTmpRect,
- (isChanging ? mSurfaceFreezer.mFreezeBounds : null));
+ controller.createRemoteAnimationRecord(this, mTmpPoint, localBounds,
+ mTmpRect, (isChanging ? mSurfaceFreezer.mFreezeBounds : null));
resultAdapters = new Pair<>(adapters.mAdapter, adapters.mThumbnailAdapter);
} else if (isChanging) {
final float durationScale = mWmService.getTransitionAnimationScaleLocked();
@@ -2196,6 +2215,10 @@ class WindowContainer<E extends WindowContainer> extends ConfigurationContainer<
return null;
}
+ boolean canCreateRemoteAnimationTarget() {
+ return false;
+ }
+
boolean okToDisplay() {
final DisplayContent dc = getDisplayContent();
return dc != null && dc.okToDisplay();
diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java
index 3f4f629b5292..42a66adff5e5 100644
--- a/services/core/java/com/android/server/wm/WindowManagerService.java
+++ b/services/core/java/com/android/server/wm/WindowManagerService.java
@@ -1287,7 +1287,7 @@ public class WindowManagerService extends IWindowManager.Stub
mConstants.start(new HandlerExecutor(mH));
LocalServices.addService(WindowManagerInternal.class, new LocalService());
- mEmbeddedWindowController = new EmbeddedWindowController(mGlobalLock);
+ mEmbeddedWindowController = new EmbeddedWindowController(mAtmService);
mDisplayAreaPolicyProvider = DisplayAreaPolicy.Provider.fromResources(
mContext.getResources());
@@ -1900,7 +1900,7 @@ public class WindowManagerService extends IWindowManager.Stub
if (dc.mCurrentFocus == null) {
dc.mWinRemovedSinceNullFocus.add(win);
}
- mEmbeddedWindowController.removeWindowsWithHost(win);
+ mEmbeddedWindowController.onWindowRemoved(win);
mPendingRemove.remove(win);
mResizingWindows.remove(win);
updateNonSystemOverlayWindowsVisibilityIfNeeded(win, false /* surfaceShown */);
@@ -2610,7 +2610,8 @@ public class WindowManagerService extends IWindowManager.Stub
if (type == TYPE_WALLPAPER) {
new WallpaperWindowToken(this, binder, true, dc, callerCanManageAppTokens);
} else {
- new WindowToken(this, binder, type, true, dc, callerCanManageAppTokens);
+ new WindowToken(this, binder, type, true, dc, callerCanManageAppTokens,
+ false /* roundedCornerOverlay */, fromClientToken);
}
}
} finally {
@@ -4661,6 +4662,7 @@ public class WindowManagerService extends IWindowManager.Stub
public static final int RECOMPUTE_FOCUS = 61;
public static final int ON_POINTER_DOWN_OUTSIDE_FOCUS = 62;
public static final int LAYOUT_AND_ASSIGN_WINDOW_LAYERS_IF_NEEDED = 63;
+ public static final int WINDOW_STATE_BLAST_SYNC_TIMEOUT = 64;
/**
* Used to denote that an integer field in a message will not be used.
@@ -5041,6 +5043,13 @@ public class WindowManagerService extends IWindowManager.Stub
}
break;
}
+ case WINDOW_STATE_BLAST_SYNC_TIMEOUT: {
+ synchronized (mGlobalLock) {
+ final WindowState ws = (WindowState) msg.obj;
+ ws.finishDrawing(null);
+ }
+ break;
+ }
}
if (DEBUG_WINDOW_TRACE) {
Slog.v(TAG_WM, "handleMessage: exit");
@@ -6126,7 +6135,7 @@ public class WindowManagerService extends IWindowManager.Stub
}
mRoot.forAllWindows((w) -> {
- if ((!visibleOnly || w.mWinAnimator.getShown())
+ if ((!visibleOnly || w.isVisible())
&& (!appsOnly || w.mActivityRecord != null)) {
windows.add(w);
}
@@ -8010,9 +8019,9 @@ public class WindowManagerService extends IWindowManager.Stub
}
@Override
- public void getWindowInsets(WindowManager.LayoutParams attrs,
+ public boolean getWindowInsets(WindowManager.LayoutParams attrs,
int displayId, Rect outContentInsets, Rect outStableInsets,
- DisplayCutout.ParcelableWrapper displayCutout) {
+ DisplayCutout.ParcelableWrapper outDisplayCutout, InsetsState outInsetsState) {
final long origId = Binder.clearCallingIdentity();
try {
synchronized (mGlobalLock) {
@@ -8022,8 +8031,13 @@ public class WindowManagerService extends IWindowManager.Stub
+ "could not be found!");
}
final WindowToken windowToken = dc.getWindowToken(attrs.token);
- dc.getDisplayPolicy().getLayoutHint(attrs, windowToken, mTmpRect /* outFrame */,
- outContentInsets, outStableInsets, displayCutout);
+ final InsetsStateController insetsStateController =
+ dc.getInsetsStateController();
+ outInsetsState.set(insetsStateController.getInsetsForWindowMetrics(attrs));
+
+ return dc.getDisplayPolicy().getLayoutHint(attrs, windowToken,
+ mTmpRect /* outFrame */, outContentInsets, outStableInsets,
+ outDisplayCutout);
}
} finally {
Binder.restoreCallingIdentity(origId);
diff --git a/services/core/java/com/android/server/wm/WindowProcessController.java b/services/core/java/com/android/server/wm/WindowProcessController.java
index 03dc4c9fd1d2..833bb83acb30 100644
--- a/services/core/java/com/android/server/wm/WindowProcessController.java
+++ b/services/core/java/com/android/server/wm/WindowProcessController.java
@@ -41,6 +41,7 @@ import static com.android.server.wm.ActivityTaskManagerService.KEY_DISPATCHING_T
import static com.android.server.wm.ActivityTaskManagerService.RELAUNCH_REASON_NONE;
import android.annotation.NonNull;
+import android.annotation.Nullable;
import android.app.ActivityThread;
import android.app.IApplicationThread;
import android.app.ProfilerInfo;
@@ -185,6 +186,13 @@ public class WindowProcessController extends ConfigurationContainer<Configuratio
// Registered display id as a listener to override config change
private int mDisplayId;
private ActivityRecord mConfigActivityRecord;
+ /**
+ * Activities that hosts some UI drawn by the current process. The activities live
+ * in another process. This is used to check if the process is currently showing anything
+ * visible to the user.
+ */
+ @Nullable
+ private final ArrayList<ActivityRecord> mHostActivities = new ArrayList<>();
/** Whether our process is currently running a {@link RecentsAnimation} */
private boolean mRunningRecentsAnimation;
@@ -672,6 +680,23 @@ public class WindowProcessController extends ConfigurationContainer<Configuratio
return true;
}
}
+ if (isEmbedded()) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ /**
+ * @return {@code true} if this process is rendering content on to a window shown by
+ * another process.
+ */
+ private boolean isEmbedded() {
+ for (int i = mHostActivities.size() - 1; i >= 0; --i) {
+ final ActivityRecord r = mHostActivities.get(i);
+ if (r.isInterestingToUserLocked()) {
+ return true;
+ }
}
return false;
}
@@ -814,6 +839,19 @@ public class WindowProcessController extends ConfigurationContainer<Configuratio
}
}
+ /** Adds an activity that hosts UI drawn by the current process. */
+ void addHostActivity(ActivityRecord r) {
+ if (mHostActivities.contains(r)) {
+ return;
+ }
+ mHostActivities.add(r);
+ }
+
+ /** Removes an activity that hosts UI drawn by the current process. */
+ void removeHostActivity(ActivityRecord r) {
+ mHostActivities.remove(r);
+ }
+
public interface ComputeOomAdjCallback {
void onVisibleActivity();
void onPausedActivity();
diff --git a/services/core/java/com/android/server/wm/WindowState.java b/services/core/java/com/android/server/wm/WindowState.java
index f140ce88a363..fc28cd594a92 100644
--- a/services/core/java/com/android/server/wm/WindowState.java
+++ b/services/core/java/com/android/server/wm/WindowState.java
@@ -118,6 +118,7 @@ import static com.android.server.wm.ProtoLogGroup.WM_DEBUG_STARTING_WINDOW;
import static com.android.server.wm.SurfaceAnimator.ANIMATION_TYPE_WINDOW_ANIMATION;
import static com.android.server.wm.WindowContainer.AnimationFlags.PARENTS;
import static com.android.server.wm.WindowContainer.AnimationFlags.TRANSITION;
+import static com.android.server.wm.WindowContainerChildProto.WINDOW;
import static com.android.server.wm.WindowManagerDebugConfig.DEBUG;
import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_ANIM;
import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_CONFIGURATION;
@@ -137,6 +138,7 @@ import static com.android.server.wm.WindowManagerService.UPDATE_FOCUS_NORMAL;
import static com.android.server.wm.WindowManagerService.UPDATE_FOCUS_REMOVING_FOCUS;
import static com.android.server.wm.WindowManagerService.UPDATE_FOCUS_WILL_PLACE_SURFACES;
import static com.android.server.wm.WindowManagerService.WINDOWS_FREEZING_SCREENS_TIMEOUT;
+import static com.android.server.wm.WindowManagerService.H.WINDOW_STATE_BLAST_SYNC_TIMEOUT;
import static com.android.server.wm.WindowStateAnimator.COMMIT_DRAW_PENDING;
import static com.android.server.wm.WindowStateAnimator.DRAW_PENDING;
import static com.android.server.wm.WindowStateAnimator.HAS_DRAWN;
@@ -145,7 +147,6 @@ import static com.android.server.wm.WindowStateAnimator.READY_TO_SHOW;
import static com.android.server.wm.WindowStateProto.ANIMATING_EXIT;
import static com.android.server.wm.WindowStateProto.ANIMATOR;
import static com.android.server.wm.WindowStateProto.ATTRIBUTES;
-import static com.android.server.wm.WindowStateProto.CHILD_WINDOWS;
import static com.android.server.wm.WindowStateProto.DESTROYING;
import static com.android.server.wm.WindowStateProto.DISPLAY_ID;
import static com.android.server.wm.WindowStateProto.FINISHED_SEAMLESS_ROTATION_FRAME;
@@ -657,7 +658,7 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP
private boolean mIsDimming = false;
private @Nullable InsetsSourceProvider mControllableInsetProvider;
- private InsetsState mRequestedInsetsState;
+ private final InsetsState mRequestedInsetsState = new InsetsState();
private static final float DEFAULT_DIM_AMOUNT_DEAD_WINDOW = 0.5f;
private KeyInterceptionInfo mKeyInterceptionInfo;
@@ -669,6 +670,8 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP
*/
int mFrameRateSelectionPriority = RefreshRatePolicy.LAYER_PRIORITY_UNSET;
+ static final int BLAST_TIMEOUT_DURATION = 5000; /* milliseconds */
+
/**
* @return The insets state as requested by the client, i.e. the dispatched insets state
* for which the visibilities are overridden with what the client requested.
@@ -816,9 +819,6 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP
mSeq = seq;
mPowerManagerWrapper = powerManagerWrapper;
mForceSeamlesslyRotate = token.mRoundedCornerOverlay;
- mRequestedInsetsState = new InsetsState(
- getDisplayContent().getInsetsPolicy().getInsetsForDispatch(this),
- true /* copySources */);
if (DEBUG) {
Slog.v(TAG, "Window " + this + " client=" + c.asBinder()
+ " token=" + token + " (" + mAttrs.token + ")" + " params=" + a);
@@ -3761,9 +3761,6 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP
mSurfacePosition.dumpDebug(proto, SURFACE_POSITION);
mWinAnimator.dumpDebug(proto, ANIMATOR);
proto.write(ANIMATING_EXIT, mAnimatingExit);
- for (int i = 0; i < mChildren.size(); i++) {
- mChildren.get(i).dumpDebug(proto, CHILD_WINDOWS, logLevel);
- }
proto.write(REQUESTED_WIDTH, mRequestedWidth);
proto.write(REQUESTED_HEIGHT, mRequestedHeight);
proto.write(VIEW_VISIBILITY, mViewVisibility);
@@ -3782,6 +3779,11 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP
}
@Override
+ long getProtoFieldId() {
+ return WINDOW;
+ }
+
+ @Override
public void writeIdentifierToProto(ProtoOutputStream proto, long fieldId) {
final long token = proto.start(fieldId);
proto.write(HASH_CODE, System.identityHashCode(this));
@@ -5663,8 +5665,8 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP
return mSession.mPid == pid && isNonToastOrStarting() && isVisibleNow();
}
- SurfaceControl getDeferTransactionBarrier() {
- return mWinAnimator.getDeferTransactionBarrier();
+ SurfaceControl getClientViewRootSurface() {
+ return mWinAnimator.getClientViewRootSurface();
}
@Override
@@ -5674,6 +5676,11 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP
mWaitingListener = waitingListener;
mWaitingSyncId = waitingId;
mUsingBLASTSyncTransaction = true;
+
+ mWmService.mH.removeMessages(WINDOW_STATE_BLAST_SYNC_TIMEOUT, this);
+ mWmService.mH.sendNewMessageDelayed(WINDOW_STATE_BLAST_SYNC_TIMEOUT, this,
+ BLAST_TIMEOUT_DURATION);
+
return true;
}
@@ -5681,6 +5688,8 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP
if (!mUsingBLASTSyncTransaction) {
return mWinAnimator.finishDrawingLocked(postDrawTransaction);
}
+
+ mWmService.mH.removeMessages(WINDOW_STATE_BLAST_SYNC_TIMEOUT, this);
if (postDrawTransaction == null) {
postDrawTransaction = new SurfaceControl.Transaction();
}
diff --git a/services/core/java/com/android/server/wm/WindowStateAnimator.java b/services/core/java/com/android/server/wm/WindowStateAnimator.java
index 81d0e3e88c1a..79dc5366445e 100644
--- a/services/core/java/com/android/server/wm/WindowStateAnimator.java
+++ b/services/core/java/com/android/server/wm/WindowStateAnimator.java
@@ -383,8 +383,9 @@ class WindowStateAnimator {
// Make sure to reparent any children of the new surface back to the preserved
// surface before destroying it.
if (mSurfaceController != null && mPendingDestroySurface != null) {
- mPostDrawTransaction.reparentChildren(mSurfaceController.mSurfaceControl,
- mPendingDestroySurface.mSurfaceControl).apply();
+ mPostDrawTransaction.reparentChildren(
+ mSurfaceController.getClientViewRootSurface(),
+ mPendingDestroySurface.mSurfaceControl).apply();
}
destroySurfaceLocked();
mSurfaceDestroyDeferred = true;
@@ -413,9 +414,9 @@ class WindowStateAnimator {
// child layers need to be reparented to the new surface to make this
// transparent to the app.
if (mWin.mActivityRecord == null || mWin.mActivityRecord.isRelaunching() == false) {
- mPostDrawTransaction.reparentChildren(mPendingDestroySurface.mSurfaceControl,
- mSurfaceController.mSurfaceControl)
- .apply();
+ mPostDrawTransaction.reparentChildren(
+ mPendingDestroySurface.getClientViewRootSurface(),
+ mSurfaceController.mSurfaceControl).apply();
}
}
}
@@ -875,7 +876,7 @@ class WindowStateAnimator {
if (mSurfaceResized && (mAttrType == TYPE_BASE_APPLICATION) &&
(task != null) && (task.getMainWindowSizeChangeTransaction() != null)) {
- mSurfaceController.deferTransactionUntil(mWin.getDeferTransactionBarrier(),
+ mSurfaceController.deferTransactionUntil(mWin.getClientViewRootSurface(),
mWin.getFrameNumber());
SurfaceControl.mergeToGlobalTransaction(task.getMainWindowSizeChangeTransaction());
task.setMainWindowSizeChangeTransaction(null);
@@ -1012,7 +1013,7 @@ class WindowStateAnimator {
// the WS position is reset (so the stack position is shown) at the same
// time that the buffer size changes.
setOffsetPositionForStackResize(false);
- mSurfaceController.deferTransactionUntil(mWin.getDeferTransactionBarrier(),
+ mSurfaceController.deferTransactionUntil(mWin.getClientViewRootSurface(),
mWin.getFrameNumber());
} else {
final ActivityStack stack = mWin.getRootTask();
@@ -1043,7 +1044,7 @@ class WindowStateAnimator {
// comes in at the new size (normally position and crop are unfrozen).
// deferTransactionUntil accomplishes this for us.
if (wasForceScaled && !mForceScaleUntilResize) {
- mSurfaceController.deferTransactionUntil(mWin.getDeferTransactionBarrier(),
+ mSurfaceController.deferTransactionUntil(mWin.getClientViewRootSurface(),
mWin.getFrameNumber());
mSurfaceController.forceScaleableInTransaction(false);
}
@@ -1288,8 +1289,9 @@ class WindowStateAnimator {
if (mPendingDestroySurface != null && mDestroyPreservedSurfaceUponRedraw) {
final SurfaceControl pendingSurfaceControl = mPendingDestroySurface.mSurfaceControl;
mPostDrawTransaction.reparent(pendingSurfaceControl, null);
- mPostDrawTransaction.reparentChildren(pendingSurfaceControl,
- mSurfaceController.mSurfaceControl);
+ mPostDrawTransaction.reparentChildren(
+ mPendingDestroySurface.getClientViewRootSurface(),
+ mSurfaceController.mSurfaceControl);
}
SurfaceControl.mergeToGlobalTransaction(mPostDrawTransaction);
@@ -1521,10 +1523,10 @@ class WindowStateAnimator {
mOffsetPositionForStackResize = offsetPositionForStackResize;
}
- SurfaceControl getDeferTransactionBarrier() {
+ SurfaceControl getClientViewRootSurface() {
if (!hasSurface()) {
return null;
}
- return mSurfaceController.getDeferTransactionBarrier();
+ return mSurfaceController.getClientViewRootSurface();
}
}
diff --git a/services/core/java/com/android/server/wm/WindowSurfaceController.java b/services/core/java/com/android/server/wm/WindowSurfaceController.java
index 383c0d9ab3d4..d7c97b922d2d 100644
--- a/services/core/java/com/android/server/wm/WindowSurfaceController.java
+++ b/services/core/java/com/android/server/wm/WindowSurfaceController.java
@@ -533,7 +533,15 @@ class WindowSurfaceController {
return mSurfaceH;
}
- SurfaceControl getDeferTransactionBarrier() {
+ /**
+ * Returns the Surface which the client-framework ViewRootImpl will be using.
+ * This is either the WSA SurfaceControl or it's BLAST child surface.
+ * This has too main uses:
+ * 1. This is the Surface the client will add children to, we use this to make
+ * sure we don't reparent the BLAST surface itself when calling reparentChildren
+ * 2. We use this as the barrier Surface for some deferTransaction operations.
+ */
+ SurfaceControl getClientViewRootSurface() {
if (mBLASTSurfaceControl != null) {
return mBLASTSurfaceControl;
}
diff --git a/services/core/java/com/android/server/wm/WindowToken.java b/services/core/java/com/android/server/wm/WindowToken.java
index 98d9c8fcab5a..b7c6af2f7a0d 100644
--- a/services/core/java/com/android/server/wm/WindowToken.java
+++ b/services/core/java/com/android/server/wm/WindowToken.java
@@ -28,13 +28,13 @@ import static com.android.server.wm.ProtoLogGroup.WM_ERROR;
import static com.android.server.wm.WindowContainer.AnimationFlags.CHILDREN;
import static com.android.server.wm.WindowContainer.AnimationFlags.PARENTS;
import static com.android.server.wm.WindowContainer.AnimationFlags.TRANSITION;
+import static com.android.server.wm.WindowContainerChildProto.WINDOW_TOKEN;
import static com.android.server.wm.WindowManagerDebugConfig.TAG_WITH_CLASS_NAME;
import static com.android.server.wm.WindowManagerDebugConfig.TAG_WM;
import static com.android.server.wm.WindowManagerService.UPDATE_FOCUS_NORMAL;
import static com.android.server.wm.WindowTokenProto.HASH_CODE;
import static com.android.server.wm.WindowTokenProto.PAUSED;
import static com.android.server.wm.WindowTokenProto.WAITING_TO_SHOW;
-import static com.android.server.wm.WindowTokenProto.WINDOWS;
import static com.android.server.wm.WindowTokenProto.WINDOW_CONTAINER;
import android.annotation.CallSuper;
@@ -50,6 +50,7 @@ import android.view.InsetsState;
import android.view.SurfaceControl;
import android.view.WindowManager;
+import com.android.internal.annotations.VisibleForTesting;
import com.android.server.policy.WindowManagerPolicy;
import com.android.server.protolog.common.ProtoLog;
@@ -99,7 +100,8 @@ class WindowToken extends WindowContainer<WindowState> {
private Configuration mLastReportedConfig;
private int mLastReportedDisplay = INVALID_DISPLAY;
- private final boolean mFromClientToken;
+ @VisibleForTesting
+ final boolean mFromClientToken;
/**
* Used to fix the transform of the token to be rotated to a rotation different than it's
@@ -180,13 +182,13 @@ class WindowToken extends WindowContainer<WindowState> {
WindowToken(WindowManagerService service, IBinder _token, int type, boolean persistOnEmpty,
DisplayContent dc, boolean ownerCanManageAppTokens) {
this(service, _token, type, persistOnEmpty, dc, ownerCanManageAppTokens,
- false /* roundedCornersOverlay */);
+ false /* roundedCornerOverlay */);
}
WindowToken(WindowManagerService service, IBinder _token, int type, boolean persistOnEmpty,
- DisplayContent dc, boolean ownerCanManageAppTokens, boolean fromClientToken) {
+ DisplayContent dc, boolean ownerCanManageAppTokens, boolean roundedCornerOverlay) {
this(service, _token, type, persistOnEmpty, dc, ownerCanManageAppTokens,
- false /* roundedCornersOverlay */, fromClientToken);
+ roundedCornerOverlay, false /* fromClientToken */);
}
WindowToken(WindowManagerService service, IBinder _token, int type, boolean persistOnEmpty,
@@ -539,15 +541,16 @@ class WindowToken extends WindowContainer<WindowState> {
final long token = proto.start(fieldId);
super.dumpDebug(proto, WINDOW_CONTAINER, logLevel);
proto.write(HASH_CODE, System.identityHashCode(this));
- for (int i = 0; i < mChildren.size(); i++) {
- final WindowState w = mChildren.get(i);
- w.dumpDebug(proto, WINDOWS, logLevel);
- }
proto.write(WAITING_TO_SHOW, waitingToShow);
proto.write(PAUSED, paused);
proto.end(token);
}
+ @Override
+ long getProtoFieldId() {
+ return WINDOW_TOKEN;
+ }
+
void dump(PrintWriter pw, String prefix, boolean dumpAll) {
super.dump(pw, prefix, dumpAll);
pw.print(prefix); pw.print("windows="); pw.println(mChildren);
diff --git a/services/core/jni/Android.bp b/services/core/jni/Android.bp
index 27bd58ec3010..74982c6918a2 100644
--- a/services/core/jni/Android.bp
+++ b/services/core/jni/Android.bp
@@ -56,7 +56,6 @@ cc_library_static {
"com_android_server_PersistentDataBlockService.cpp",
"com_android_server_am_CachedAppOptimizer.cpp",
"com_android_server_am_LowMemDetector.cpp",
- "com_android_server_incremental_IncrementalManagerService.cpp",
"com_android_server_pm_PackageManagerShellCommandDataLoader.cpp",
"onload.cpp",
":lib_networkStatsFactory_native",
@@ -147,6 +146,7 @@ cc_defaults {
"android.hardware.light@2.0",
"android.hardware.power@1.0",
"android.hardware.power@1.1",
+ "android.hardware.power-cpp",
"android.hardware.power.stats@1.0",
"android.hardware.thermal@1.0",
"android.hardware.tv.cec@1.0",
diff --git a/services/core/jni/com_android_server_SystemServer.cpp b/services/core/jni/com_android_server_SystemServer.cpp
index 279ea4b9a790..e99a264c42e4 100644
--- a/services/core/jni/com_android_server_SystemServer.cpp
+++ b/services/core/jni/com_android_server_SystemServer.cpp
@@ -25,6 +25,7 @@
#include <binder/IServiceManager.h>
#include <hidl/HidlTransportSupport.h>
+#include <incremental_service.h>
#include <schedulerservice/SchedulingPolicyService.h>
#include <sensorservice/SensorService.h>
@@ -132,18 +133,31 @@ static void android_server_SystemServer_spawnFdLeakCheckThread(JNIEnv*, jobject)
}).detach();
}
+static jlong android_server_SystemServer_startIncrementalService(JNIEnv* env, jclass klass,
+ jobject self) {
+ return Incremental_IncrementalService_Start();
+}
+
+static void android_server_SystemServer_setIncrementalServiceSystemReady(JNIEnv* env, jclass klass,
+ jlong handle) {
+ Incremental_IncrementalService_OnSystemReady(handle);
+}
+
/*
* JNI registration.
*/
static const JNINativeMethod gMethods[] = {
- /* name, signature, funcPtr */
- { "startSensorService", "()V", (void*) android_server_SystemServer_startSensorService },
- { "startHidlServices", "()V", (void*) android_server_SystemServer_startHidlServices },
- { "initZygoteChildHeapProfiling", "()V",
- (void*) android_server_SystemServer_initZygoteChildHeapProfiling },
- { "spawnFdLeakCheckThread", "()V",
- (void*) android_server_SystemServer_spawnFdLeakCheckThread },
-
+ /* name, signature, funcPtr */
+ {"startSensorService", "()V", (void*)android_server_SystemServer_startSensorService},
+ {"startHidlServices", "()V", (void*)android_server_SystemServer_startHidlServices},
+ {"initZygoteChildHeapProfiling", "()V",
+ (void*)android_server_SystemServer_initZygoteChildHeapProfiling},
+ {"spawnFdLeakCheckThread", "()V",
+ (void*)android_server_SystemServer_spawnFdLeakCheckThread},
+ {"startIncrementalService", "()J",
+ (void*)android_server_SystemServer_startIncrementalService},
+ {"setIncrementalServiceSystemReady", "(J)V",
+ (void*)android_server_SystemServer_setIncrementalServiceSystemReady},
};
int register_android_server_SystemServer(JNIEnv* env)
diff --git a/services/core/jni/com_android_server_am_BatteryStatsService.cpp b/services/core/jni/com_android_server_am_BatteryStatsService.cpp
index 9cbb58d35b9f..b08868e2c7f8 100644
--- a/services/core/jni/com_android_server_am_BatteryStatsService.cpp
+++ b/services/core/jni/com_android_server_am_BatteryStatsService.cpp
@@ -67,9 +67,9 @@ namespace android
static bool wakeup_init = false;
static sem_t wakeup_sem;
-extern sp<IPowerV1_0> getPowerHalV1_0();
-extern sp<IPowerV1_1> getPowerHalV1_1();
-extern bool processPowerHalReturn(const Return<void> &ret, const char* functionName);
+extern sp<IPowerV1_0> getPowerHalHidlV1_0();
+extern sp<IPowerV1_1> getPowerHalHidlV1_1();
+extern bool processPowerHalReturn(bool isOk, const char* functionName);
extern sp<ISuspendControlService> getSuspendControl();
// Java methods used in getLowPowerStats
@@ -596,7 +596,7 @@ static void getPowerStatsHalRailEnergyData(JNIEnv* env, jobject jrailStats) {
// The caller must be holding powerHalMutex.
static void getPowerHalLowPowerData(JNIEnv* env, jobject jrpmStats) {
- sp<IPowerV1_0> powerHalV1_0 = getPowerHalV1_0();
+ sp<IPowerV1_0> powerHalV1_0 = getPowerHalHidlV1_0();
if (powerHalV1_0 == nullptr) {
ALOGE("Power Hal not loaded");
return;
@@ -629,12 +629,12 @@ static void getPowerHalLowPowerData(JNIEnv* env, jobject jrpmStats) {
}
}
});
- if (!processPowerHalReturn(ret, "getPlatformLowPowerStats")) {
+ if (!processPowerHalReturn(ret.isOk(), "getPlatformLowPowerStats")) {
return;
}
// Trying to get IPower 1.1, this will succeed only for devices supporting 1.1
- sp<IPowerV1_1> powerHal_1_1 = getPowerHalV1_1();
+ sp<IPowerV1_1> powerHal_1_1 = getPowerHalHidlV1_1();
if (powerHal_1_1 == nullptr) {
// This device does not support IPower@1.1, exiting gracefully
return;
@@ -665,7 +665,7 @@ static void getPowerHalLowPowerData(JNIEnv* env, jobject jrpmStats) {
}
}
});
- processPowerHalReturn(ret, "getSubsystemLowPowerStats");
+ processPowerHalReturn(ret.isOk(), "getSubsystemLowPowerStats");
}
static jint getPowerHalPlatformData(JNIEnv* env, jobject outBuf) {
@@ -675,7 +675,7 @@ static jint getPowerHalPlatformData(JNIEnv* env, jobject outBuf) {
int total_added = -1;
{
- sp<IPowerV1_0> powerHalV1_0 = getPowerHalV1_0();
+ sp<IPowerV1_0> powerHalV1_0 = getPowerHalHidlV1_0();
if (powerHalV1_0 == nullptr) {
ALOGE("Power Hal not loaded");
return -1;
@@ -733,7 +733,7 @@ static jint getPowerHalPlatformData(JNIEnv* env, jobject outBuf) {
}
);
- if (!processPowerHalReturn(ret, "getPlatformLowPowerStats")) {
+ if (!processPowerHalReturn(ret.isOk(), "getPlatformLowPowerStats")) {
return -1;
}
}
@@ -753,7 +753,7 @@ static jint getPowerHalSubsystemData(JNIEnv* env, jobject outBuf) {
{
// Trying to get 1.1, this will succeed only for devices supporting 1.1
- powerHal_1_1 = getPowerHalV1_1();
+ powerHal_1_1 = getPowerHalHidlV1_1();
if (powerHal_1_1 == nullptr) {
//This device does not support IPower@1.1, exiting gracefully
return 0;
@@ -820,7 +820,7 @@ static jint getPowerHalSubsystemData(JNIEnv* env, jobject outBuf) {
}
);
- if (!processPowerHalReturn(ret, "getSubsystemLowPowerStats")) {
+ if (!processPowerHalReturn(ret.isOk(), "getSubsystemLowPowerStats")) {
return -1;
}
}
diff --git a/services/core/jni/com_android_server_incremental_IncrementalManagerService.cpp b/services/core/jni/com_android_server_incremental_IncrementalManagerService.cpp
deleted file mode 100644
index 10bac94f77e2..000000000000
--- a/services/core/jni/com_android_server_incremental_IncrementalManagerService.cpp
+++ /dev/null
@@ -1,52 +0,0 @@
-/*
- * Copyright (C) 2019 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#define LOG_TAG "incremental_manager_service-jni"
-
-#include "incremental_service.h"
-#include "jni.h"
-
-#include <memory>
-#include <nativehelper/JNIHelp.h>
-
-
-namespace android {
-
-static jlong nativeStartService(JNIEnv* env, jclass klass, jobject self) {
- return Incremental_IncrementalService_Start();
-}
-
-static void nativeSystemReady(JNIEnv* env, jclass klass, jlong self) {
- Incremental_IncrementalService_OnSystemReady(self);
-}
-
-static void nativeDump(JNIEnv* env, jclass klass, jlong self, jint fd) {
- Incremental_IncrementalService_OnDump(self, fd);
-}
-
-static const JNINativeMethod method_table[] = {
- {"nativeStartService", "()J", (void*)nativeStartService},
- {"nativeSystemReady", "(J)V", (void*)nativeSystemReady},
- {"nativeDump", "(JI)V", (void*)nativeDump},
-};
-
-int register_android_server_incremental_IncrementalManagerService(JNIEnv* env) {
- return jniRegisterNativeMethods(env,
- "com/android/server/incremental/IncrementalManagerService",
- method_table, std::size(method_table));
-}
-
-} // namespace android
diff --git a/services/core/jni/com_android_server_power_PowerManagerService.cpp b/services/core/jni/com_android_server_power_PowerManagerService.cpp
index 4e0434873944..239a1011422c 100644
--- a/services/core/jni/com_android_server_power_PowerManagerService.cpp
+++ b/services/core/jni/com_android_server_power_PowerManagerService.cpp
@@ -19,6 +19,9 @@
//#define LOG_NDEBUG 0
#include <android/hardware/power/1.1/IPower.h>
+#include <android/hardware/power/Boost.h>
+#include <android/hardware/power/IPower.h>
+#include <android/hardware/power/Mode.h>
#include <android/system/suspend/1.0/ISystemSuspend.h>
#include <android/system/suspend/ISuspendControlService.h>
#include <nativehelper/JNIHelp.h>
@@ -45,6 +48,8 @@
using android::hardware::Return;
using android::hardware::Void;
+using android::hardware::power::Boost;
+using android::hardware::power::Mode;
using android::hardware::power::V1_0::PowerHint;
using android::hardware::power::V1_0::Feature;
using android::String8;
@@ -54,6 +59,7 @@ using android::system::suspend::V1_0::WakeLockType;
using android::system::suspend::ISuspendControlService;
using IPowerV1_1 = android::hardware::power::V1_1::IPower;
using IPowerV1_0 = android::hardware::power::V1_0::IPower;
+using IPowerAidl = android::hardware::power::IPower;
namespace android {
@@ -66,11 +72,18 @@ static struct {
// ----------------------------------------------------------------------------
static jobject gPowerManagerServiceObj;
-// Use getPowerHal* to retrieve a copy
-static sp<IPowerV1_0> gPowerHalV1_0_ = nullptr;
-static sp<IPowerV1_1> gPowerHalV1_1_ = nullptr;
-static bool gPowerHalExists = true;
+static sp<IPowerV1_0> gPowerHalHidlV1_0_ = nullptr;
+static sp<IPowerV1_1> gPowerHalHidlV1_1_ = nullptr;
+static sp<IPowerAidl> gPowerHalAidl_ = nullptr;
static std::mutex gPowerHalMutex;
+
+enum class HalVersion {
+ NONE,
+ HIDL_1_0,
+ HIDL_1_1,
+ AIDL,
+};
+
static nsecs_t gLastEventTime[USER_ACTIVITY_EVENT_LAST + 1];
// Throttling interval for user activity calls.
@@ -88,70 +101,209 @@ static bool checkAndClearExceptionFromCallback(JNIEnv* env, const char* methodNa
return false;
}
-// Check validity of current handle to the power HAL service, and call getService() if necessary.
+// Check validity of current handle to the power HAL service, and connect to it if necessary.
// The caller must be holding gPowerHalMutex.
-static void connectPowerHalLocked() {
- if (gPowerHalExists && gPowerHalV1_0_ == nullptr) {
- gPowerHalV1_0_ = IPowerV1_0::getService();
- if (gPowerHalV1_0_ != nullptr) {
- ALOGI("Loaded power HAL 1.0 service");
- // Try cast to powerHAL V1_1
- gPowerHalV1_1_ = IPowerV1_1::castFrom(gPowerHalV1_0_);
- if (gPowerHalV1_1_ == nullptr) {
- } else {
- ALOGI("Loaded power HAL 1.1 service");
+static HalVersion connectPowerHalLocked() {
+ static bool gPowerHalHidlExists = true;
+ static bool gPowerHalAidlExists = true;
+ if (!gPowerHalHidlExists && !gPowerHalAidlExists) {
+ return HalVersion::NONE;
+ }
+ if (gPowerHalAidlExists) {
+ if (!gPowerHalAidl_) {
+ gPowerHalAidl_ = waitForVintfService<IPowerAidl>();
+ }
+ if (gPowerHalAidl_) {
+ ALOGI("Successfully connected to Power HAL AIDL service.");
+ return HalVersion::AIDL;
+ } else {
+ gPowerHalAidlExists = false;
+ }
+ }
+ if (gPowerHalHidlExists && gPowerHalHidlV1_0_ == nullptr) {
+ gPowerHalHidlV1_0_ = IPowerV1_0::getService();
+ if (gPowerHalHidlV1_0_) {
+ ALOGI("Successfully connected to Power HAL HIDL 1.0 service.");
+ // Try cast to powerHAL HIDL V1_1
+ gPowerHalHidlV1_1_ = IPowerV1_1::castFrom(gPowerHalHidlV1_0_);
+ if (gPowerHalHidlV1_1_) {
+ ALOGI("Successfully connected to Power HAL HIDL 1.1 service.");
}
} else {
- ALOGI("Couldn't load power HAL service");
- gPowerHalExists = false;
+ ALOGI("Couldn't load power HAL HIDL service");
+ gPowerHalHidlExists = false;
+ return HalVersion::NONE;
}
}
+ if (gPowerHalHidlV1_1_) {
+ return HalVersion::HIDL_1_1;
+ } else if (gPowerHalHidlV1_0_) {
+ return HalVersion::HIDL_1_0;
+ }
+ return HalVersion::NONE;
}
-// Retrieve a copy of PowerHAL V1_0
-sp<IPowerV1_0> getPowerHalV1_0() {
+// Retrieve a copy of PowerHAL HIDL V1_0
+sp<IPowerV1_0> getPowerHalHidlV1_0() {
std::lock_guard<std::mutex> lock(gPowerHalMutex);
- connectPowerHalLocked();
- return gPowerHalV1_0_;
+ HalVersion halVersion = connectPowerHalLocked();
+ if (halVersion == HalVersion::HIDL_1_0 || halVersion == HalVersion::HIDL_1_1) {
+ return gPowerHalHidlV1_0_;
+ }
+
+ return nullptr;
}
-// Retrieve a copy of PowerHAL V1_1
-sp<IPowerV1_1> getPowerHalV1_1() {
+// Retrieve a copy of PowerHAL HIDL V1_1
+sp<IPowerV1_1> getPowerHalHidlV1_1() {
std::lock_guard<std::mutex> lock(gPowerHalMutex);
- connectPowerHalLocked();
- return gPowerHalV1_1_;
+ if (connectPowerHalLocked() == HalVersion::HIDL_1_1) {
+ return gPowerHalHidlV1_1_;
+ }
+
+ return nullptr;
}
// Check if a call to a power HAL function failed; if so, log the failure and invalidate the
// current handle to the power HAL service.
-bool processPowerHalReturn(const Return<void> &ret, const char* functionName) {
- if (!ret.isOk()) {
+bool processPowerHalReturn(bool isOk, const char* functionName) {
+ if (!isOk) {
ALOGE("%s() failed: power HAL service not available.", functionName);
gPowerHalMutex.lock();
- gPowerHalV1_0_ = nullptr;
- gPowerHalV1_1_ = nullptr;
+ gPowerHalHidlV1_0_ = nullptr;
+ gPowerHalHidlV1_1_ = nullptr;
+ gPowerHalAidl_ = nullptr;
gPowerHalMutex.unlock();
}
- return ret.isOk();
+ return isOk;
}
static void sendPowerHint(PowerHint hintId, uint32_t data) {
- sp<IPowerV1_1> powerHalV1_1 = getPowerHalV1_1();
- Return<void> ret;
- if (powerHalV1_1 != nullptr) {
- ret = powerHalV1_1->powerHintAsync(hintId, data);
- processPowerHalReturn(ret, "powerHintAsync");
- } else {
- sp<IPowerV1_0> powerHalV1_0 = getPowerHalV1_0();
- if (powerHalV1_0 != nullptr) {
- ret = powerHalV1_0->powerHint(hintId, data);
- processPowerHalReturn(ret, "powerHint");
+ std::unique_lock<std::mutex> lock(gPowerHalMutex);
+ switch (connectPowerHalLocked()) {
+ case HalVersion::NONE:
+ return;
+ case HalVersion::HIDL_1_0: {
+ sp<IPowerV1_0> handle = gPowerHalHidlV1_0_;
+ lock.unlock();
+ auto ret = handle->powerHint(hintId, data);
+ processPowerHalReturn(ret.isOk(), "powerHint");
+ break;
+ }
+ case HalVersion::HIDL_1_1: {
+ sp<IPowerV1_1> handle = gPowerHalHidlV1_1_;
+ lock.unlock();
+ auto ret = handle->powerHintAsync(hintId, data);
+ processPowerHalReturn(ret.isOk(), "powerHintAsync");
+ break;
+ }
+ case HalVersion::AIDL: {
+ if (hintId == PowerHint::INTERACTION) {
+ sp<IPowerAidl> handle = gPowerHalAidl_;
+ lock.unlock();
+ auto ret = handle->setBoost(Boost::INTERACTION, data);
+ processPowerHalReturn(ret.isOk(), "setBoost");
+ break;
+ } else if (hintId == PowerHint::LAUNCH) {
+ sp<IPowerAidl> handle = gPowerHalAidl_;
+ lock.unlock();
+ auto ret = handle->setMode(Mode::LAUNCH, static_cast<bool>(data));
+ processPowerHalReturn(ret.isOk(), "setMode");
+ break;
+ } else {
+ ALOGE("Unsupported power hint: %s.", toString(hintId).c_str());
+ return;
+ }
+ }
+ default: {
+ ALOGE("Unknown power HAL state");
+ return;
}
}
-
SurfaceComposerClient::notifyPowerHint(static_cast<int32_t>(hintId));
}
+enum class HalSupport {
+ UNKNOWN = 0,
+ ON,
+ OFF,
+};
+
+static void setPowerBoost(Boost boost, int32_t durationMs) {
+ // Android framework only sends boost upto DISPLAY_UPDATE_IMMINENT.
+ // Need to increase the array size if more boost supported.
+ static std::array<std::atomic<HalSupport>,
+ static_cast<int32_t>(Boost::DISPLAY_UPDATE_IMMINENT) + 1>
+ boostSupportedArray = {HalSupport::UNKNOWN};
+
+ // Quick return if boost is not supported by HAL
+ if (boost > Boost::DISPLAY_UPDATE_IMMINENT ||
+ boostSupportedArray[static_cast<int32_t>(boost)] == HalSupport::OFF) {
+ ALOGV("Skipped setPowerBoost %s because HAL doesn't support it", toString(boost).c_str());
+ return;
+ }
+
+ std::unique_lock<std::mutex> lock(gPowerHalMutex);
+ if (connectPowerHalLocked() != HalVersion::AIDL) {
+ ALOGV("Power HAL AIDL not available");
+ return;
+ }
+ sp<IPowerAidl> handle = gPowerHalAidl_;
+ lock.unlock();
+
+ if (boostSupportedArray[static_cast<int32_t>(boost)] == HalSupport::UNKNOWN) {
+ bool isSupported = false;
+ handle->isBoostSupported(boost, &isSupported);
+ boostSupportedArray[static_cast<int32_t>(boost)] =
+ isSupported ? HalSupport::ON : HalSupport::OFF;
+ if (!isSupported) {
+ ALOGV("Skipped setPowerBoost %s because HAL doesn't support it",
+ toString(boost).c_str());
+ return;
+ }
+ }
+
+ auto ret = handle->setBoost(boost, durationMs);
+ processPowerHalReturn(ret.isOk(), "setPowerBoost");
+}
+
+static void setPowerMode(Mode mode, bool enabled) {
+ // Android framework only sends mode upto DISPLAY_INACTIVE.
+ // Need to increase the array if more mode supported.
+ static std::array<std::atomic<HalSupport>,
+ static_cast<int32_t>(Mode::DISPLAY_INACTIVE) + 1>
+ modeSupportedArray = {HalSupport::UNKNOWN};
+
+ // Quick return if mode is not supported by HAL
+ if (mode > Mode::DISPLAY_INACTIVE ||
+ modeSupportedArray[static_cast<int32_t>(mode)] == HalSupport::OFF) {
+ ALOGV("Skipped setPowerMode %s because HAL doesn't support it", toString(mode).c_str());
+ return;
+ }
+
+ std::unique_lock<std::mutex> lock(gPowerHalMutex);
+ if (connectPowerHalLocked() != HalVersion::AIDL) {
+ ALOGV("Power HAL AIDL not available");
+ return;
+ }
+ sp<IPowerAidl> handle = gPowerHalAidl_;
+ lock.unlock();
+
+ if (modeSupportedArray[static_cast<int32_t>(mode)] == HalSupport::UNKNOWN) {
+ bool isSupported = false;
+ handle->isModeSupported(mode, &isSupported);
+ modeSupportedArray[static_cast<int32_t>(mode)] =
+ isSupported ? HalSupport::ON : HalSupport::OFF;
+ if (!isSupported) {
+ ALOGV("Skipped setPowerMode %s because HAL doesn't support it", toString(mode).c_str());
+ return;
+ }
+ }
+
+ auto ret = handle->setMode(mode, enabled);
+ processPowerHalReturn(ret.isOk(), "setPowerMode");
+}
+
void android_server_PowerManagerService_userActivity(nsecs_t eventTime, int32_t eventType) {
if (gPowerManagerServiceObj) {
// Throttle calls into user activity by event type.
@@ -253,14 +405,34 @@ static void nativeReleaseSuspendBlocker(JNIEnv *env, jclass /* clazz */, jstring
}
static void nativeSetInteractive(JNIEnv* /* env */, jclass /* clazz */, jboolean enable) {
- sp<IPowerV1_0> powerHalV1_0 = getPowerHalV1_0();
- if (powerHalV1_0 != nullptr) {
- android::base::Timer t;
- Return<void> ret = powerHalV1_0->setInteractive(enable);
- processPowerHalReturn(ret, "setInteractive");
- if (t.duration() > 20ms) {
- ALOGD("Excessive delay in setInteractive(%s) while turning screen %s",
- enable ? "true" : "false", enable ? "on" : "off");
+ std::unique_lock<std::mutex> lock(gPowerHalMutex);
+ switch (connectPowerHalLocked()) {
+ case HalVersion::NONE:
+ return;
+ case HalVersion::HIDL_1_0:
+ FALLTHROUGH_INTENDED;
+ case HalVersion::HIDL_1_1: {
+ android::base::Timer t;
+ sp<IPowerV1_0> handle = gPowerHalHidlV1_0_;
+ lock.unlock();
+ auto ret = handle->setInteractive(enable);
+ processPowerHalReturn(ret.isOk(), "setInteractive");
+ if (t.duration() > 20ms) {
+ ALOGD("Excessive delay in setInteractive(%s) while turning screen %s",
+ enable ? "true" : "false", enable ? "on" : "off");
+ }
+ return;
+ }
+ case HalVersion::AIDL: {
+ sp<IPowerAidl> handle = gPowerHalAidl_;
+ lock.unlock();
+ auto ret = handle->setMode(Mode::INTERACTIVE, enable);
+ processPowerHalReturn(ret.isOk(), "setMode");
+ return;
+ }
+ default: {
+ ALOGE("Unknown power HAL state");
+ return;
}
}
}
@@ -285,11 +457,38 @@ static void nativeSendPowerHint(JNIEnv* /* env */, jclass /* clazz */, jint hint
sendPowerHint(static_cast<PowerHint>(hintId), data);
}
+static void nativeSetPowerBoost(JNIEnv* /* env */, jclass /* clazz */, jint boost,
+ jint durationMs) {
+ setPowerBoost(static_cast<Boost>(boost), durationMs);
+}
+
+static void nativeSetPowerMode(JNIEnv* /* env */, jclass /* clazz */, jint mode, jboolean enabled) {
+ setPowerMode(static_cast<Mode>(mode), enabled);
+}
+
static void nativeSetFeature(JNIEnv* /* env */, jclass /* clazz */, jint featureId, jint data) {
- sp<IPowerV1_0> powerHalV1_0 = getPowerHalV1_0();
- if (powerHalV1_0 != nullptr) {
- Return<void> ret = powerHalV1_0->setFeature((Feature)featureId, static_cast<bool>(data));
- processPowerHalReturn(ret, "setFeature");
+ std::unique_lock<std::mutex> lock(gPowerHalMutex);
+ switch (connectPowerHalLocked()) {
+ case HalVersion::NONE:
+ return;
+ case HalVersion::HIDL_1_0:
+ FALLTHROUGH_INTENDED;
+ case HalVersion::HIDL_1_1: {
+ sp<IPowerV1_0> handle = gPowerHalHidlV1_0_;
+ lock.unlock();
+ auto ret = handle->setFeature(static_cast<Feature>(featureId), static_cast<bool>(data));
+ processPowerHalReturn(ret.isOk(), "setFeature");
+ return;
+ }
+ case HalVersion::AIDL: {
+ auto ret = gPowerHalAidl_->setMode(Mode::DOUBLE_TAP_TO_WAKE, static_cast<bool>(data));
+ processPowerHalReturn(ret.isOk(), "setMode");
+ return;
+ }
+ default: {
+ ALOGE("Unknown power HAL state");
+ return;
+ }
}
}
@@ -317,6 +516,10 @@ static const JNINativeMethod gPowerManagerServiceMethods[] = {
(void*) nativeSetAutoSuspend },
{ "nativeSendPowerHint", "(II)V",
(void*) nativeSendPowerHint },
+ { "nativeSetPowerBoost", "(II)V",
+ (void*) nativeSetPowerBoost },
+ { "nativeSetPowerMode", "(IZ)V",
+ (void*) nativeSetPowerMode },
{ "nativeSetFeature", "(II)V",
(void*) nativeSetFeature },
};
diff --git a/services/core/jni/onload.cpp b/services/core/jni/onload.cpp
index a5339a5d2e62..eb486fea0116 100644
--- a/services/core/jni/onload.cpp
+++ b/services/core/jni/onload.cpp
@@ -58,7 +58,6 @@ int register_android_server_am_CachedAppOptimizer(JNIEnv* env);
int register_android_server_am_LowMemDetector(JNIEnv* env);
int register_com_android_server_soundtrigger_middleware_AudioSessionProviderImpl(
JNIEnv* env);
-int register_android_server_incremental_IncrementalManagerService(JNIEnv* env);
int register_android_server_com_android_server_pm_PackageManagerShellCommandDataLoader(JNIEnv* env);
int register_android_server_stats_pull_StatsPullAtomService(JNIEnv* env);
int register_android_server_AdbDebuggingManager(JNIEnv* env);
@@ -113,7 +112,6 @@ extern "C" jint JNI_OnLoad(JavaVM* vm, void* /* reserved */)
register_android_server_am_LowMemDetector(env);
register_com_android_server_soundtrigger_middleware_AudioSessionProviderImpl(
env);
- register_android_server_incremental_IncrementalManagerService(env);
register_android_server_com_android_server_pm_PackageManagerShellCommandDataLoader(env);
register_android_server_stats_pull_StatsPullAtomService(env);
register_android_server_AdbDebuggingManager(env);
diff --git a/services/core/xsd/platform-compat-config.xsd b/services/core/xsd/platform-compat-config.xsd
index a70568f5911a..5a4c682f52eb 100644
--- a/services/core/xsd/platform-compat-config.xsd
+++ b/services/core/xsd/platform-compat-config.xsd
@@ -27,6 +27,7 @@
<xs:attribute type="xs:long" name="id" use="required"/>
<xs:attribute type="xs:string" name="name" use="required"/>
<xs:attribute type="xs:boolean" name="disabled"/>
+ <xs:attribute type="xs:boolean" name="loggingOnly"/>
<xs:attribute type="xs:int" name="enableAfterTargetSdk"/>
<xs:attribute type="xs:string" name="description"/>
</xs:extension>
diff --git a/services/core/xsd/platform-compat-schema/current.txt b/services/core/xsd/platform-compat-schema/current.txt
index 3a33f63361a5..7def58d56a26 100644
--- a/services/core/xsd/platform-compat-schema/current.txt
+++ b/services/core/xsd/platform-compat-schema/current.txt
@@ -7,12 +7,14 @@ package com.android.server.compat.config {
method public boolean getDisabled();
method public int getEnableAfterTargetSdk();
method public long getId();
+ method public boolean getLoggingOnly();
method public String getName();
method public String getValue();
method public void setDescription(String);
method public void setDisabled(boolean);
method public void setEnableAfterTargetSdk(int);
method public void setId(long);
+ method public void setLoggingOnly(boolean);
method public void setName(String);
method public void setValue(String);
}
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
index eed3d9d51e56..312d2d2e2ac2 100644
--- a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
@@ -148,10 +148,6 @@ import android.app.admin.StartInstallingUpdateCallback;
import android.app.admin.SystemUpdateInfo;
import android.app.admin.SystemUpdatePolicy;
import android.app.backup.IBackupManager;
-import android.app.timedetector.ManualTimeSuggestion;
-import android.app.timedetector.TimeDetector;
-import android.app.timezonedetector.ManualTimeZoneSuggestion;
-import android.app.timezonedetector.TimeZoneDetector;
import android.app.trust.TrustManager;
import android.app.usage.UsageStatsManagerInternal;
import android.compat.annotation.ChangeId;
@@ -2118,14 +2114,6 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
return mContext.getSystemService(AlarmManager.class);
}
- TimeDetector getTimeDetector() {
- return mContext.getSystemService(TimeDetector.class);
- }
-
- TimeZoneDetector getTimeZoneDetector() {
- return mContext.getSystemService(TimeZoneDetector.class);
- }
-
ConnectivityManager getConnectivityManager() {
return mContext.getSystemService(ConnectivityManager.class);
}
@@ -2691,6 +2679,27 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
}
}
+ /**
+ * If the device is in Device Owner mode, apply the restriction on adding
+ * a managed profile.
+ */
+ @GuardedBy("getLockObject()")
+ void applyManagedProfileRestrictionIfDeviceOwnerLocked() {
+ final int doUserId = mOwners.getDeviceOwnerUserId();
+ if (doUserId == UserHandle.USER_NULL) {
+ logIfVerbose("No DO found, skipping application of restriction.");
+ return;
+ }
+
+ final UserHandle doUserHandle = UserHandle.of(doUserId);
+ // Set the restriction if not set.
+ if (!mUserManager.hasUserRestriction(
+ UserManager.DISALLOW_ADD_MANAGED_PROFILE, doUserHandle)) {
+ mUserManager.setUserRestriction(UserManager.DISALLOW_ADD_MANAGED_PROFILE, true,
+ doUserHandle);
+ }
+ }
+
/** Apply default restrictions that haven't been applied to profile owners yet. */
private void maybeSetDefaultProfileOwnerUserRestrictions() {
synchronized (getLockObject()) {
@@ -3297,22 +3306,24 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
}
- public DeviceAdminInfo findAdmin(ComponentName adminName, int userHandle,
+ public DeviceAdminInfo findAdmin(final ComponentName adminName, final int userHandle,
boolean throwForMissingPermission) {
if (!mHasFeature) {
return null;
}
enforceFullCrossUsersPermission(userHandle);
- ActivityInfo ai = null;
- try {
- ai = mIPackageManager.getReceiverInfo(adminName,
- PackageManager.GET_META_DATA |
- PackageManager.MATCH_DISABLED_UNTIL_USED_COMPONENTS |
- PackageManager.MATCH_DIRECT_BOOT_AWARE |
- PackageManager.MATCH_DIRECT_BOOT_UNAWARE, userHandle);
- } catch (RemoteException e) {
- // shouldn't happen.
- }
+ final ActivityInfo ai = mInjector.binderWithCleanCallingIdentity(() -> {
+ try {
+ return mIPackageManager.getReceiverInfo(adminName,
+ PackageManager.GET_META_DATA
+ | PackageManager.MATCH_DISABLED_UNTIL_USED_COMPONENTS
+ | PackageManager.MATCH_DIRECT_BOOT_AWARE
+ | PackageManager.MATCH_DIRECT_BOOT_UNAWARE, userHandle);
+ } catch (RemoteException e) {
+ // shouldn't happen.
+ return null;
+ }
+ });
if (ai == null) {
throw new IllegalArgumentException("Unknown admin: " + adminName);
}
@@ -3899,6 +3910,7 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
maybeStartSecurityLogMonitorOnActivityManagerReady();
synchronized (getLockObject()) {
migrateToProfileOnOrganizationOwnedDeviceIfCompLocked();
+ applyManagedProfileRestrictionIfDeviceOwnerLocked();
}
final int userId = getManagedUserId(UserHandle.USER_SYSTEM);
if (userId >= 0) {
@@ -8762,6 +8774,7 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
mOwners.writeProfileOwner(userId);
deleteTransferOwnershipBundleLocked(userId);
toggleBackupServiceActive(userId, true);
+ applyManagedProfileRestrictionIfDeviceOwnerLocked();
}
@Override
@@ -10910,9 +10923,14 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
private void enforcePackageIsSystemPackage(String packageName, int userId)
throws RemoteException {
- if (!isSystemApp(mIPackageManager, packageName, userId)) {
- throw new IllegalArgumentException(
- "The provided package is not a system package");
+ boolean isSystem;
+ try {
+ isSystem = isSystemApp(mIPackageManager, packageName, userId);
+ } catch (IllegalArgumentException e) {
+ isSystem = false;
+ }
+ if (!isSystem) {
+ throw new IllegalArgumentException("The provided package is not a system package");
}
}
@@ -11700,15 +11718,11 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
if (mInjector.settingsGlobalGetInt(Global.AUTO_TIME, 0) == 1) {
return false;
}
- ManualTimeSuggestion manualTimeSuggestion = TimeDetector.createManualTimeSuggestion(
- millis, "DevicePolicyManagerService: setTime");
- mInjector.binderWithCleanCallingIdentity(
- () -> mInjector.getTimeDetector().suggestManualTime(manualTimeSuggestion));
-
DevicePolicyEventLogger
.createEvent(DevicePolicyEnums.SET_TIME)
.setAdmin(who)
.write();
+ mInjector.binderWithCleanCallingIdentity(() -> mInjector.getAlarmManager().setTime(millis));
return true;
}
@@ -11720,11 +11734,8 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
if (mInjector.settingsGlobalGetInt(Global.AUTO_TIME_ZONE, 0) == 1) {
return false;
}
- ManualTimeZoneSuggestion manualTimeZoneSuggestion =
- TimeZoneDetector.createManualTimeZoneSuggestion(
- timeZone, "DevicePolicyManagerService: setTimeZone");
mInjector.binderWithCleanCallingIdentity(() ->
- mInjector.getTimeZoneDetector().suggestManualTimeZone(manualTimeZoneSuggestion));
+ mInjector.getAlarmManager().setTimeZone(timeZone));
DevicePolicyEventLogger
.createEvent(DevicePolicyEnums.SET_TIME_ZONE)
diff --git a/services/incremental/BinderIncrementalService.h b/services/incremental/BinderIncrementalService.h
index 4075da6d8159..28613e101b7c 100644
--- a/services/incremental/BinderIncrementalService.h
+++ b/services/incremental/BinderIncrementalService.h
@@ -31,7 +31,7 @@ public:
BinderIncrementalService(const sp<IServiceManager>& sm);
static BinderIncrementalService* start();
- static const char16_t* getServiceName() { return u"incremental_service"; }
+ static const char16_t* getServiceName() { return u"incremental"; }
status_t dump(int fd, const Vector<String16>& args) final;
void onSystemReady();
diff --git a/services/incremental/IncrementalService.cpp b/services/incremental/IncrementalService.cpp
index 980ae083ad40..2426e8f29dca 100644
--- a/services/incremental/IncrementalService.cpp
+++ b/services/incremental/IncrementalService.cpp
@@ -155,7 +155,7 @@ std::string makeBindMdName() {
} // namespace
IncrementalService::IncFsMount::~IncFsMount() {
- incrementalService.mIncrementalManager->destroyDataLoader(mountId);
+ incrementalService.mDataLoaderManager->destroyDataLoader(mountId);
control.reset();
LOG(INFO) << "Unmounting and cleaning up mount " << mountId << " with root '" << root << '\'';
for (auto&& [target, _] : bindPoints) {
@@ -229,14 +229,14 @@ void IncrementalService::IncFsMount::cleanupFilesystem(std::string_view root) {
IncrementalService::IncrementalService(ServiceManagerWrapper&& sm, std::string_view rootDir)
: mVold(sm.getVoldService()),
- mIncrementalManager(sm.getIncrementalManager()),
+ mDataLoaderManager(sm.getDataLoaderManager()),
mIncFs(sm.getIncFs()),
mIncrementalDir(rootDir) {
if (!mVold) {
LOG(FATAL) << "Vold service is unavailable";
}
- if (!mIncrementalManager) {
- LOG(FATAL) << "IncrementalManager service is unavailable";
+ if (!mDataLoaderManager) {
+ LOG(FATAL) << "DataLoaderManagerService is unavailable";
}
mountExistingImages();
}
@@ -921,7 +921,6 @@ bool IncrementalService::startLoading(StorageId storage) const {
if (!ifs) {
return false;
}
- bool started = false;
std::unique_lock l(ifs->lock);
if (ifs->dataLoaderStatus != IDataLoaderStatusListener::DATA_LOADER_CREATED) {
if (ifs->dataLoaderReady.wait_for(l, Seconds(5)) == std::cv_status::timeout) {
@@ -929,11 +928,19 @@ bool IncrementalService::startLoading(StorageId storage) const {
return false;
}
}
- auto status = mIncrementalManager->startDataLoader(ifs->mountId, &started);
+ sp<IDataLoader> dataloader;
+ auto status = mDataLoaderManager->getDataLoader(ifs->mountId, &dataloader);
if (!status.isOk()) {
return false;
}
- return started;
+ if (!dataloader) {
+ return false;
+ }
+ status = dataloader->start();
+ if (!status.isOk()) {
+ return false;
+ }
+ return true;
}
void IncrementalService::mountExistingImages() {
@@ -1086,8 +1093,8 @@ bool IncrementalService::prepareDataLoader(IncrementalService::IncFsMount& ifs,
sp<IncrementalDataLoaderListener> listener =
new IncrementalDataLoaderListener(*this, *externalListener);
bool created = false;
- auto status = mIncrementalManager->prepareDataLoader(ifs.mountId, fsControlParcel, *dlp,
- listener, &created);
+ auto status = mDataLoaderManager->initializeDataLoader(ifs.mountId, *dlp, fsControlParcel,
+ listener, &created);
if (!status.isOk() || !created) {
LOG(ERROR) << "Failed to create a data loader for mount " << ifs.mountId;
return false;
@@ -1229,16 +1236,7 @@ binder::Status IncrementalService::IncrementalDataLoaderListener::onStatusChange
ifs->dataLoaderStatus = newStatus;
switch (newStatus) {
case IDataLoaderStatusListener::DATA_LOADER_NO_CONNECTION: {
- auto now = Clock::now();
- if (ifs->connectionLostTime.time_since_epoch().count() == 0) {
- ifs->connectionLostTime = now;
- break;
- }
- auto duration =
- std::chrono::duration_cast<Seconds>(now - ifs->connectionLostTime).count();
- if (duration >= 10) {
- incrementalService.mIncrementalManager->showHealthBlockedUI(mountId);
- }
+ // TODO(b/150411019): handle data loader connection loss
break;
}
case IDataLoaderStatusListener::DATA_LOADER_CONNECTION_OK: {
diff --git a/services/incremental/IncrementalService.h b/services/incremental/IncrementalService.h
index 19424973b035..8ff441b5a276 100644
--- a/services/incremental/IncrementalService.h
+++ b/services/incremental/IncrementalService.h
@@ -19,7 +19,6 @@
#include <android-base/strings.h>
#include <android-base/unique_fd.h>
#include <android/content/pm/DataLoaderParamsParcel.h>
-#include <android/os/incremental/IIncrementalManager.h>
#include <binder/IServiceManager.h>
#include <utils/String16.h>
#include <utils/StrongPointer.h>
@@ -220,7 +219,7 @@ private:
// Member variables
std::unique_ptr<VoldServiceWrapper> mVold;
- std::unique_ptr<IncrementalManagerWrapper> mIncrementalManager;
+ std::unique_ptr<DataLoaderManagerWrapper> mDataLoaderManager;
std::unique_ptr<IncFsWrapper> mIncFs;
const std::string mIncrementalDir;
diff --git a/services/incremental/ServiceWrappers.cpp b/services/incremental/ServiceWrappers.cpp
index 5d978a1cf741..2e31ef1dcc2f 100644
--- a/services/incremental/ServiceWrappers.cpp
+++ b/services/incremental/ServiceWrappers.cpp
@@ -23,7 +23,7 @@ using namespace std::literals;
namespace android::os::incremental {
static constexpr auto kVoldServiceName = "vold"sv;
-static constexpr auto kIncrementalManagerName = "incremental"sv;
+static constexpr auto kDataLoaderManagerName = "dataloader_manager"sv;
RealServiceManager::RealServiceManager(sp<IServiceManager> serviceManager)
: mServiceManager(std::move(serviceManager)) {}
@@ -46,11 +46,11 @@ std::unique_ptr<VoldServiceWrapper> RealServiceManager::getVoldService() {
return nullptr;
}
-std::unique_ptr<IncrementalManagerWrapper> RealServiceManager::getIncrementalManager() {
- sp<IIncrementalManager> manager =
- RealServiceManager::getRealService<IIncrementalManager>(kIncrementalManagerName);
+std::unique_ptr<DataLoaderManagerWrapper> RealServiceManager::getDataLoaderManager() {
+ sp<IDataLoaderManager> manager =
+ RealServiceManager::getRealService<IDataLoaderManager>(kDataLoaderManagerName);
if (manager) {
- return std::make_unique<RealIncrementalManager>(manager);
+ return std::make_unique<RealDataLoaderManager>(manager);
}
return nullptr;
}
diff --git a/services/incremental/ServiceWrappers.h b/services/incremental/ServiceWrappers.h
index c574ca73c090..5349ebff5052 100644
--- a/services/incremental/ServiceWrappers.h
+++ b/services/incremental/ServiceWrappers.h
@@ -20,9 +20,10 @@
#include <android-base/unique_fd.h>
#include <android/content/pm/DataLoaderParamsParcel.h>
#include <android/content/pm/FileSystemControlParcel.h>
+#include <android/content/pm/IDataLoader.h>
+#include <android/content/pm/IDataLoaderManager.h>
#include <android/content/pm/IDataLoaderStatusListener.h>
#include <android/os/IVold.h>
-#include <android/os/incremental/IIncrementalManager.h>
#include <binder/IServiceManager.h>
#include <incfs.h>
@@ -50,17 +51,16 @@ public:
const std::string& targetDir) const = 0;
};
-class IncrementalManagerWrapper {
+class DataLoaderManagerWrapper {
public:
- virtual ~IncrementalManagerWrapper() = default;
- virtual binder::Status prepareDataLoader(MountId mountId,
- const FileSystemControlParcel& control,
- const DataLoaderParamsParcel& params,
- const sp<IDataLoaderStatusListener>& listener,
- bool* _aidl_return) const = 0;
- virtual binder::Status startDataLoader(MountId mountId, bool* _aidl_return) const = 0;
+ virtual ~DataLoaderManagerWrapper() = default;
+ virtual binder::Status initializeDataLoader(MountId mountId,
+ const DataLoaderParamsParcel& params,
+ const FileSystemControlParcel& control,
+ const sp<IDataLoaderStatusListener>& listener,
+ bool* _aidl_return) const = 0;
+ virtual binder::Status getDataLoader(MountId mountId, sp<IDataLoader>* _aidl_return) const = 0;
virtual binder::Status destroyDataLoader(MountId mountId) const = 0;
- virtual binder::Status showHealthBlockedUI(MountId mountId) const = 0;
};
class IncFsWrapper {
@@ -82,7 +82,7 @@ class ServiceManagerWrapper {
public:
virtual ~ServiceManagerWrapper() = default;
virtual std::unique_ptr<VoldServiceWrapper> getVoldService() = 0;
- virtual std::unique_ptr<IncrementalManagerWrapper> getIncrementalManager() = 0;
+ virtual std::unique_ptr<DataLoaderManagerWrapper> getDataLoaderManager() = 0;
virtual std::unique_ptr<IncFsWrapper> getIncFs() = 0;
};
@@ -109,29 +109,26 @@ private:
sp<os::IVold> mInterface;
};
-class RealIncrementalManager : public IncrementalManagerWrapper {
+class RealDataLoaderManager : public DataLoaderManagerWrapper {
public:
- RealIncrementalManager(const sp<os::incremental::IIncrementalManager> manager)
+ RealDataLoaderManager(const sp<content::pm::IDataLoaderManager> manager)
: mInterface(manager) {}
- ~RealIncrementalManager() = default;
- binder::Status prepareDataLoader(MountId mountId, const FileSystemControlParcel& control,
- const DataLoaderParamsParcel& params,
- const sp<IDataLoaderStatusListener>& listener,
- bool* _aidl_return) const override {
- return mInterface->prepareDataLoader(mountId, control, params, listener, _aidl_return);
+ ~RealDataLoaderManager() = default;
+ binder::Status initializeDataLoader(MountId mountId, const DataLoaderParamsParcel& params,
+ const FileSystemControlParcel& control,
+ const sp<IDataLoaderStatusListener>& listener,
+ bool* _aidl_return) const override {
+ return mInterface->initializeDataLoader(mountId, params, control, listener, _aidl_return);
}
- binder::Status startDataLoader(MountId mountId, bool* _aidl_return) const override {
- return mInterface->startDataLoader(mountId, _aidl_return);
+ binder::Status getDataLoader(MountId mountId, sp<IDataLoader>* _aidl_return) const override {
+ return mInterface->getDataLoader(mountId, _aidl_return);
}
binder::Status destroyDataLoader(MountId mountId) const override {
return mInterface->destroyDataLoader(mountId);
}
- binder::Status showHealthBlockedUI(MountId mountId) const override {
- return mInterface->showHealthBlockedUI(mountId);
- }
private:
- sp<os::incremental::IIncrementalManager> mInterface;
+ sp<content::pm::IDataLoaderManager> mInterface;
};
class RealServiceManager : public ServiceManagerWrapper {
@@ -139,7 +136,7 @@ public:
RealServiceManager(sp<IServiceManager> serviceManager);
~RealServiceManager() = default;
std::unique_ptr<VoldServiceWrapper> getVoldService() override;
- std::unique_ptr<IncrementalManagerWrapper> getIncrementalManager() override;
+ std::unique_ptr<DataLoaderManagerWrapper> getDataLoaderManager() override;
std::unique_ptr<IncFsWrapper> getIncFs() override;
private:
diff --git a/services/incremental/test/IncrementalServiceTest.cpp b/services/incremental/test/IncrementalServiceTest.cpp
index aca6ca49e805..6002226f9630 100644
--- a/services/incremental/test/IncrementalServiceTest.cpp
+++ b/services/incremental/test/IncrementalServiceTest.cpp
@@ -93,47 +93,60 @@ private:
TemporaryFile logFile;
};
-class MockIncrementalManager : public IncrementalManagerWrapper {
+class FakeDataLoader : public IDataLoader {
public:
- MOCK_CONST_METHOD5(prepareDataLoader,
- binder::Status(int32_t mountId, const FileSystemControlParcel& control,
- const DataLoaderParamsParcel& params,
+ IBinder* onAsBinder() override { return nullptr; }
+ binder::Status create(int32_t, const DataLoaderParamsParcel&, const FileSystemControlParcel&,
+ const sp<IDataLoaderStatusListener>&) override {
+ return binder::Status::ok();
+ }
+ binder::Status start() override { return binder::Status::ok(); }
+ binder::Status stop() override { return binder::Status::ok(); }
+ binder::Status destroy() override { return binder::Status::ok(); }
+ binder::Status prepareImage(const std::vector<InstallationFileParcel>&,
+ const std::vector<std::string>&) override {
+ return binder::Status::ok();
+ }
+};
+
+class MockDataLoaderManager : public DataLoaderManagerWrapper {
+public:
+ MOCK_CONST_METHOD5(initializeDataLoader,
+ binder::Status(int32_t mountId, const DataLoaderParamsParcel& params,
+ const FileSystemControlParcel& control,
const sp<IDataLoaderStatusListener>& listener,
bool* _aidl_return));
- MOCK_CONST_METHOD2(startDataLoader, binder::Status(int32_t mountId, bool* _aidl_return));
+ MOCK_CONST_METHOD2(getDataLoader,
+ binder::Status(int32_t mountId, sp<IDataLoader>* _aidl_return));
MOCK_CONST_METHOD1(destroyDataLoader, binder::Status(int32_t mountId));
- MOCK_CONST_METHOD3(newFileForDataLoader,
- binder::Status(int32_t mountId, FileId fileId,
- const ::std::vector<uint8_t>& metadata));
- MOCK_CONST_METHOD1(showHealthBlockedUI, binder::Status(int32_t mountId));
-
- binder::Status prepareDataLoaderOk(int32_t mountId, const FileSystemControlParcel& control,
- const DataLoaderParamsParcel& params,
- const sp<IDataLoaderStatusListener>& listener,
- bool* _aidl_return) {
+
+ binder::Status initializeDataLoaderOk(int32_t mountId, const DataLoaderParamsParcel& params,
+ const FileSystemControlParcel& control,
+ const sp<IDataLoaderStatusListener>& listener,
+ bool* _aidl_return) {
mId = mountId;
mListener = listener;
*_aidl_return = true;
return binder::Status::ok();
}
- binder::Status startDataLoaderOk(int32_t mountId, bool* _aidl_return) {
- *_aidl_return = true;
+ binder::Status getDataLoaderOk(int32_t mountId, sp<IDataLoader>* _aidl_return) {
+ *_aidl_return = mDataLoader;
return binder::Status::ok();
}
- void prepareDataLoaderFails() {
- ON_CALL(*this, prepareDataLoader(_, _, _, _, _))
+ void initializeDataLoaderFails() {
+ ON_CALL(*this, initializeDataLoader(_, _, _, _, _))
.WillByDefault(Return(
(binder::Status::fromExceptionCode(1, String8("failed to prepare")))));
}
- void prepareDataLoaderSuccess() {
- ON_CALL(*this, prepareDataLoader(_, _, _, _, _))
- .WillByDefault(Invoke(this, &MockIncrementalManager::prepareDataLoaderOk));
+ void initializeDataLoaderSuccess() {
+ ON_CALL(*this, initializeDataLoader(_, _, _, _, _))
+ .WillByDefault(Invoke(this, &MockDataLoaderManager::initializeDataLoaderOk));
}
- void startDataLoaderSuccess() {
- ON_CALL(*this, startDataLoader(_, _))
- .WillByDefault(Invoke(this, &MockIncrementalManager::startDataLoaderOk));
+ void getDataLoaderSuccess() {
+ ON_CALL(*this, getDataLoader(_, _))
+ .WillByDefault(Invoke(this, &MockDataLoaderManager::getDataLoaderOk));
}
void setDataLoaderStatusNotReady() {
mListener->onStatusChanged(mId, IDataLoaderStatusListener::DATA_LOADER_DESTROYED);
@@ -145,6 +158,7 @@ public:
private:
int mId;
sp<IDataLoaderStatusListener> mListener;
+ sp<IDataLoader> mDataLoader = sp<IDataLoader>(new FakeDataLoader());
};
class MockIncFs : public IncFsWrapper {
@@ -197,20 +211,20 @@ public:
class MockServiceManager : public ServiceManagerWrapper {
public:
MockServiceManager(std::unique_ptr<MockVoldService> vold,
- std::unique_ptr<MockIncrementalManager> manager,
+ std::unique_ptr<MockDataLoaderManager> manager,
std::unique_ptr<MockIncFs> incfs)
: mVold(std::move(vold)),
- mIncrementalManager(std::move(manager)),
+ mDataLoaderManager(std::move(manager)),
mIncFs(std::move(incfs)) {}
std::unique_ptr<VoldServiceWrapper> getVoldService() final { return std::move(mVold); }
- std::unique_ptr<IncrementalManagerWrapper> getIncrementalManager() final {
- return std::move(mIncrementalManager);
+ std::unique_ptr<DataLoaderManagerWrapper> getDataLoaderManager() final {
+ return std::move(mDataLoaderManager);
}
std::unique_ptr<IncFsWrapper> getIncFs() final { return std::move(mIncFs); }
private:
std::unique_ptr<MockVoldService> mVold;
- std::unique_ptr<MockIncrementalManager> mIncrementalManager;
+ std::unique_ptr<MockDataLoaderManager> mDataLoaderManager;
std::unique_ptr<MockIncFs> mIncFs;
};
@@ -221,14 +235,14 @@ public:
void SetUp() override {
auto vold = std::make_unique<NiceMock<MockVoldService>>();
mVold = vold.get();
- auto incrementalManager = std::make_unique<NiceMock<MockIncrementalManager>>();
- mIncrementalManager = incrementalManager.get();
+ auto dataloaderManager = std::make_unique<NiceMock<MockDataLoaderManager>>();
+ mDataLoaderManager = dataloaderManager.get();
auto incFs = std::make_unique<NiceMock<MockIncFs>>();
mIncFs = incFs.get();
mIncrementalService =
std::make_unique<IncrementalService>(MockServiceManager(std::move(vold),
std::move(
- incrementalManager),
+ dataloaderManager),
std::move(incFs)),
mRootDir.path);
mDataLoaderParcel.packageName = "com.test";
@@ -260,7 +274,7 @@ public:
protected:
NiceMock<MockVoldService>* mVold;
NiceMock<MockIncFs>* mIncFs;
- NiceMock<MockIncrementalManager>* mIncrementalManager;
+ NiceMock<MockDataLoaderManager>* mDataLoaderManager;
std::unique_ptr<IncrementalService> mIncrementalService;
TemporaryDir mRootDir;
DataLoaderParamsParcel mDataLoaderParcel;
@@ -268,7 +282,7 @@ protected:
TEST_F(IncrementalServiceTest, testCreateStorageMountIncFsFails) {
mVold->mountIncFsFails();
- EXPECT_CALL(*mIncrementalManager, prepareDataLoader(_, _, _, _, _)).Times(0);
+ EXPECT_CALL(*mDataLoaderManager, initializeDataLoader(_, _, _, _, _)).Times(0);
TemporaryDir tempDir;
int storageId =
mIncrementalService->createStorage(tempDir.path, std::move(mDataLoaderParcel), {},
@@ -278,7 +292,7 @@ TEST_F(IncrementalServiceTest, testCreateStorageMountIncFsFails) {
TEST_F(IncrementalServiceTest, testCreateStorageMountIncFsInvalidControlParcel) {
mVold->mountIncFsInvalidControlParcel();
- EXPECT_CALL(*mIncrementalManager, prepareDataLoader(_, _, _, _, _)).Times(0);
+ EXPECT_CALL(*mDataLoaderManager, initializeDataLoader(_, _, _, _, _)).Times(0);
TemporaryDir tempDir;
int storageId =
mIncrementalService->createStorage(tempDir.path, std::move(mDataLoaderParcel), {},
@@ -289,8 +303,8 @@ TEST_F(IncrementalServiceTest, testCreateStorageMountIncFsInvalidControlParcel)
TEST_F(IncrementalServiceTest, testCreateStorageMakeFileFails) {
mVold->mountIncFsSuccess();
mIncFs->makeFileFails();
- EXPECT_CALL(*mIncrementalManager, prepareDataLoader(_, _, _, _, _)).Times(0);
- EXPECT_CALL(*mIncrementalManager, destroyDataLoader(_));
+ EXPECT_CALL(*mDataLoaderManager, initializeDataLoader(_, _, _, _, _)).Times(0);
+ EXPECT_CALL(*mDataLoaderManager, destroyDataLoader(_));
EXPECT_CALL(*mVold, unmountIncFs(_));
TemporaryDir tempDir;
int storageId =
@@ -303,8 +317,8 @@ TEST_F(IncrementalServiceTest, testCreateStorageBindMountFails) {
mVold->mountIncFsSuccess();
mIncFs->makeFileSuccess();
mVold->bindMountFails();
- EXPECT_CALL(*mIncrementalManager, prepareDataLoader(_, _, _, _, _)).Times(0);
- EXPECT_CALL(*mIncrementalManager, destroyDataLoader(_));
+ EXPECT_CALL(*mDataLoaderManager, initializeDataLoader(_, _, _, _, _)).Times(0);
+ EXPECT_CALL(*mDataLoaderManager, destroyDataLoader(_));
EXPECT_CALL(*mVold, unmountIncFs(_));
TemporaryDir tempDir;
int storageId =
@@ -317,8 +331,8 @@ TEST_F(IncrementalServiceTest, testCreateStoragePrepareDataLoaderFails) {
mVold->mountIncFsSuccess();
mIncFs->makeFileSuccess();
mVold->bindMountSuccess();
- mIncrementalManager->prepareDataLoaderFails();
- EXPECT_CALL(*mIncrementalManager, destroyDataLoader(_));
+ mDataLoaderManager->initializeDataLoaderFails();
+ EXPECT_CALL(*mDataLoaderManager, destroyDataLoader(_));
EXPECT_CALL(*mVold, unmountIncFs(_)).Times(2);
TemporaryDir tempDir;
int storageId =
@@ -331,8 +345,8 @@ TEST_F(IncrementalServiceTest, testDeleteStorageSuccess) {
mVold->mountIncFsSuccess();
mIncFs->makeFileSuccess();
mVold->bindMountSuccess();
- mIncrementalManager->prepareDataLoaderSuccess();
- EXPECT_CALL(*mIncrementalManager, destroyDataLoader(_));
+ mDataLoaderManager->initializeDataLoaderSuccess();
+ EXPECT_CALL(*mDataLoaderManager, destroyDataLoader(_));
EXPECT_CALL(*mVold, unmountIncFs(_)).Times(2);
TemporaryDir tempDir;
int storageId =
@@ -346,31 +360,31 @@ TEST_F(IncrementalServiceTest, testOnStatusNotReady) {
mVold->mountIncFsSuccess();
mIncFs->makeFileSuccess();
mVold->bindMountSuccess();
- mIncrementalManager->prepareDataLoaderSuccess();
- EXPECT_CALL(*mIncrementalManager, destroyDataLoader(_));
+ mDataLoaderManager->initializeDataLoaderSuccess();
+ EXPECT_CALL(*mDataLoaderManager, destroyDataLoader(_));
EXPECT_CALL(*mVold, unmountIncFs(_)).Times(2);
TemporaryDir tempDir;
int storageId =
mIncrementalService->createStorage(tempDir.path, std::move(mDataLoaderParcel), {},
IncrementalService::CreateOptions::CreateNew);
ASSERT_GE(storageId, 0);
- mIncrementalManager->setDataLoaderStatusNotReady();
+ mDataLoaderManager->setDataLoaderStatusNotReady();
}
TEST_F(IncrementalServiceTest, testStartDataLoaderSuccess) {
mVold->mountIncFsSuccess();
mIncFs->makeFileSuccess();
mVold->bindMountSuccess();
- mIncrementalManager->prepareDataLoaderSuccess();
- mIncrementalManager->startDataLoaderSuccess();
- EXPECT_CALL(*mIncrementalManager, destroyDataLoader(_));
+ mDataLoaderManager->initializeDataLoaderSuccess();
+ mDataLoaderManager->getDataLoaderSuccess();
+ EXPECT_CALL(*mDataLoaderManager, destroyDataLoader(_));
EXPECT_CALL(*mVold, unmountIncFs(_)).Times(2);
TemporaryDir tempDir;
int storageId =
mIncrementalService->createStorage(tempDir.path, std::move(mDataLoaderParcel), {},
IncrementalService::CreateOptions::CreateNew);
ASSERT_GE(storageId, 0);
- mIncrementalManager->setDataLoaderStatusReady();
+ mDataLoaderManager->setDataLoaderStatusReady();
ASSERT_TRUE(mIncrementalService->startLoading(storageId));
}
@@ -378,8 +392,8 @@ TEST_F(IncrementalServiceTest, testMakeDirectory) {
mVold->mountIncFsSuccess();
mIncFs->makeFileSuccess();
mVold->bindMountSuccess();
- mIncrementalManager->prepareDataLoaderSuccess();
- mIncrementalManager->startDataLoaderSuccess();
+ mDataLoaderManager->initializeDataLoaderSuccess();
+ mDataLoaderManager->getDataLoaderSuccess();
TemporaryDir tempDir;
int storageId =
mIncrementalService->createStorage(tempDir.path, std::move(mDataLoaderParcel), {},
@@ -402,8 +416,8 @@ TEST_F(IncrementalServiceTest, testMakeDirectories) {
mVold->mountIncFsSuccess();
mIncFs->makeFileSuccess();
mVold->bindMountSuccess();
- mIncrementalManager->prepareDataLoaderSuccess();
- mIncrementalManager->startDataLoaderSuccess();
+ mDataLoaderManager->initializeDataLoaderSuccess();
+ mDataLoaderManager->getDataLoaderSuccess();
TemporaryDir tempDir;
int storageId =
mIncrementalService->createStorage(tempDir.path, std::move(mDataLoaderParcel), {},
diff --git a/services/java/com/android/server/SystemServer.java b/services/java/com/android/server/SystemServer.java
index c1ac55f88a9d..b019e9dd03ba 100644
--- a/services/java/com/android/server/SystemServer.java
+++ b/services/java/com/android/server/SystemServer.java
@@ -105,7 +105,6 @@ import com.android.server.emergency.EmergencyAffordanceService;
import com.android.server.gpu.GpuService;
import com.android.server.hdmi.HdmiControlService;
import com.android.server.incident.IncidentCompanionService;
-import com.android.server.incremental.IncrementalManagerService;
import com.android.server.input.InputManagerService;
import com.android.server.inputmethod.InputMethodManagerService;
import com.android.server.inputmethod.InputMethodSystemProperty;
@@ -295,8 +294,6 @@ public final class SystemServer {
"com.android.server.DeviceIdleController";
private static final String BLOB_STORE_MANAGER_SERVICE_CLASS =
"com.android.server.blob.BlobStoreManagerService";
- private static final String APP_SEARCH_MANAGER_SERVICE_CLASS =
- "com.android.server.appsearch.AppSearchManagerService";
private static final String TETHERING_CONNECTOR_CLASS = "android.net.ITetheringConnector";
@@ -335,7 +332,7 @@ public final class SystemServer {
private ContentResolver mContentResolver;
private EntropyMixer mEntropyMixer;
private DataLoaderManagerService mDataLoaderManagerService;
- private IncrementalManagerService mIncrementalManagerService;
+ private long mIncrementalServiceHandle = 0;
private boolean mOnlyCore;
private boolean mFirstBoot;
@@ -378,6 +375,16 @@ public final class SystemServer {
private static native void spawnFdLeakCheckThread();
/**
+ * Start native Incremental Service and get its handle.
+ */
+ private static native long startIncrementalService();
+
+ /**
+ * Inform Incremental Service that system is ready.
+ */
+ private static native void setIncrementalServiceSystemReady(long incrementalServiceHandle);
+
+ /**
* The main entry point from zygote.
*/
public static void main(String[] args) {
@@ -745,8 +752,8 @@ public final class SystemServer {
t.traceEnd();
// Incremental service needs to be started before package manager
- t.traceBegin("StartIncrementalManagerService");
- mIncrementalManagerService = IncrementalManagerService.start(mSystemContext);
+ t.traceBegin("StartIncrementalService");
+ mIncrementalServiceHandle = startIncrementalService();
t.traceEnd();
// Power manager needs to be started early because other services need it.
@@ -2133,9 +2140,9 @@ public final class SystemServer {
mPackageManagerService.systemReady();
t.traceEnd();
- if (mIncrementalManagerService != null) {
- t.traceBegin("MakeIncrementalManagerServiceReady");
- mIncrementalManagerService.systemReady();
+ if (mIncrementalServiceHandle != 0) {
+ t.traceBegin("MakeIncrementalServiceReady");
+ setIncrementalServiceSystemReady(mIncrementalServiceHandle);
t.traceEnd();
}
@@ -2169,10 +2176,6 @@ public final class SystemServer {
mSystemServiceManager.startBootPhase(t, SystemService.PHASE_DEVICE_SPECIFIC_SERVICES_READY);
t.traceEnd();
- t.traceBegin("AppSearchManagerService");
- mSystemServiceManager.startService(APP_SEARCH_MANAGER_SERVICE_CLASS);
- t.traceEnd();
-
ConcurrentUtils.waitForFutureNoInterrupt(mBlobStoreServiceStart,
START_BLOB_STORE_SERVICE);
diff --git a/services/people/java/com/android/server/people/PeopleService.java b/services/people/java/com/android/server/people/PeopleService.java
index 983a639776f6..37bf66491882 100644
--- a/services/people/java/com/android/server/people/PeopleService.java
+++ b/services/people/java/com/android/server/people/PeopleService.java
@@ -72,13 +72,13 @@ public class PeopleService extends SystemService {
}
@Override
- public void onUserUnlocking(@NonNull TargetUser targetUser) {
- mDataManager.onUserUnlocked(targetUser.getUserIdentifier());
+ public void onUserUnlocked(@NonNull TargetUser user) {
+ mDataManager.onUserUnlocked(user.getUserIdentifier());
}
@Override
- public void onUserStopping(@NonNull TargetUser targetUser) {
- mDataManager.onUserStopped(targetUser.getUserIdentifier());
+ public void onUserStopping(@NonNull TargetUser user) {
+ mDataManager.onUserStopping(user.getUserIdentifier());
}
@VisibleForTesting
diff --git a/services/people/java/com/android/server/people/data/DataManager.java b/services/people/java/com/android/server/people/data/DataManager.java
index e4ce6bafff31..4e0afc525383 100644
--- a/services/people/java/com/android/server/people/data/DataManager.java
+++ b/services/people/java/com/android/server/people/data/DataManager.java
@@ -198,13 +198,13 @@ public class DataManager {
DataMaintenanceService.scheduleJob(mContext, userId);
}
- /** This method is called when a user is stopped. */
- public void onUserStopped(int userId) {
+ /** This method is called when a user is stopping. */
+ public void onUserStopping(int userId) {
if (mUserDataArray.indexOfKey(userId) >= 0) {
mUserDataArray.get(userId).setUserStopped();
}
if (mUsageStatsQueryFutures.indexOfKey(userId) >= 0) {
- mUsageStatsQueryFutures.valueAt(userId).cancel(true);
+ mUsageStatsQueryFutures.get(userId).cancel(true);
}
if (mBroadcastReceivers.indexOfKey(userId) >= 0) {
mContext.unregisterReceiver(mBroadcastReceivers.get(userId));
diff --git a/services/tests/mockingservicestests/src/com/android/server/am/ApplicationExitInfoTest.java b/services/tests/mockingservicestests/src/com/android/server/am/ApplicationExitInfoTest.java
index 6083ce34a3bd..95f4e832cd2d 100644
--- a/services/tests/mockingservicestests/src/com/android/server/am/ApplicationExitInfoTest.java
+++ b/services/tests/mockingservicestests/src/com/android/server/am/ApplicationExitInfoTest.java
@@ -847,8 +847,8 @@ public class ApplicationExitInfoTest {
app.connectionGroup = connectionGroup;
app.setProcState = procState;
app.lastMemInfo = spy(new Debug.MemoryInfo());
- doReturn((int) pss).when(app.lastMemInfo).getTotalPss();
- doReturn((int) rss).when(app.lastMemInfo).getTotalRss();
+ app.lastPss = pss;
+ app.mLastRss = rss;
return app;
}
diff --git a/services/tests/mockingservicestests/src/com/android/server/am/CachedAppOptimizerTest.java b/services/tests/mockingservicestests/src/com/android/server/am/CachedAppOptimizerTest.java
index 4722b39cc652..e5ec1f76c554 100644
--- a/services/tests/mockingservicestests/src/com/android/server/am/CachedAppOptimizerTest.java
+++ b/services/tests/mockingservicestests/src/com/android/server/am/CachedAppOptimizerTest.java
@@ -36,6 +36,7 @@ import com.android.server.appop.AppOpsService;
import com.android.server.testables.TestableDeviceConfig;
import org.junit.After;
+import org.junit.Assume;
import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
@@ -267,9 +268,7 @@ public final class CachedAppOptimizerTest {
@Test
public void useFreeze_doesNotListenToDeviceConfigChanges() throws InterruptedException {
- if (!mCachedAppOptimizerUnderTest.isFreezerSupported()) {
- return;
- }
+ Assume.assumeTrue(mCachedAppOptimizerUnderTest.isFreezerSupported());
assertThat(mCachedAppOptimizerUnderTest.useFreezer()).isEqualTo(
CachedAppOptimizer.DEFAULT_USE_FREEZER);
diff --git a/services/tests/mockingservicestests/src/com/android/server/blob/BlobStoreConfigTest.java b/services/tests/mockingservicestests/src/com/android/server/blob/BlobStoreConfigTest.java
new file mode 100644
index 000000000000..ad19a4893153
--- /dev/null
+++ b/services/tests/mockingservicestests/src/com/android/server/blob/BlobStoreConfigTest.java
@@ -0,0 +1,94 @@
+/*
+ * Copyright 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.server.blob;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import static junit.framework.Assert.fail;
+
+import android.content.Context;
+import android.os.Environment;
+import android.platform.test.annotations.Presubmit;
+import android.provider.DeviceConfig;
+import android.util.DataUnit;
+
+import androidx.test.InstrumentationRegistry;
+import androidx.test.filters.SmallTest;
+import androidx.test.runner.AndroidJUnit4;
+
+import com.android.server.testables.TestableDeviceConfig;
+
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.TimeUnit;
+
+@RunWith(AndroidJUnit4.class)
+@SmallTest
+@Presubmit
+public class BlobStoreConfigTest {
+ private static final long TIMEOUT_UPDATE_PROPERTIES_MS = 1_000;
+
+ @Rule
+ public TestableDeviceConfig.TestableDeviceConfigRule
+ mDeviceConfigRule = new TestableDeviceConfig.TestableDeviceConfigRule();
+
+ private Context mContext;
+
+ @Before
+ public void setUp() {
+ mContext = InstrumentationRegistry.getInstrumentation().getTargetContext();
+ BlobStoreConfig.initialize(mContext);
+ }
+
+ @Test
+ public void testGetAppDataBytesLimit() throws Exception {
+ DeviceConfig.setProperty(DeviceConfig.NAMESPACE_BLOBSTORE,
+ BlobStoreConfig.DeviceConfigProperties.KEY_TOTAL_BYTES_PER_APP_LIMIT_FLOOR,
+ String.valueOf(DataUnit.MEBIBYTES.toBytes(1000)),
+ false /* makeDefault */);
+ DeviceConfig.setProperty(DeviceConfig.NAMESPACE_BLOBSTORE,
+ BlobStoreConfig.DeviceConfigProperties.KEY_TOTAL_BYTES_PER_APP_LIMIT_FRACTION,
+ String.valueOf(0.002f),
+ false /* makeDefault */);
+ waitForListenerToHandle();
+ assertThat(BlobStoreConfig.getAppDataBytesLimit()).isEqualTo(
+ DataUnit.MEBIBYTES.toBytes(1000));
+
+ DeviceConfig.setProperty(DeviceConfig.NAMESPACE_BLOBSTORE,
+ BlobStoreConfig.DeviceConfigProperties.KEY_TOTAL_BYTES_PER_APP_LIMIT_FLOOR,
+ String.valueOf(DataUnit.MEBIBYTES.toBytes(100)),
+ false /* makeDefault */);
+ DeviceConfig.setProperty(DeviceConfig.NAMESPACE_BLOBSTORE,
+ BlobStoreConfig.DeviceConfigProperties.KEY_TOTAL_BYTES_PER_APP_LIMIT_FRACTION,
+ String.valueOf(0.1f),
+ false /* makeDefault */);
+ waitForListenerToHandle();
+ final long expectedLimit = (long) (Environment.getDataDirectory().getTotalSpace() * 0.1f);
+ assertThat(BlobStoreConfig.getAppDataBytesLimit()).isEqualTo(expectedLimit);
+ }
+
+ private void waitForListenerToHandle() throws Exception {
+ final CountDownLatch latch = new CountDownLatch(1);
+ mContext.getMainExecutor().execute(latch::countDown);
+ if (!latch.await(TIMEOUT_UPDATE_PROPERTIES_MS, TimeUnit.MILLISECONDS)) {
+ fail("Timed out waiting for properties to get updated");
+ }
+ }
+}
diff --git a/services/tests/mockingservicestests/src/com/android/server/blob/BlobStoreManagerServiceTest.java b/services/tests/mockingservicestests/src/com/android/server/blob/BlobStoreManagerServiceTest.java
index 6e0df3ecfabf..cd39144d5c6b 100644
--- a/services/tests/mockingservicestests/src/com/android/server/blob/BlobStoreManagerServiceTest.java
+++ b/services/tests/mockingservicestests/src/com/android/server/blob/BlobStoreManagerServiceTest.java
@@ -303,6 +303,37 @@ public class BlobStoreManagerServiceTest {
assertThat(mService.getKnownIdsForTest()).containsExactly(blobId1, blobId2, blobId3);
}
+ @Test
+ public void testGetTotalUsageBytes() throws Exception {
+ // Setup blobs
+ final BlobMetadata blobMetadata1 = mock(BlobMetadata.class);
+ final long size1 = 4567;
+ doReturn(size1).when(blobMetadata1).getSize();
+ doReturn(true).when(blobMetadata1).isALeasee(TEST_PKG1, TEST_UID1);
+ doReturn(true).when(blobMetadata1).isALeasee(TEST_PKG2, TEST_UID2);
+ mUserBlobs.put(mock(BlobHandle.class), blobMetadata1);
+
+ final BlobMetadata blobMetadata2 = mock(BlobMetadata.class);
+ final long size2 = 89475;
+ doReturn(size2).when(blobMetadata2).getSize();
+ doReturn(false).when(blobMetadata2).isALeasee(TEST_PKG1, TEST_UID1);
+ doReturn(true).when(blobMetadata2).isALeasee(TEST_PKG2, TEST_UID2);
+ mUserBlobs.put(mock(BlobHandle.class), blobMetadata2);
+
+ final BlobMetadata blobMetadata3 = mock(BlobMetadata.class);
+ final long size3 = 328732;
+ doReturn(size3).when(blobMetadata3).getSize();
+ doReturn(true).when(blobMetadata3).isALeasee(TEST_PKG1, TEST_UID1);
+ doReturn(false).when(blobMetadata3).isALeasee(TEST_PKG2, TEST_UID2);
+ mUserBlobs.put(mock(BlobHandle.class), blobMetadata3);
+
+ // Verify usage is calculated correctly
+ assertThat(mService.getTotalUsageBytesLocked(TEST_UID1, TEST_PKG1))
+ .isEqualTo(size1 + size3);
+ assertThat(mService.getTotalUsageBytesLocked(TEST_UID2, TEST_PKG2))
+ .isEqualTo(size1 + size2);
+ }
+
private BlobStoreSession createBlobStoreSessionMock(String ownerPackageName, int ownerUid,
long sessionId, File sessionFile) {
return createBlobStoreSessionMock(ownerPackageName, ownerUid, sessionId, sessionFile,
diff --git a/services/tests/mockingservicestests/src/com/android/server/testables/TestableDeviceConfig.java b/services/tests/mockingservicestests/src/com/android/server/testables/TestableDeviceConfig.java
index 32631be3ec24..64b24c12f046 100644
--- a/services/tests/mockingservicestests/src/com/android/server/testables/TestableDeviceConfig.java
+++ b/services/tests/mockingservicestests/src/com/android/server/testables/TestableDeviceConfig.java
@@ -24,15 +24,18 @@ import static org.mockito.ArgumentMatchers.anyFloat;
import static org.mockito.ArgumentMatchers.anyInt;
import static org.mockito.ArgumentMatchers.anyLong;
import static org.mockito.ArgumentMatchers.anyString;
+import static org.mockito.ArgumentMatchers.nullable;
import static org.mockito.Mockito.when;
import android.provider.DeviceConfig;
import android.provider.DeviceConfig.Properties;
+import android.util.ArrayMap;
import android.util.Pair;
import com.android.dx.mockito.inline.extended.StaticMockitoSessionBuilder;
import org.junit.rules.TestRule;
+import org.mockito.ArgumentMatchers;
import org.mockito.Mockito;
import org.mockito.stubbing.Answer;
@@ -109,6 +112,27 @@ public final class TestableDeviceConfig implements StaticMockFixture {
String name = invocationOnMock.getArgument(1);
return mKeyValueMap.get(getKey(namespace, name));
}).when(() -> DeviceConfig.getProperty(anyString(), anyString()));
+
+ doAnswer((Answer<Properties>) invocationOnMock -> {
+ String namespace = invocationOnMock.getArgument(0);
+ final int varargStartIdx = 1;
+ Map<String, String> keyValues = new ArrayMap<>();
+ if (invocationOnMock.getArguments().length == varargStartIdx) {
+ mKeyValueMap.entrySet().forEach(entry -> {
+ Pair<String, String> nameSpaceAndName = getNameSpaceAndName(entry.getKey());
+ if (!nameSpaceAndName.first.equals(namespace)) {
+ return;
+ }
+ keyValues.put(nameSpaceAndName.second.toLowerCase(), entry.getValue());
+ });
+ } else {
+ for (int i = varargStartIdx; i < invocationOnMock.getArguments().length; ++i) {
+ String name = invocationOnMock.getArgument(i);
+ keyValues.put(name.toLowerCase(), mKeyValueMap.get(getKey(namespace, name)));
+ }
+ }
+ return getProperties(namespace, keyValues);
+ }).when(() -> DeviceConfig.getProperties(anyString(), ArgumentMatchers.<String>any()));
}
/**
@@ -124,15 +148,25 @@ public final class TestableDeviceConfig implements StaticMockFixture {
return namespace + "/" + name;
}
+ private Pair<String, String> getNameSpaceAndName(String key) {
+ final String[] values = key.split("/");
+ return Pair.create(values[0], values[1]);
+ }
+
private Properties getProperties(String namespace, String name, String value) {
+ return getProperties(namespace, Collections.singletonMap(name.toLowerCase(), value));
+ }
+
+ private Properties getProperties(String namespace, Map<String, String> keyValues) {
Properties properties = Mockito.mock(Properties.class);
when(properties.getNamespace()).thenReturn(namespace);
- when(properties.getKeyset()).thenReturn(Collections.singleton(name));
+ when(properties.getKeyset()).thenReturn(keyValues.keySet());
when(properties.getBoolean(anyString(), anyBoolean())).thenAnswer(
invocation -> {
String key = invocation.getArgument(0);
boolean defaultValue = invocation.getArgument(1);
- if (name.equalsIgnoreCase(key) && value != null) {
+ final String value = keyValues.get(key.toLowerCase());
+ if (value != null) {
return Boolean.parseBoolean(value);
} else {
return defaultValue;
@@ -143,7 +177,8 @@ public final class TestableDeviceConfig implements StaticMockFixture {
invocation -> {
String key = invocation.getArgument(0);
float defaultValue = invocation.getArgument(1);
- if (name.equalsIgnoreCase(key) && value != null) {
+ final String value = keyValues.get(key.toLowerCase());
+ if (value != null) {
try {
return Float.parseFloat(value);
} catch (NumberFormatException e) {
@@ -158,7 +193,8 @@ public final class TestableDeviceConfig implements StaticMockFixture {
invocation -> {
String key = invocation.getArgument(0);
int defaultValue = invocation.getArgument(1);
- if (name.equalsIgnoreCase(key) && value != null) {
+ final String value = keyValues.get(key.toLowerCase());
+ if (value != null) {
try {
return Integer.parseInt(value);
} catch (NumberFormatException e) {
@@ -173,7 +209,8 @@ public final class TestableDeviceConfig implements StaticMockFixture {
invocation -> {
String key = invocation.getArgument(0);
long defaultValue = invocation.getArgument(1);
- if (name.equalsIgnoreCase(key) && value != null) {
+ final String value = keyValues.get(key.toLowerCase());
+ if (value != null) {
try {
return Long.parseLong(value);
} catch (NumberFormatException e) {
@@ -184,11 +221,12 @@ public final class TestableDeviceConfig implements StaticMockFixture {
}
}
);
- when(properties.getString(anyString(), anyString())).thenAnswer(
+ when(properties.getString(anyString(), nullable(String.class))).thenAnswer(
invocation -> {
String key = invocation.getArgument(0);
String defaultValue = invocation.getArgument(1);
- if (name.equalsIgnoreCase(key) && value != null) {
+ final String value = keyValues.get(key.toLowerCase());
+ if (value != null) {
return value;
} else {
return defaultValue;
diff --git a/services/tests/mockingservicestests/src/com/android/server/testables/TestableDeviceConfigTest.java b/services/tests/mockingservicestests/src/com/android/server/testables/TestableDeviceConfigTest.java
index d76c9388cacf..0e40669cf870 100644
--- a/services/tests/mockingservicestests/src/com/android/server/testables/TestableDeviceConfigTest.java
+++ b/services/tests/mockingservicestests/src/com/android/server/testables/TestableDeviceConfigTest.java
@@ -23,6 +23,7 @@ import static com.google.common.truth.Truth.assertThat;
import android.app.ActivityThread;
import android.platform.test.annotations.Presubmit;
import android.provider.DeviceConfig;
+import android.provider.DeviceConfig.Properties;
import androidx.test.filters.SmallTest;
import androidx.test.runner.AndroidJUnit4;
@@ -91,6 +92,45 @@ public class TestableDeviceConfigTest {
}
@Test
+ public void getProperties_empty() {
+ String newKey = "key2";
+ String newValue = "value2";
+ DeviceConfig.setProperty(sNamespace, sKey, sValue, false);
+ Properties properties = DeviceConfig.getProperties(sNamespace);
+ assertThat(properties.getString(sKey, null)).isEqualTo(sValue);
+ assertThat(properties.getString(newKey, null)).isNull();
+
+ DeviceConfig.setProperty(sNamespace, newKey, newValue, false);
+ properties = DeviceConfig.getProperties(sNamespace);
+ assertThat(properties.getString(sKey, null)).isEqualTo(sValue);
+ assertThat(properties.getString(newKey, null)).isEqualTo(newValue);
+
+ }
+
+ @Test
+ public void getProperties() {
+ Properties properties = DeviceConfig.getProperties(sNamespace, sKey);
+ assertThat(properties.getString(sKey, null)).isNull();
+
+ DeviceConfig.setProperty(sNamespace, sKey, sValue, false);
+ properties = DeviceConfig.getProperties(sNamespace, sKey);
+ assertThat(properties.getString(sKey, null)).isEqualTo(sValue);
+
+ String newKey = "key2";
+ String newValue = "value2";
+ DeviceConfig.setProperty(sNamespace, newKey, newValue, false);
+ properties = DeviceConfig.getProperties(sNamespace, sKey, newKey);
+ assertThat(properties.getString(sKey, null)).isEqualTo(sValue);
+ assertThat(properties.getString(newKey, null)).isEqualTo(newValue);
+
+ String unsetKey = "key3";
+ properties = DeviceConfig.getProperties(sNamespace, newKey, unsetKey);
+ assertThat(properties.getKeyset()).containsExactly(newKey, unsetKey);
+ assertThat(properties.getString(newKey, null)).isEqualTo(newValue);
+ assertThat(properties.getString(unsetKey, null)).isNull();
+ }
+
+ @Test
public void testListener() throws InterruptedException {
CountDownLatch countDownLatch = new CountDownLatch(1);
diff --git a/services/tests/servicestests/Android.bp b/services/tests/servicestests/Android.bp
index d148c21b7d6e..449e75cd11a0 100644
--- a/services/tests/servicestests/Android.bp
+++ b/services/tests/servicestests/Android.bp
@@ -43,7 +43,6 @@ android_test {
"platformprotosnano",
"hamcrest-library",
"servicestests-utils",
- "service-appsearch",
"service-jobscheduler",
"service-permission",
// TODO: remove once Android migrates to JUnit 4.12,
diff --git a/services/tests/servicestests/src/com/android/server/appsearch/impl/AppSearchImplTest.java b/services/tests/servicestests/src/com/android/server/appsearch/impl/AppSearchImplTest.java
deleted file mode 100644
index 34ade818f062..000000000000
--- a/services/tests/servicestests/src/com/android/server/appsearch/impl/AppSearchImplTest.java
+++ /dev/null
@@ -1,109 +0,0 @@
-/*
- * Copyright (C) 2019 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package com.android.server.appsearch.impl;
-
-import static com.google.common.truth.Truth.assertThat;
-
-import static org.testng.Assert.expectThrows;
-
-import android.annotation.UserIdInt;
-import android.content.Context;
-import android.os.UserHandle;
-
-import androidx.test.InstrumentationRegistry;
-import androidx.test.runner.AndroidJUnit4;
-
-import com.google.android.icing.proto.IndexingConfig;
-import com.google.android.icing.proto.PropertyConfigProto;
-import com.google.android.icing.proto.SchemaProto;
-import com.google.android.icing.proto.SchemaTypeConfigProto;
-import com.google.android.icing.proto.TermMatchType;
-
-import org.junit.Test;
-import org.junit.runner.RunWith;
-
-@RunWith(AndroidJUnit4.class)
-public class AppSearchImplTest {
- private final Context mContext = InstrumentationRegistry.getContext();
- private final @UserIdInt int mUserId = UserHandle.getCallingUserId();
-
- @Test
- public void testRewriteSchemaTypes() {
- SchemaProto inSchema = SchemaProto.newBuilder()
- .addTypes(SchemaTypeConfigProto.newBuilder()
- .setSchemaType("TestType")
- .addProperties(PropertyConfigProto.newBuilder()
- .setPropertyName("subject")
- .setDataType(PropertyConfigProto.DataType.Code.STRING)
- .setCardinality(PropertyConfigProto.Cardinality.Code.OPTIONAL)
- .setIndexingConfig(
- IndexingConfig.newBuilder()
- .setTokenizerType(
- IndexingConfig.TokenizerType.Code.PLAIN)
- .setTermMatchType(TermMatchType.Code.PREFIX)
- .build()
- ).build()
- ).addProperties(PropertyConfigProto.newBuilder()
- .setPropertyName("link")
- .setDataType(PropertyConfigProto.DataType.Code.DOCUMENT)
- .setCardinality(PropertyConfigProto.Cardinality.Code.OPTIONAL)
- .setSchemaType("RefType")
- .build()
- ).build()
- ).build();
-
- SchemaProto expectedSchema = SchemaProto.newBuilder()
- .addTypes(SchemaTypeConfigProto.newBuilder()
- .setSchemaType("com.android.server.appsearch.impl@42:TestType")
- .addProperties(PropertyConfigProto.newBuilder()
- .setPropertyName("subject")
- .setDataType(PropertyConfigProto.DataType.Code.STRING)
- .setCardinality(PropertyConfigProto.Cardinality.Code.OPTIONAL)
- .setIndexingConfig(
- IndexingConfig.newBuilder()
- .setTokenizerType(
- IndexingConfig.TokenizerType.Code.PLAIN)
- .setTermMatchType(TermMatchType.Code.PREFIX)
- .build()
- ).build()
- ).addProperties(PropertyConfigProto.newBuilder()
- .setPropertyName("link")
- .setDataType(PropertyConfigProto.DataType.Code.DOCUMENT)
- .setCardinality(PropertyConfigProto.Cardinality.Code.OPTIONAL)
- .setSchemaType("com.android.server.appsearch.impl@42:RefType")
- .build()
- ).build()
- ).build();
-
- AppSearchImpl impl = new AppSearchImpl(mContext, mUserId);
- SchemaProto.Builder actualSchema = inSchema.toBuilder();
- impl.rewriteSchemaTypes("com.android.server.appsearch.impl@42:", actualSchema);
-
- assertThat(actualSchema.build()).isEqualTo(expectedSchema);
- }
-
- @Test
- public void testPackageNotFound() {
- AppSearchImpl impl = new AppSearchImpl(mContext, mUserId);
- IllegalStateException e = expectThrows(
- IllegalStateException.class,
- () -> impl.setSchema(
- /*callingUid=*/Integer.MAX_VALUE,
- SchemaProto.getDefaultInstance(),
- /*forceOverride=*/false));
- assertThat(e).hasMessageThat().contains("Failed to look up package name");
- }
-}
diff --git a/services/tests/servicestests/src/com/android/server/appsearch/impl/FakeIcingTest.java b/services/tests/servicestests/src/com/android/server/appsearch/impl/FakeIcingTest.java
deleted file mode 100644
index 07b655652fac..000000000000
--- a/services/tests/servicestests/src/com/android/server/appsearch/impl/FakeIcingTest.java
+++ /dev/null
@@ -1,127 +0,0 @@
-/*
- * Copyright (C) 2019 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package com.android.server.appsearch.impl;
-
-import static com.google.common.truth.Truth.assertThat;
-
-import androidx.test.runner.AndroidJUnit4;
-
-import com.google.android.icing.proto.DocumentProto;
-import com.google.android.icing.proto.PropertyProto;
-import com.google.android.icing.proto.SearchResultProto;
-import com.google.android.icing.proto.StatusProto;
-
-import org.junit.Test;
-import org.junit.runner.RunWith;
-
-import java.util.ArrayList;
-import java.util.List;
-
-@RunWith(AndroidJUnit4.class)
-public class FakeIcingTest {
- @Test
- public void query() {
- FakeIcing icing = new FakeIcing();
- icing.put(createDoc("uri:cat", "The cat said meow"));
- icing.put(createDoc("uri:dog", "The dog said woof"));
-
- assertThat(queryGetUris(icing, "meow")).containsExactly("uri:cat");
- assertThat(queryGetUris(icing, "said")).containsExactly("uri:cat", "uri:dog");
- assertThat(queryGetUris(icing, "fred")).isEmpty();
- }
-
- @Test
- public void queryNorm() {
- FakeIcing icing = new FakeIcing();
- icing.put(createDoc("uri:cat", "The cat said meow"));
- icing.put(createDoc("uri:dog", "The dog said woof"));
-
- assertThat(queryGetUris(icing, "the")).containsExactly("uri:cat", "uri:dog");
- assertThat(queryGetUris(icing, "The")).containsExactly("uri:cat", "uri:dog");
- assertThat(queryGetUris(icing, "tHe")).containsExactly("uri:cat", "uri:dog");
- }
-
- @Test
- public void get() {
- DocumentProto cat = createDoc("uri:cat", "The cat said meow");
- FakeIcing icing = new FakeIcing();
- icing.put(cat);
- assertThat(icing.get("uri:cat")).isEqualTo(cat);
- }
-
- @Test
- public void replace() {
- DocumentProto cat = createDoc("uri:cat", "The cat said meow");
- DocumentProto dog = createDoc("uri:dog", "The dog said woof");
-
- FakeIcing icing = new FakeIcing();
- icing.put(cat);
- icing.put(dog);
-
- assertThat(queryGetUris(icing, "meow")).containsExactly("uri:cat");
- assertThat(queryGetUris(icing, "said")).containsExactly("uri:cat", "uri:dog");
- assertThat(icing.get("uri:cat")).isEqualTo(cat);
-
- // Replace
- DocumentProto cat2 = createDoc("uri:cat", "The cat said purr");
- DocumentProto bird = createDoc("uri:bird", "The cat said tweet");
- icing.put(cat2);
- icing.put(bird);
-
- assertThat(queryGetUris(icing, "meow")).isEmpty();
- assertThat(queryGetUris(icing, "said")).containsExactly("uri:cat", "uri:dog", "uri:bird");
- assertThat(icing.get("uri:cat")).isEqualTo(cat2);
- }
-
- @Test
- public void delete() {
- DocumentProto cat = createDoc("uri:cat", "The cat said meow");
- DocumentProto dog = createDoc("uri:dog", "The dog said woof");
-
- FakeIcing icing = new FakeIcing();
- icing.put(cat);
- icing.put(dog);
-
- assertThat(queryGetUris(icing, "meow")).containsExactly("uri:cat");
- assertThat(queryGetUris(icing, "said")).containsExactly("uri:cat", "uri:dog");
- assertThat(icing.get("uri:cat")).isEqualTo(cat);
-
- // Delete
- icing.delete("uri:cat");
- icing.delete("uri:notreal");
-
- assertThat(queryGetUris(icing, "meow")).isEmpty();
- assertThat(queryGetUris(icing, "said")).containsExactly("uri:dog");
- assertThat(icing.get("uri:cat")).isNull();
- }
-
- private static DocumentProto createDoc(String uri, String body) {
- return DocumentProto.newBuilder()
- .setUri(uri)
- .addProperties(PropertyProto.newBuilder().addStringValues(body))
- .build();
- }
-
- private static List<String> queryGetUris(FakeIcing icing, String term) {
- List<String> uris = new ArrayList<>();
- SearchResultProto results = icing.query(term);
- assertThat(results.getStatus().getCode()).isEqualTo(StatusProto.Code.OK);
- for (SearchResultProto.ResultProto result : results.getResultsList()) {
- uris.add(result.getDocument().getUri());
- }
- return uris;
- }
-}
diff --git a/services/tests/servicestests/src/com/android/server/compat/CompatConfigBuilder.java b/services/tests/servicestests/src/com/android/server/compat/CompatConfigBuilder.java
index 328c71dbc7db..2cbe7be8ac33 100644
--- a/services/tests/servicestests/src/com/android/server/compat/CompatConfigBuilder.java
+++ b/services/tests/servicestests/src/com/android/server/compat/CompatConfigBuilder.java
@@ -40,52 +40,57 @@ class CompatConfigBuilder {
}
CompatConfigBuilder addTargetSdkChangeWithId(int sdk, long id) {
- mChanges.add(new CompatChange(id, "", sdk, false, ""));
+ mChanges.add(new CompatChange(id, "", sdk, false, false, ""));
return this;
}
CompatConfigBuilder addTargetSdkDisabledChangeWithId(int sdk, long id) {
- mChanges.add(new CompatChange(id, "", sdk, true, ""));
+ mChanges.add(new CompatChange(id, "", sdk, true, false, ""));
return this;
}
CompatConfigBuilder addTargetSdkChangeWithIdAndName(int sdk, long id, String name) {
- mChanges.add(new CompatChange(id, name, sdk, false, ""));
+ mChanges.add(new CompatChange(id, name, sdk, false, false, ""));
return this;
}
CompatConfigBuilder addTargetSdkChangeWithIdAndDescription(int sdk, long id,
String description) {
- mChanges.add(new CompatChange(id, "", sdk, false, description));
+ mChanges.add(new CompatChange(id, "", sdk, false, false, description));
return this;
}
CompatConfigBuilder addEnabledChangeWithId(long id) {
- mChanges.add(new CompatChange(id, "", -1, false, ""));
+ mChanges.add(new CompatChange(id, "", -1, false, false, ""));
return this;
}
CompatConfigBuilder addEnabledChangeWithIdAndName(long id, String name) {
- mChanges.add(new CompatChange(id, name, -1, false, ""));
+ mChanges.add(new CompatChange(id, name, -1, false, false, ""));
return this;
}
CompatConfigBuilder addEnabledChangeWithIdAndDescription(long id, String description) {
- mChanges.add(new CompatChange(id, "", -1, false, description));
+ mChanges.add(new CompatChange(id, "", -1, false, false, description));
return this;
}
CompatConfigBuilder addDisabledChangeWithId(long id) {
- mChanges.add(new CompatChange(id, "", -1, true, ""));
+ mChanges.add(new CompatChange(id, "", -1, true, false, ""));
return this;
}
CompatConfigBuilder addDisabledChangeWithIdAndName(long id, String name) {
- mChanges.add(new CompatChange(id, name, -1, true, ""));
+ mChanges.add(new CompatChange(id, name, -1, true, false, ""));
return this;
}
CompatConfigBuilder addDisabledChangeWithIdAndDescription(long id, String description) {
- mChanges.add(new CompatChange(id, "", -1, true, description));
+ mChanges.add(new CompatChange(id, "", -1, true, false, description));
+ return this;
+ }
+
+ CompatConfigBuilder addLoggingOnlyChangeWithId(long id) {
+ mChanges.add(new CompatChange(id, "", -1, false, true, ""));
return this;
}
diff --git a/services/tests/servicestests/src/com/android/server/compat/CompatConfigTest.java b/services/tests/servicestests/src/com/android/server/compat/CompatConfigTest.java
index 44f4ccf69cdd..eb2dd6461071 100644
--- a/services/tests/servicestests/src/com/android/server/compat/CompatConfigTest.java
+++ b/services/tests/servicestests/src/com/android/server/compat/CompatConfigTest.java
@@ -214,6 +214,17 @@ public class CompatConfigTest {
}
@Test
+ public void testLoggingOnlyChangePreventAddOverride() throws Exception {
+ CompatConfig compatConfig = CompatConfigBuilder.create(mBuildClassifier, mContext)
+ .addLoggingOnlyChangeWithId(1234L)
+ .build();
+
+ assertThrows(SecurityException.class,
+ () -> compatConfig.addOverride(1234L, "com.some.package", true)
+ );
+ }
+
+ @Test
public void testPreventRemoveOverride() throws Exception {
CompatConfig compatConfig = CompatConfigBuilder.create(mBuildClassifier, mContext)
.addDisabledChangeWithId(1234L)
diff --git a/services/tests/servicestests/src/com/android/server/compat/OverrideValidatorImplTest.java b/services/tests/servicestests/src/com/android/server/compat/OverrideValidatorImplTest.java
index b14291b34195..425c7247e50f 100644
--- a/services/tests/servicestests/src/com/android/server/compat/OverrideValidatorImplTest.java
+++ b/services/tests/servicestests/src/com/android/server/compat/OverrideValidatorImplTest.java
@@ -20,6 +20,7 @@ import static com.android.internal.compat.OverrideAllowedState.ALLOWED;
import static com.android.internal.compat.OverrideAllowedState.DISABLED_NON_TARGET_SDK;
import static com.android.internal.compat.OverrideAllowedState.DISABLED_NOT_DEBUGGABLE;
import static com.android.internal.compat.OverrideAllowedState.DISABLED_TARGET_SDK_TOO_HIGH;
+import static com.android.internal.compat.OverrideAllowedState.LOGGING_ONLY_CHANGE;
import static com.google.common.truth.Truth.assertThat;
@@ -78,6 +79,7 @@ public class OverrideValidatorImplTest {
@Before
public void setUp() throws Exception {
MockitoAnnotations.initMocks(this);
+ android.app.compat.ChangeIdStateCache.disable();
when(mContext.getPackageManager()).thenReturn(mPackageManager);
}
@@ -89,7 +91,8 @@ public class OverrideValidatorImplTest {
.addTargetSdkChangeWithId(TARGET_SDK, 2)
.addTargetSdkChangeWithId(TARGET_SDK_AFTER, 3)
.addEnabledChangeWithId(4)
- .addDisabledChangeWithId(5).build();
+ .addDisabledChangeWithId(5)
+ .addLoggingOnlyChangeWithId(6).build();
IOverrideValidator overrideValidator = config.getOverrideValidator();
when(mPackageManager.getApplicationInfo(eq(PACKAGE_NAME), anyInt()))
.thenReturn(ApplicationInfoBuilder.create()
@@ -107,6 +110,8 @@ public class OverrideValidatorImplTest {
overrideValidator.getOverrideAllowedState(4, PACKAGE_NAME);
OverrideAllowedState stateDisabledChange =
overrideValidator.getOverrideAllowedState(5, PACKAGE_NAME);
+ OverrideAllowedState stateDLoggingOnlyChange =
+ overrideValidator.getOverrideAllowedState(6, PACKAGE_NAME);
assertThat(stateTargetSdkLessChange)
.isEqualTo(new OverrideAllowedState(ALLOWED, -1, -1));
@@ -118,6 +123,8 @@ public class OverrideValidatorImplTest {
.isEqualTo(new OverrideAllowedState(ALLOWED, -1, -1));
assertThat(stateDisabledChange)
.isEqualTo(new OverrideAllowedState(ALLOWED, -1, -1));
+ assertThat(stateDLoggingOnlyChange)
+ .isEqualTo(new OverrideAllowedState(LOGGING_ONLY_CHANGE, -1, -1));
}
@Test
@@ -128,7 +135,8 @@ public class OverrideValidatorImplTest {
.addTargetSdkChangeWithId(TARGET_SDK, 2)
.addTargetSdkChangeWithId(TARGET_SDK_AFTER, 3)
.addEnabledChangeWithId(4)
- .addDisabledChangeWithId(5).build();
+ .addDisabledChangeWithId(5)
+ .addLoggingOnlyChangeWithId(6).build();
IOverrideValidator overrideValidator = config.getOverrideValidator();
when(mPackageManager.getApplicationInfo(eq(PACKAGE_NAME), anyInt()))
.thenReturn(ApplicationInfoBuilder.create()
@@ -145,6 +153,8 @@ public class OverrideValidatorImplTest {
overrideValidator.getOverrideAllowedState(4, PACKAGE_NAME);
OverrideAllowedState stateDisabledChange =
overrideValidator.getOverrideAllowedState(5, PACKAGE_NAME);
+ OverrideAllowedState stateDLoggingOnlyChange =
+ overrideValidator.getOverrideAllowedState(6, PACKAGE_NAME);
assertThat(stateTargetSdkLessChange)
.isEqualTo(new OverrideAllowedState(ALLOWED, -1, -1));
@@ -156,6 +166,8 @@ public class OverrideValidatorImplTest {
.isEqualTo(new OverrideAllowedState(ALLOWED, -1, -1));
assertThat(stateDisabledChange)
.isEqualTo(new OverrideAllowedState(ALLOWED, -1, -1));
+ assertThat(stateDLoggingOnlyChange)
+ .isEqualTo(new OverrideAllowedState(LOGGING_ONLY_CHANGE, -1, -1));
}
@Test
@@ -164,7 +176,8 @@ public class OverrideValidatorImplTest {
CompatConfig config = CompatConfigBuilder.create(betaBuild(), mContext)
.addTargetSdkChangeWithId(TARGET_SDK_BEFORE, 1)
.addTargetSdkChangeWithId(TARGET_SDK, 2)
- .addTargetSdkChangeWithId(TARGET_SDK_AFTER, 3).build();
+ .addTargetSdkChangeWithId(TARGET_SDK_AFTER, 3)
+ .addDisabledChangeWithId(4).build();
IOverrideValidator overrideValidator = config.getOverrideValidator();
when(mPackageManager.getApplicationInfo(eq(PACKAGE_NAME), anyInt()))
.thenReturn(ApplicationInfoBuilder.create()
@@ -178,6 +191,8 @@ public class OverrideValidatorImplTest {
overrideValidator.getOverrideAllowedState(2, PACKAGE_NAME);
OverrideAllowedState stateTargetSdkAfterChange =
overrideValidator.getOverrideAllowedState(3, PACKAGE_NAME);
+ OverrideAllowedState stateDisabledChange =
+ overrideValidator.getOverrideAllowedState(4, PACKAGE_NAME);
assertThat(stateTargetSdkLessChange)
.isEqualTo(new OverrideAllowedState(ALLOWED, TARGET_SDK, TARGET_SDK_BEFORE));
@@ -185,6 +200,8 @@ public class OverrideValidatorImplTest {
.isEqualTo(new OverrideAllowedState(ALLOWED, TARGET_SDK, TARGET_SDK));
assertThat(stateTargetSdkAfterChange)
.isEqualTo(new OverrideAllowedState(ALLOWED, TARGET_SDK, TARGET_SDK_AFTER));
+ assertThat(stateDisabledChange)
+ .isEqualTo(new OverrideAllowedState(ALLOWED, TARGET_SDK, -1));
}
@Test
@@ -232,7 +249,8 @@ public class OverrideValidatorImplTest {
.addTargetSdkChangeWithId(TARGET_SDK, 2)
.addTargetSdkChangeWithId(TARGET_SDK_AFTER, 3)
.addEnabledChangeWithId(4)
- .addDisabledChangeWithId(5).build();
+ .addDisabledChangeWithId(5)
+ .addLoggingOnlyChangeWithId(6).build();
IOverrideValidator overrideValidator = config.getOverrideValidator();
when(mPackageManager.getApplicationInfo(eq(PACKAGE_NAME), anyInt()))
.thenReturn(ApplicationInfoBuilder.create()
@@ -249,6 +267,8 @@ public class OverrideValidatorImplTest {
overrideValidator.getOverrideAllowedState(4, PACKAGE_NAME);
OverrideAllowedState stateDisabledChange =
overrideValidator.getOverrideAllowedState(5, PACKAGE_NAME);
+ OverrideAllowedState stateDLoggingOnlyChange =
+ overrideValidator.getOverrideAllowedState(6, PACKAGE_NAME);
assertThat(stateTargetSdkLessChange)
.isEqualTo(new OverrideAllowedState(DISABLED_NOT_DEBUGGABLE, -1, -1));
@@ -260,6 +280,8 @@ public class OverrideValidatorImplTest {
.isEqualTo(new OverrideAllowedState(DISABLED_NOT_DEBUGGABLE, -1, -1));
assertThat(stateDisabledChange)
.isEqualTo(new OverrideAllowedState(DISABLED_NOT_DEBUGGABLE, -1, -1));
+ assertThat(stateDLoggingOnlyChange)
+ .isEqualTo(new OverrideAllowedState(LOGGING_ONLY_CHANGE, -1, -1));
}
@Test
@@ -326,21 +348,22 @@ public class OverrideValidatorImplTest {
}
@Test
- public void getOverrideAllowedState_finalBuildDisabledChangeDebugApp_rejectOverride()
+ public void getOverrideAllowedState_finalBuildDisabledChangeDebugApp_allowOverride()
throws Exception {
CompatConfig config = CompatConfigBuilder.create(finalBuild(), mContext)
- .addDisabledChangeWithId(1).build();
+ .addDisabledChangeWithId(1).build();
IOverrideValidator overrideValidator = config.getOverrideValidator();
when(mPackageManager.getApplicationInfo(eq(PACKAGE_NAME), anyInt()))
.thenReturn(ApplicationInfoBuilder.create()
.withPackageName(PACKAGE_NAME)
+ .withTargetSdk(TARGET_SDK)
.debuggable().build());
OverrideAllowedState allowedState =
overrideValidator.getOverrideAllowedState(1, PACKAGE_NAME);
assertThat(allowedState)
- .isEqualTo(new OverrideAllowedState(DISABLED_NON_TARGET_SDK, -1, -1));
+ .isEqualTo(new OverrideAllowedState(ALLOWED, TARGET_SDK, -1));
}
@Test
@@ -351,7 +374,8 @@ public class OverrideValidatorImplTest {
.addTargetSdkChangeWithId(TARGET_SDK, 2)
.addTargetSdkChangeWithId(TARGET_SDK_AFTER, 3)
.addEnabledChangeWithId(4)
- .addDisabledChangeWithId(5).build();
+ .addDisabledChangeWithId(5)
+ .addLoggingOnlyChangeWithId(6).build();
IOverrideValidator overrideValidator = config.getOverrideValidator();
when(mPackageManager.getApplicationInfo(eq(PACKAGE_NAME), anyInt()))
.thenReturn(ApplicationInfoBuilder.create()
@@ -368,6 +392,8 @@ public class OverrideValidatorImplTest {
overrideValidator.getOverrideAllowedState(4, PACKAGE_NAME);
OverrideAllowedState stateDisabledChange =
overrideValidator.getOverrideAllowedState(5, PACKAGE_NAME);
+ OverrideAllowedState stateDLoggingOnlyChange =
+ overrideValidator.getOverrideAllowedState(6, PACKAGE_NAME);
assertThat(stateTargetSdkLessChange)
.isEqualTo(new OverrideAllowedState(DISABLED_NOT_DEBUGGABLE, -1, -1));
@@ -379,5 +405,7 @@ public class OverrideValidatorImplTest {
.isEqualTo(new OverrideAllowedState(DISABLED_NOT_DEBUGGABLE, -1, -1));
assertThat(stateDisabledChange)
.isEqualTo(new OverrideAllowedState(DISABLED_NOT_DEBUGGABLE, -1, -1));
+ assertThat(stateDLoggingOnlyChange)
+ .isEqualTo(new OverrideAllowedState(LOGGING_ONLY_CHANGE, -1, -1));
}
}
diff --git a/services/tests/servicestests/src/com/android/server/content/ObserverNodeTest.java b/services/tests/servicestests/src/com/android/server/content/ObserverNodeTest.java
index 891ca74a545f..0e4d2be49b0e 100644
--- a/services/tests/servicestests/src/com/android/server/content/ObserverNodeTest.java
+++ b/services/tests/servicestests/src/com/android/server/content/ObserverNodeTest.java
@@ -16,30 +16,52 @@
package com.android.server.content;
-import java.util.ArrayList;
-
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.anyBoolean;
+import static org.mockito.ArgumentMatchers.anyInt;
+import static org.mockito.ArgumentMatchers.argThat;
+import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+import android.app.ActivityManager;
+import android.app.ActivityManagerInternal;
+import android.content.ContentResolver;
import android.database.ContentObserver;
+import android.database.IContentObserver;
import android.net.Uri;
+import android.os.Binder;
import android.os.Handler;
import android.os.Looper;
import android.os.UserHandle;
-import android.test.AndroidTestCase;
-import android.test.suitebuilder.annotation.SmallTest;
+import android.util.ArraySet;
+
+import androidx.test.runner.AndroidJUnit4;
-import com.android.server.content.ContentService.ObserverCall;
+import com.android.server.LocalServices;
+import com.android.server.content.ContentService.ObserverCollector;
import com.android.server.content.ContentService.ObserverNode;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.ArgumentMatcher;
+
+import java.util.Arrays;
+
/**
* atest FrameworksServicesTests:com.android.server.content.ObserverNodeTest
*/
-@SmallTest
-public class ObserverNodeTest extends AndroidTestCase {
- static class TestObserver extends ContentObserver {
+@RunWith(AndroidJUnit4.class)
+public class ObserverNodeTest {
+ static class TestObserver extends ContentObserver {
public TestObserver() {
super(new Handler(Looper.getMainLooper()));
}
}
+ @Test
public void testUri() {
final int myUserHandle = UserHandle.myUserId();
@@ -65,15 +87,15 @@ public class ObserverNodeTest extends AndroidTestCase {
0, 0, myUserHandle);
}
- ArrayList<ObserverCall> calls = new ArrayList<ObserverCall>();
-
for (int i = nums.length - 1; i >=0; --i) {
- root.collectObserversLocked(uris[i], 0, null, false, 0, myUserHandle, calls);
- assertEquals(nums[i], calls.size());
- calls.clear();
+ final ObserverCollector collector = mock(ObserverCollector.class);
+ root.collectObserversLocked(uris[i], 0, null, false, 0, myUserHandle, collector);
+ verify(collector, times(nums[i])).collect(
+ any(), anyInt(), anyBoolean(), any(), anyInt(), anyInt());
}
}
+ @Test
public void testUriNotNotify() {
final int myUserHandle = UserHandle.myUserId();
@@ -95,12 +117,67 @@ public class ObserverNodeTest extends AndroidTestCase {
0, 0, myUserHandle);
}
- ArrayList<ObserverCall> calls = new ArrayList<ObserverCall>();
-
for (int i = uris.length - 1; i >=0; --i) {
- root.collectObserversLocked(uris[i], 0, null, false, 0, myUserHandle, calls);
- assertEquals(nums[i], calls.size());
- calls.clear();
+ final ObserverCollector collector = mock(ObserverCollector.class);
+ root.collectObserversLocked(uris[i], 0, null, false, 0, myUserHandle, collector);
+ verify(collector, times(nums[i])).collect(
+ any(), anyInt(), anyBoolean(), any(), anyInt(), anyInt());
+ }
+ }
+
+ @Test
+ public void testCluster() throws Exception {
+ final int myUserHandle = UserHandle.myUserId();
+
+ // Assume everything is foreground during our test
+ final ActivityManagerInternal ami = mock(ActivityManagerInternal.class);
+ when(ami.getUidProcessState(anyInt()))
+ .thenReturn(ActivityManager.PROCESS_STATE_IMPORTANT_FOREGROUND);
+ LocalServices.removeServiceForTest(ActivityManagerInternal.class);
+ LocalServices.addService(ActivityManagerInternal.class, ami);
+
+ final IContentObserver observer = mock(IContentObserver.class);
+ when(observer.asBinder()).thenReturn(new Binder());
+
+ final ObserverNode root = new ObserverNode("");
+ root.addObserverLocked(Uri.parse("content://authority/"), observer,
+ true, root, 0, 1000, myUserHandle);
+
+ final ObserverCollector collector = new ObserverCollector();
+ root.collectObserversLocked(Uri.parse("content://authority/1"), 0, null, false,
+ 0, myUserHandle, collector);
+ root.collectObserversLocked(Uri.parse("content://authority/1"), 0, null, false,
+ ContentResolver.NOTIFY_INSERT, myUserHandle, collector);
+ root.collectObserversLocked(Uri.parse("content://authority/2"), 0, null, false,
+ ContentResolver.NOTIFY_INSERT, myUserHandle, collector);
+ root.collectObserversLocked(Uri.parse("content://authority/2"), 0, null, false,
+ ContentResolver.NOTIFY_UPDATE, myUserHandle, collector);
+ collector.dispatch();
+
+ // We should only cluster when all other arguments are equal
+ verify(observer).onChangeEtc(eq(false), argThat(new UriSetMatcher(
+ Uri.parse("content://authority/1"))),
+ eq(0), anyInt());
+ verify(observer).onChangeEtc(eq(false), argThat(new UriSetMatcher(
+ Uri.parse("content://authority/1"),
+ Uri.parse("content://authority/2"))),
+ eq(ContentResolver.NOTIFY_INSERT), anyInt());
+ verify(observer).onChangeEtc(eq(false), argThat(new UriSetMatcher(
+ Uri.parse("content://authority/2"))),
+ eq(ContentResolver.NOTIFY_UPDATE), anyInt());
+ }
+
+ private static class UriSetMatcher implements ArgumentMatcher<Uri[]> {
+ private final ArraySet<Uri> uris;
+
+ public UriSetMatcher(Uri... uris) {
+ this.uris = new ArraySet<>(Arrays.asList(uris));
+ }
+
+ @Override
+ public boolean matches(Uri[] uris) {
+ final ArraySet<Uri> test = new ArraySet<>(Arrays.asList(uris));
+ return this.uris.equals(test);
}
}
}
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 5ad81b2c4506..c1bcf1fb75a6 100644
--- a/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerServiceTestable.java
+++ b/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerServiceTestable.java
@@ -22,8 +22,6 @@ import android.app.IActivityTaskManager;
import android.app.NotificationManager;
import android.app.PendingIntent;
import android.app.backup.IBackupManager;
-import android.app.timedetector.TimeDetector;
-import android.app.timezonedetector.TimeZoneDetector;
import android.app.usage.UsageStatsManagerInternal;
import android.content.Context;
import android.content.Intent;
@@ -236,16 +234,6 @@ public class DevicePolicyManagerServiceTestable extends DevicePolicyManagerServi
AlarmManager getAlarmManager() {return services.alarmManager;}
@Override
- TimeDetector getTimeDetector() {
- return services.timeDetector;
- }
-
- @Override
- TimeZoneDetector getTimeZoneDetector() {
- return services.timeZoneDetector;
- }
-
- @Override
LockPatternUtils newLockPatternUtils() {
return services.lockPatternUtils;
}
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 ac818ea8385f..2a6a24eab3d9 100644
--- a/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java
+++ b/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java
@@ -67,9 +67,6 @@ import android.app.admin.DevicePolicyManager;
import android.app.admin.DevicePolicyManagerInternal;
import android.app.admin.FactoryResetProtectionPolicy;
import android.app.admin.PasswordMetrics;
-import android.app.timedetector.ManualTimeSuggestion;
-import android.app.timezonedetector.ManualTimeZoneSuggestion;
-import android.app.timezonedetector.TimeZoneDetector;
import android.content.BroadcastReceiver;
import android.content.ComponentName;
import android.content.Intent;
@@ -3969,19 +3966,7 @@ public class DevicePolicyManagerTest extends DpmTestBase {
mContext.binder.callingUid = DpmMockContext.CALLER_SYSTEM_USER_UID;
setupDeviceOwner();
dpm.setTime(admin1, 0);
-
- BaseMatcher<ManualTimeSuggestion> hasZeroTime = new BaseMatcher<ManualTimeSuggestion>() {
- @Override
- public boolean matches(Object item) {
- final ManualTimeSuggestion suggestion = (ManualTimeSuggestion) item;
- return suggestion.getUtcTime().getValue() == 0;
- }
- @Override
- public void describeTo(Description description) {
- description.appendText("ManualTimeSuggestion{utcTime.value=0}");
- }
- };
- verify(getServices().timeDetector).suggestManualTime(argThat(hasZeroTime));
+ verify(getServices().alarmManager).setTime(0);
}
public void testSetTimeFailWithPO() throws Exception {
@@ -3993,19 +3978,7 @@ public class DevicePolicyManagerTest extends DpmTestBase {
setupProfileOwner();
configureProfileOwnerOfOrgOwnedDevice(admin1, DpmMockContext.CALLER_USER_HANDLE);
dpm.setTime(admin1, 0);
-
- BaseMatcher<ManualTimeSuggestion> hasZeroTime = new BaseMatcher<ManualTimeSuggestion>() {
- @Override
- public boolean matches(Object item) {
- final ManualTimeSuggestion suggestion = (ManualTimeSuggestion) item;
- return suggestion.getUtcTime().getValue() == 0;
- }
- @Override
- public void describeTo(Description description) {
- description.appendText("ManualTimeSuggestion{utcTime.value=0}");
- }
- };
- verify(getServices().timeDetector).suggestManualTime(argThat(hasZeroTime));
+ verify(getServices().alarmManager).setTime(0);
}
public void testSetTimeWithAutoTimeOn() throws Exception {
@@ -4020,9 +3993,7 @@ public class DevicePolicyManagerTest extends DpmTestBase {
mContext.binder.callingUid = DpmMockContext.CALLER_SYSTEM_USER_UID;
setupDeviceOwner();
dpm.setTimeZone(admin1, "Asia/Shanghai");
- ManualTimeZoneSuggestion suggestion =
- TimeZoneDetector.createManualTimeZoneSuggestion("Asia/Shanghai", "Test debug info");
- verify(getServices().timeZoneDetector).suggestManualTimeZone(suggestion);
+ verify(getServices().alarmManager).setTimeZone("Asia/Shanghai");
}
public void testSetTimeZoneFailWithPO() throws Exception {
@@ -4035,9 +4006,7 @@ public class DevicePolicyManagerTest extends DpmTestBase {
setupProfileOwner();
configureProfileOwnerOfOrgOwnedDevice(admin1, DpmMockContext.CALLER_USER_HANDLE);
dpm.setTimeZone(admin1, "Asia/Shanghai");
- ManualTimeZoneSuggestion suggestion =
- TimeZoneDetector.createManualTimeZoneSuggestion("Asia/Shanghai", "Test debug info");
- verify(getServices().timeZoneDetector).suggestManualTimeZone(suggestion);
+ verify(getServices().alarmManager).setTimeZone("Asia/Shanghai");
}
public void testSetTimeZoneWithAutoTimeZoneOn() throws Exception {
diff --git a/services/tests/servicestests/src/com/android/server/devicepolicy/DpmMockContext.java b/services/tests/servicestests/src/com/android/server/devicepolicy/DpmMockContext.java
index 12228c19ca00..8625a1ed9fda 100644
--- a/services/tests/servicestests/src/com/android/server/devicepolicy/DpmMockContext.java
+++ b/services/tests/servicestests/src/com/android/server/devicepolicy/DpmMockContext.java
@@ -207,8 +207,6 @@ public class DpmMockContext extends MockContext {
switch (name) {
case Context.ALARM_SERVICE:
return mMockSystemServices.alarmManager;
- case Context.TIME_DETECTOR_SERVICE:
- return mMockSystemServices.timeDetector;
case Context.USER_SERVICE:
return mMockSystemServices.userManager;
case Context.POWER_SERVICE:
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 01f1a3e92f2c..bbd4472f7d56 100644
--- a/services/tests/servicestests/src/com/android/server/devicepolicy/MockSystemServices.java
+++ b/services/tests/servicestests/src/com/android/server/devicepolicy/MockSystemServices.java
@@ -33,8 +33,6 @@ import android.app.IActivityManager;
import android.app.IActivityTaskManager;
import android.app.NotificationManager;
import android.app.backup.IBackupManager;
-import android.app.timedetector.TimeDetector;
-import android.app.timezonedetector.TimeZoneDetector;
import android.app.usage.UsageStatsManagerInternal;
import android.content.BroadcastReceiver;
import android.content.ComponentName;
@@ -118,8 +116,6 @@ public class MockSystemServices {
public final TelephonyManager telephonyManager;
public final AccountManager accountManager;
public final AlarmManager alarmManager;
- public final TimeDetector timeDetector;
- public final TimeZoneDetector timeZoneDetector;
public final KeyChain.KeyChainConnection keyChainConnection;
public final CrossProfileApps crossProfileApps;
public final PersistentDataBlockManagerInternal persistentDataBlockManagerInternal;
@@ -164,8 +160,6 @@ public class MockSystemServices {
telephonyManager = mock(TelephonyManager.class);
accountManager = mock(AccountManager.class);
alarmManager = mock(AlarmManager.class);
- timeDetector = mock(TimeDetector.class);
- timeZoneDetector = mock(TimeZoneDetector.class);
keyChainConnection = mock(KeyChain.KeyChainConnection.class, RETURNS_DEEP_STUBS);
crossProfileApps = mock(CrossProfileApps.class);
persistentDataBlockManagerInternal = mock(PersistentDataBlockManagerInternal.class);
diff --git a/services/tests/servicestests/src/com/android/server/integrity/AppIntegrityManagerServiceImplTest.java b/services/tests/servicestests/src/com/android/server/integrity/AppIntegrityManagerServiceImplTest.java
index e2b63e2bb9b7..3dd150479ddc 100644
--- a/services/tests/servicestests/src/com/android/server/integrity/AppIntegrityManagerServiceImplTest.java
+++ b/services/tests/servicestests/src/com/android/server/integrity/AppIntegrityManagerServiceImplTest.java
@@ -62,7 +62,6 @@ import android.net.Uri;
import android.os.Handler;
import android.os.Message;
import android.provider.Settings;
-import android.security.FileIntegrityManager;
import androidx.test.InstrumentationRegistry;
@@ -136,7 +135,6 @@ public class AppIntegrityManagerServiceImplTest {
@Mock RuleEvaluationEngine mRuleEvaluationEngine;
@Mock IntegrityFileManager mIntegrityFileManager;
@Mock Handler mHandler;
- FileIntegrityManager mFileIntegrityManager;
private final Context mRealContext = InstrumentationRegistry.getTargetContext();
@@ -165,16 +163,12 @@ public class AppIntegrityManagerServiceImplTest {
Files.copy(inputStream, mTestApkSourceStamp.toPath(), REPLACE_EXISTING);
}
- mFileIntegrityManager =
- (FileIntegrityManager)
- mRealContext.getSystemService(Context.FILE_INTEGRITY_SERVICE);
mService =
new AppIntegrityManagerServiceImpl(
mMockContext,
mPackageManagerInternal,
mRuleEvaluationEngine,
mIntegrityFileManager,
- mFileIntegrityManager,
mHandler);
mSpyPackageManager = spy(mRealContext.getPackageManager());
@@ -379,7 +373,7 @@ public class AppIntegrityManagerServiceImplTest {
AppInstallMetadata appInstallMetadata = metadataCaptor.getValue();
assertTrue(appInstallMetadata.isStampPresent());
assertTrue(appInstallMetadata.isStampVerified());
- assertFalse(appInstallMetadata.isStampTrusted());
+ assertTrue(appInstallMetadata.isStampTrusted());
assertEquals(SOURCE_STAMP_CERTIFICATE_HASH, appInstallMetadata.getStampCertificateHash());
}
diff --git a/services/tests/servicestests/src/com/android/server/locksettings/LockSettingsServiceTests.java b/services/tests/servicestests/src/com/android/server/locksettings/LockSettingsServiceTests.java
index 2e77c9fd694e..684bbd4fc8eb 100644
--- a/services/tests/servicestests/src/com/android/server/locksettings/LockSettingsServiceTests.java
+++ b/services/tests/servicestests/src/com/android/server/locksettings/LockSettingsServiceTests.java
@@ -236,6 +236,7 @@ public class LockSettingsServiceTests extends BaseLockSettingsServiceTests {
@Test
public void testSetLockCredential_forProfileWithSeparateChallenge_updatesCredentials()
throws Exception {
+ mService.setSeparateProfileChallengeEnabled(MANAGED_PROFILE_USER_ID, true, null);
initializeStorageWithCredential(
MANAGED_PROFILE_USER_ID,
newPattern("12345"),
diff --git a/services/tests/servicestests/src/com/android/server/people/data/DataManagerTest.java b/services/tests/servicestests/src/com/android/server/people/data/DataManagerTest.java
index 624b67ccda85..a4d63ac8a564 100644
--- a/services/tests/servicestests/src/com/android/server/people/data/DataManagerTest.java
+++ b/services/tests/servicestests/src/com/android/server/people/data/DataManagerTest.java
@@ -269,7 +269,7 @@ public final class DataManagerTest {
assertEquals(1, conversations.size());
assertEquals("sc_1", conversations.get(0).getShortcutId());
- mDataManager.onUserStopped(USER_ID_PRIMARY);
+ mDataManager.onUserStopping(USER_ID_PRIMARY);
conversations = getConversationsInPrimary();
assertTrue(conversations.isEmpty());
}
diff --git a/services/tests/servicestests/src/com/android/server/tv/TvRemoteProviderWatcherTest.java b/services/tests/servicestests/src/com/android/server/tv/TvRemoteProviderWatcherTest.java
new file mode 100644
index 000000000000..0a2bb620eb11
--- /dev/null
+++ b/services/tests/servicestests/src/com/android/server/tv/TvRemoteProviderWatcherTest.java
@@ -0,0 +1,146 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.server.tv;
+
+import static org.hamcrest.Matchers.not;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+import static org.mockito.ArgumentMatchers.anyInt;
+import static org.mockito.ArgumentMatchers.anyString;
+import static org.mockito.Mockito.reset;
+import static org.mockito.Mockito.when;
+import static org.mockito.hamcrest.MockitoHamcrest.argThat;
+
+import android.Manifest;
+import android.content.Context;
+import android.content.pm.PackageManager;
+import android.content.pm.ServiceInfo;
+import android.content.res.Resources;
+import android.os.Looper;
+
+import androidx.test.filters.SmallTest;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+
+@SmallTest
+public class TvRemoteProviderWatcherTest {
+ private static final String TV_REMOTE_SERVICE_PACKAGE_NAME =
+ "com.google.android.tv.remote.service";
+
+ @Mock
+ Context mMockContext;
+ @Mock
+ PackageManager mMockPackageManager;
+ @Mock
+ Resources mMockResources;
+
+ private TvRemoteProviderWatcher mTvRemoteProviderWatcher;
+
+ @Before
+ public void setUp() throws Exception {
+ MockitoAnnotations.initMocks(this);
+
+ if (Looper.myLooper() == null) {
+ Looper.prepare();
+ }
+
+ when(mMockContext.getPackageManager()).thenReturn(mMockPackageManager);
+ when(mMockContext.getResources()).thenReturn(mMockResources);
+
+ when(mMockResources.getString(com.android.internal.R.string.config_tvRemoteServicePackage))
+ .thenReturn(TV_REMOTE_SERVICE_PACKAGE_NAME);
+
+
+ when(mMockPackageManager.checkPermission(
+ argThat(not(Manifest.permission.TV_VIRTUAL_REMOTE_CONTROLLER)),
+ anyString())).thenReturn(
+ PackageManager.PERMISSION_DENIED);
+
+ when(mMockPackageManager.checkPermission(
+ anyString(),
+ argThat(not(TV_REMOTE_SERVICE_PACKAGE_NAME)))).thenReturn(
+ PackageManager.PERMISSION_DENIED);
+
+ when(mMockPackageManager.checkPermission(Manifest.permission.TV_VIRTUAL_REMOTE_CONTROLLER,
+ TV_REMOTE_SERVICE_PACKAGE_NAME)).thenReturn(PackageManager.PERMISSION_GRANTED);
+
+ mTvRemoteProviderWatcher = new TvRemoteProviderWatcher(mMockContext, new Object());
+ }
+
+ @Test
+ public void tvServiceIsTrusted() {
+ assertTrue(mTvRemoteProviderWatcher.verifyServiceTrusted(createTvServiceInfo()));
+ }
+
+ @Test
+ public void permissionIsRequired() {
+ ServiceInfo serviceInfo = createTvServiceInfo();
+ serviceInfo.permission = null;
+
+ assertFalse(mTvRemoteProviderWatcher.verifyServiceTrusted(serviceInfo));
+ }
+
+ @Test
+ public void permissionMustBeBindRemote() {
+ ServiceInfo serviceInfo = createTvServiceInfo();
+ serviceInfo.permission = Manifest.permission.BIND_TV_INPUT;
+ assertFalse(mTvRemoteProviderWatcher.verifyServiceTrusted(serviceInfo));
+ }
+
+ @Test
+ public void packageNameMustMatch() {
+ ServiceInfo serviceInfo = createTvServiceInfo();
+ serviceInfo.packageName = "some.random.package";
+ assertFalse(mTvRemoteProviderWatcher.verifyServiceTrusted(serviceInfo));
+ }
+
+ @Test
+ public void packageManagerPermissionIsRequired() {
+ reset(mMockPackageManager);
+ when(mMockPackageManager.checkPermission(anyString(), anyString())).thenReturn(
+ PackageManager.PERMISSION_DENIED);
+
+ assertFalse(mTvRemoteProviderWatcher.verifyServiceTrusted(createTvServiceInfo()));
+ }
+
+ @Test
+ public void whitelistingPackageNameIsRequired() {
+ reset(mMockResources);
+ when(mMockResources.getString(anyInt())).thenReturn("");
+
+ // Create a new watcher, as the resources are read in the constructor of the class
+ if (Looper.myLooper() == null) {
+ Looper.prepare();
+ }
+
+ TvRemoteProviderWatcher watcher =
+ new TvRemoteProviderWatcher(mMockContext, new Object());
+ assertFalse(watcher.verifyServiceTrusted(createTvServiceInfo()));
+ }
+
+ private ServiceInfo createTvServiceInfo() {
+ ServiceInfo serviceInfo = new ServiceInfo();
+
+ serviceInfo.name = "ATV Remote Service";
+ serviceInfo.packageName = TV_REMOTE_SERVICE_PACKAGE_NAME;
+ serviceInfo.permission = Manifest.permission.BIND_TV_REMOTE_SERVICE;
+
+ return serviceInfo;
+ }
+}
diff --git a/services/tests/servicestests/src/com/android/server/tv/tunerresourcemanager/TunerResourceManagerServiceTest.java b/services/tests/servicestests/src/com/android/server/tv/tunerresourcemanager/TunerResourceManagerServiceTest.java
index bd63f3ce047c..8da3bdfdf38c 100644
--- a/services/tests/servicestests/src/com/android/server/tv/tunerresourcemanager/TunerResourceManagerServiceTest.java
+++ b/services/tests/servicestests/src/com/android/server/tv/tunerresourcemanager/TunerResourceManagerServiceTest.java
@@ -26,12 +26,12 @@ import android.media.tv.ITvInputManager;
import android.media.tv.TvInputManager;
import android.media.tv.TvInputService;
import android.media.tv.tuner.frontend.FrontendSettings;
+import android.media.tv.tunerresourcemanager.IResourcesReclaimListener;
import android.media.tv.tunerresourcemanager.ResourceClientProfile;
import android.media.tv.tunerresourcemanager.TunerFrontendInfo;
import android.media.tv.tunerresourcemanager.TunerFrontendRequest;
import android.media.tv.tunerresourcemanager.TunerResourceManager;
import android.os.RemoteException;
-import android.util.SparseArray;
import androidx.test.InstrumentationRegistry;
import androidx.test.filters.SmallTest;
@@ -45,9 +45,8 @@ import org.junit.runners.JUnit4;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
-import java.util.ArrayList;
import java.util.Arrays;
-import java.util.List;
+import java.util.Map;
/**
* Tests for {@link TunerResourceManagerService} class.
@@ -59,7 +58,19 @@ public class TunerResourceManagerServiceTest {
private Context mContextSpy;
@Mock private ITvInputManager mITvInputManagerMock;
private TunerResourceManagerService mTunerResourceManagerService;
- private int mReclaimingId;
+
+ private static final class TestResourcesReclaimListener extends IResourcesReclaimListener.Stub {
+ boolean mReclaimed;
+
+ @Override
+ public void onReclaimResources() {
+ mReclaimed = true;
+ }
+
+ public boolean isRelaimed() {
+ return mReclaimed;
+ }
+ }
// A correspondence to compare a FrontendResource and a TunerFrontendInfo.
private static final Correspondence<FrontendResource, TunerFrontendInfo> FR_TFI_COMPARE =
@@ -81,31 +92,14 @@ public class TunerResourceManagerServiceTest {
}
};
- private static <T> List<T> sparseArrayToList(SparseArray<T> sparseArray) {
- if (sparseArray == null) {
- return null;
- }
- List<T> arrayList = new ArrayList<T>(sparseArray.size());
- for (int i = 0; i < sparseArray.size(); i++) {
- arrayList.add(sparseArray.valueAt(i));
- }
- return arrayList;
- }
-
@Before
public void setUp() throws Exception {
MockitoAnnotations.initMocks(this);
TvInputManager tvInputManager = new TvInputManager(mITvInputManagerMock, 0);
mContextSpy = spy(new ContextWrapper(InstrumentationRegistry.getTargetContext()));
when(mContextSpy.getSystemService(Context.TV_INPUT_SERVICE)).thenReturn(tvInputManager);
- mTunerResourceManagerService = new TunerResourceManagerService(mContextSpy) {
- @Override
- protected void reclaimFrontendResource(int reclaimingId) {
- mReclaimingId = reclaimingId;
- }
- };
+ mTunerResourceManagerService = new TunerResourceManagerService(mContextSpy);
mTunerResourceManagerService.onStart(true /*isForTesting*/);
- mReclaimingId = -1;
}
@Test
@@ -118,7 +112,7 @@ public class TunerResourceManagerServiceTest {
new TunerFrontendInfo(1 /*id*/, FrontendSettings.TYPE_DVBT, 1 /*exclusiveGroupId*/);
mTunerResourceManagerService.setFrontendInfoListInternal(infos);
- SparseArray<FrontendResource> resources =
+ Map<Integer, FrontendResource> resources =
mTunerResourceManagerService.getFrontendResources();
for (int id = 0; id < infos.length; id++) {
assertThat(resources.get(infos[id].getId())
@@ -128,7 +122,7 @@ public class TunerResourceManagerServiceTest {
assertThat(resources.get(infos[id].getId())
.getExclusiveGroupMemberFeIds().size()).isEqualTo(0);
}
- assertThat(sparseArrayToList(resources)).comparingElementsUsing(FR_TFI_COMPARE)
+ assertThat(resources.values()).comparingElementsUsing(FR_TFI_COMPARE)
.containsExactlyElementsIn(Arrays.asList(infos));
}
@@ -146,19 +140,15 @@ public class TunerResourceManagerServiceTest {
new TunerFrontendInfo(3 /*id*/, FrontendSettings.TYPE_ATSC, 1 /*exclusiveGroupId*/);
mTunerResourceManagerService.setFrontendInfoListInternal(infos);
- SparseArray<FrontendResource> resources =
+ Map<Integer, FrontendResource> resources =
mTunerResourceManagerService.getFrontendResources();
- assertThat(sparseArrayToList(resources)).comparingElementsUsing(FR_TFI_COMPARE)
+ assertThat(resources.values()).comparingElementsUsing(FR_TFI_COMPARE)
.containsExactlyElementsIn(Arrays.asList(infos));
- assertThat(resources.get(0).getExclusiveGroupMemberFeIds())
- .isEqualTo(new ArrayList<Integer>());
- assertThat(resources.get(1).getExclusiveGroupMemberFeIds())
- .isEqualTo(new ArrayList<Integer>(Arrays.asList(2, 3)));
- assertThat(resources.get(2).getExclusiveGroupMemberFeIds())
- .isEqualTo(new ArrayList<Integer>(Arrays.asList(1, 3)));
- assertThat(resources.get(3).getExclusiveGroupMemberFeIds())
- .isEqualTo(new ArrayList<Integer>(Arrays.asList(1, 2)));
+ assertThat(resources.get(0).getExclusiveGroupMemberFeIds()).isEmpty();
+ assertThat(resources.get(1).getExclusiveGroupMemberFeIds()).containsExactly(2, 3);
+ assertThat(resources.get(2).getExclusiveGroupMemberFeIds()).containsExactly(1, 3);
+ assertThat(resources.get(3).getExclusiveGroupMemberFeIds()).containsExactly(1, 2);
}
@Test
@@ -171,11 +161,11 @@ public class TunerResourceManagerServiceTest {
new TunerFrontendInfo(1 /*id*/, FrontendSettings.TYPE_DVBS, 1 /*exclusiveGroupId*/);
mTunerResourceManagerService.setFrontendInfoListInternal(infos);
- SparseArray<FrontendResource> resources0 =
+ Map<Integer, FrontendResource> resources0 =
mTunerResourceManagerService.getFrontendResources();
mTunerResourceManagerService.setFrontendInfoListInternal(infos);
- SparseArray<FrontendResource> resources1 =
+ Map<Integer, FrontendResource> resources1 =
mTunerResourceManagerService.getFrontendResources();
assertThat(resources0).isEqualTo(resources1);
@@ -198,13 +188,13 @@ public class TunerResourceManagerServiceTest {
new TunerFrontendInfo(1 /*id*/, FrontendSettings.TYPE_DVBT, 1 /*exclusiveGroupId*/);
mTunerResourceManagerService.setFrontendInfoListInternal(infos1);
- SparseArray<FrontendResource> resources =
+ Map<Integer, FrontendResource> resources =
mTunerResourceManagerService.getFrontendResources();
for (int id = 0; id < infos1.length; id++) {
assertThat(resources.get(infos1[id].getId())
.getExclusiveGroupMemberFeIds().size()).isEqualTo(0);
}
- assertThat(sparseArrayToList(resources)).comparingElementsUsing(FR_TFI_COMPARE)
+ assertThat(resources.values()).comparingElementsUsing(FR_TFI_COMPARE)
.containsExactlyElementsIn(Arrays.asList(infos1));
}
@@ -225,13 +215,13 @@ public class TunerResourceManagerServiceTest {
new TunerFrontendInfo(1 /*id*/, FrontendSettings.TYPE_DVBT, 1 /*exclusiveGroupId*/);
mTunerResourceManagerService.setFrontendInfoListInternal(infos1);
- SparseArray<FrontendResource> resources =
+ Map<Integer, FrontendResource> resources =
mTunerResourceManagerService.getFrontendResources();
for (int id = 0; id < infos1.length; id++) {
assertThat(resources.get(infos1[id].getId())
.getExclusiveGroupMemberFeIds().size()).isEqualTo(0);
}
- assertThat(sparseArrayToList(resources)).comparingElementsUsing(FR_TFI_COMPARE)
+ assertThat(resources.values()).comparingElementsUsing(FR_TFI_COMPARE)
.containsExactlyElementsIn(Arrays.asList(infos1));
}
@@ -352,9 +342,9 @@ public class TunerResourceManagerServiceTest {
throw e.rethrowFromSystemServer();
}
assertThat(frontendId[0]).isEqualTo(infos[1].getId());
- assertThat(mTunerResourceManagerService.getFrontendResources().get(infos[1].getId())
+ assertThat(mTunerResourceManagerService.getFrontendResource(infos[1].getId())
.isInUse()).isTrue();
- assertThat(mTunerResourceManagerService.getFrontendResources().get(infos[2].getId())
+ assertThat(mTunerResourceManagerService.getFrontendResource(infos[2].getId())
.isInUse()).isTrue();
}
@@ -369,15 +359,17 @@ public class TunerResourceManagerServiceTest {
int[] clientPriorities = {100, 50};
int[] clientId0 = new int[1];
int[] clientId1 = new int[1];
+ TestResourcesReclaimListener listener = new TestResourcesReclaimListener();
+
mTunerResourceManagerService.registerClientProfileInternal(
- profiles[0], null /*listener*/, clientId0);
+ profiles[0], listener, clientId0);
assertThat(clientId0[0]).isNotEqualTo(TunerResourceManagerService.INVALID_CLIENT_ID);
- mTunerResourceManagerService.getClientProfiles().get(clientId0[0])
+ mTunerResourceManagerService.getClientProfile(clientId0[0])
.setPriority(clientPriorities[0]);
mTunerResourceManagerService.registerClientProfileInternal(
- profiles[1], null /*listener*/, clientId1);
+ profiles[1], new TestResourcesReclaimListener(), clientId1);
assertThat(clientId1[0]).isNotEqualTo(TunerResourceManagerService.INVALID_CLIENT_ID);
- mTunerResourceManagerService.getClientProfiles().get(clientId1[0])
+ mTunerResourceManagerService.getClientProfile(clientId1[0])
.setPriority(clientPriorities[1]);
// Init frontend resources.
@@ -403,17 +395,17 @@ public class TunerResourceManagerServiceTest {
try {
assertThat(mTunerResourceManagerService.requestFrontendInternal(request, frontendId))
.isFalse();
+ assertThat(listener.isRelaimed()).isFalse();
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
- assertThat(mReclaimingId).isEqualTo(-1);
request =
new TunerFrontendRequest(clientId1[0] /*clientId*/, FrontendSettings.TYPE_DVBS);
try {
assertThat(mTunerResourceManagerService.requestFrontendInternal(request, frontendId))
.isFalse();
- assertThat(mReclaimingId).isEqualTo(-1);
+ assertThat(listener.isRelaimed()).isFalse();
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
@@ -430,15 +422,16 @@ public class TunerResourceManagerServiceTest {
int[] clientPriorities = {100, 500};
int[] clientId0 = new int[1];
int[] clientId1 = new int[1];
+ TestResourcesReclaimListener listener = new TestResourcesReclaimListener();
mTunerResourceManagerService.registerClientProfileInternal(
- profiles[0], null /*listener*/, clientId0);
+ profiles[0], listener, clientId0);
assertThat(clientId0[0]).isNotEqualTo(TunerResourceManagerService.INVALID_CLIENT_ID);
- mTunerResourceManagerService.getClientProfiles().get(clientId0[0])
+ mTunerResourceManagerService.getClientProfile(clientId0[0])
.setPriority(clientPriorities[0]);
mTunerResourceManagerService.registerClientProfileInternal(
- profiles[1], null /*listener*/, clientId1);
+ profiles[1], new TestResourcesReclaimListener(), clientId1);
assertThat(clientId1[0]).isNotEqualTo(TunerResourceManagerService.INVALID_CLIENT_ID);
- mTunerResourceManagerService.getClientProfiles().get(clientId1[0])
+ mTunerResourceManagerService.getClientProfile(clientId1[0])
.setPriority(clientPriorities[1]);
// Init frontend resources.
@@ -469,15 +462,15 @@ public class TunerResourceManagerServiceTest {
throw e.rethrowFromSystemServer();
}
assertThat(frontendId[0]).isEqualTo(infos[1].getId());
- assertThat(mTunerResourceManagerService.getFrontendResources().get(infos[0].getId())
+ assertThat(mTunerResourceManagerService.getFrontendResource(infos[0].getId())
.isInUse()).isTrue();
- assertThat(mTunerResourceManagerService.getFrontendResources().get(infos[1].getId())
+ assertThat(mTunerResourceManagerService.getFrontendResource(infos[1].getId())
.isInUse()).isTrue();
- assertThat(mTunerResourceManagerService.getFrontendResources()
- .get(infos[0].getId()).getOwnerClientId()).isEqualTo(clientId1[0]);
- assertThat(mTunerResourceManagerService.getFrontendResources()
- .get(infos[1].getId()).getOwnerClientId()).isEqualTo(clientId1[0]);
- assertThat(mReclaimingId).isEqualTo(clientId0[0]);
+ assertThat(mTunerResourceManagerService.getFrontendResource(infos[0].getId())
+ .getOwnerClientId()).isEqualTo(clientId1[0]);
+ assertThat(mTunerResourceManagerService.getFrontendResource(infos[1].getId())
+ .getOwnerClientId()).isEqualTo(clientId1[0]);
+ assertThat(listener.isRelaimed()).isTrue();
}
@Test
@@ -508,17 +501,18 @@ public class TunerResourceManagerServiceTest {
throw e.rethrowFromSystemServer();
}
assertThat(frontendId[0]).isEqualTo(infos[0].getId());
- assertThat(mTunerResourceManagerService.getFrontendResources().get(infos[0].getId())
+ assertThat(mTunerResourceManagerService.getFrontendResource(infos[0].getId())
.isInUse()).isTrue();
- assertThat(mTunerResourceManagerService.getFrontendResources().get(infos[1].getId())
+ assertThat(mTunerResourceManagerService.getFrontendResource(infos[1].getId())
.isInUse()).isTrue();
// Unregister client when using frontend
mTunerResourceManagerService.unregisterClientProfileInternal(clientId[0]);
- assertThat(mTunerResourceManagerService.getFrontendResources().get(infos[0].getId())
+ assertThat(mTunerResourceManagerService.getFrontendResource(infos[0].getId())
.isInUse()).isFalse();
- assertThat(mTunerResourceManagerService.getFrontendResources().get(infos[1].getId())
+ assertThat(mTunerResourceManagerService.getFrontendResource(infos[1].getId())
.isInUse()).isFalse();
+ assertThat(mTunerResourceManagerService.checkClientExists(clientId[0])).isFalse();
}
}
diff --git a/services/tests/uiservicestests/src/com/android/server/notification/NotificationHistoryManagerTest.java b/services/tests/uiservicestests/src/com/android/server/notification/NotificationHistoryManagerTest.java
index f7c26091a7f4..2341c10a9c91 100644
--- a/services/tests/uiservicestests/src/com/android/server/notification/NotificationHistoryManagerTest.java
+++ b/services/tests/uiservicestests/src/com/android/server/notification/NotificationHistoryManagerTest.java
@@ -31,7 +31,6 @@ import android.app.NotificationHistory;
import android.app.NotificationHistory.HistoricalNotification;
import android.content.pm.UserInfo;
import android.graphics.drawable.Icon;
-import android.os.Handler;
import android.os.UserManager;
import android.provider.Settings;
@@ -40,7 +39,6 @@ import androidx.test.runner.AndroidJUnit4;
import com.android.server.UiServiceTestCase;
-import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
@@ -58,9 +56,9 @@ public class NotificationHistoryManagerTest extends UiServiceTestCase {
UserManager mUserManager;
@Mock
NotificationHistoryDatabase mDb;
- @Mock
- Handler mHandler;
List<UserInfo> mUsers;
+ int[] mProfiles;
+ int mProfileId = 11;
NotificationHistoryManager mHistoryManager;
@@ -98,26 +96,32 @@ public class NotificationHistoryManagerTest extends UiServiceTestCase {
UserInfo userSystem = new UserInfo();
userSystem.id = USER_SYSTEM;
mUsers.add(userSystem);
- UserInfo userAll = new UserInfo();
- userAll.id = MIN_SECONDARY_USER_ID;
- mUsers.add(userAll);
- mUsers.add(userAll);
+ UserInfo userFullSecondary = new UserInfo();
+ userFullSecondary.id = MIN_SECONDARY_USER_ID;
+ mUsers.add(userFullSecondary);
+ UserInfo userProfile = new UserInfo();
+ userProfile.id = mProfileId;
+ mUsers.add(userProfile);
when(mUserManager.getUsers()).thenReturn(mUsers);
- for (UserInfo info : mUsers) {
- Settings.Secure.putIntForUser(getContext().getContentResolver(),
- Settings.Secure.NOTIFICATION_HISTORY_ENABLED, 1, info.id);
- }
+ mProfiles = new int[] {userSystem.id, userProfile.id};
+ when(mUserManager.getProfileIds(userSystem.id, true)).thenReturn(mProfiles);
+ when(mUserManager.getProfileIds(userFullSecondary.id, true))
+ .thenReturn(new int[] {userFullSecondary.id});
+ when(mUserManager.getProfileIds(userProfile.id, true))
+ .thenReturn(new int[] {userProfile.id});
+
+ when(mUserManager.getProfileParent(userProfile.id)).thenReturn(userSystem);
NotificationHistoryDatabaseFactory.setTestingNotificationHistoryDatabase(mDb);
- mHistoryManager = new NotificationHistoryManager(getContext(), mHandler);
- mHistoryManager.onBootPhaseAppsCanStart();
- }
+ mHistoryManager = new NotificationHistoryManager(getContext(), null);
- @After
- public void tearDown() {
- mHistoryManager.onDestroy();
+ for (UserInfo info : mUsers) {
+ Settings.Secure.putIntForUser(getContext().getContentResolver(),
+ Settings.Secure.NOTIFICATION_HISTORY_ENABLED, 1, info.id);
+ mHistoryManager.mSettingsObserver.update(null, info.id);
+ }
}
@Test
@@ -151,6 +155,31 @@ public class NotificationHistoryManagerTest extends UiServiceTestCase {
}
@Test
+ public void testOnUserUnlocked_historyDisabled_withProfile() {
+ // create a history
+ mHistoryManager.onUserUnlocked(USER_SYSTEM);
+ assertThat(mHistoryManager.doesHistoryExistForUser(USER_SYSTEM)).isTrue();
+ mHistoryManager.onUserUnlocked(mProfileId);
+ assertThat(mHistoryManager.doesHistoryExistForUser(mProfileId)).isTrue();
+ // lock user
+ mHistoryManager.onUserStopped(USER_SYSTEM);
+ mHistoryManager.onUserStopped(mProfileId);
+
+ // turn off history
+ Settings.Secure.putIntForUser(getContext().getContentResolver(),
+ Settings.Secure.NOTIFICATION_HISTORY_ENABLED, 0, USER_SYSTEM);
+ mHistoryManager.mSettingsObserver.update(null, USER_SYSTEM);
+
+ // unlock user, verify that history is disabled for self and profile
+ mHistoryManager.onUserUnlocked(USER_SYSTEM);
+ mHistoryManager.onUserUnlocked(mProfileId);
+
+ assertThat(mHistoryManager.doesHistoryExistForUser(USER_SYSTEM)).isFalse();
+ assertThat(mHistoryManager.doesHistoryExistForUser(mProfileId)).isFalse();
+ verify(mDb, times(2)).disableHistory();
+ }
+
+ @Test
public void testOnUserUnlocked_historyDisabledThenEnabled() {
// create a history
mHistoryManager.onUserUnlocked(USER_SYSTEM);
@@ -177,6 +206,37 @@ public class NotificationHistoryManagerTest extends UiServiceTestCase {
}
@Test
+ public void testOnUserUnlocked_historyDisabledThenEnabled_multiProfile() {
+ // create a history
+ mHistoryManager.onUserUnlocked(USER_SYSTEM);
+ assertThat(mHistoryManager.doesHistoryExistForUser(USER_SYSTEM)).isTrue();
+ mHistoryManager.onUserUnlocked(mProfileId);
+ assertThat(mHistoryManager.doesHistoryExistForUser(mProfileId)).isTrue();
+
+ // lock user
+ mHistoryManager.onUserStopped(USER_SYSTEM);
+ mHistoryManager.onUserStopped(mProfileId);
+
+ // turn off history
+ Settings.Secure.putIntForUser(getContext().getContentResolver(),
+ Settings.Secure.NOTIFICATION_HISTORY_ENABLED, 0, USER_SYSTEM);
+ mHistoryManager.mSettingsObserver.update(null, USER_SYSTEM);
+
+ // turn on history
+ Settings.Secure.putIntForUser(getContext().getContentResolver(),
+ Settings.Secure.NOTIFICATION_HISTORY_ENABLED, 1, USER_SYSTEM);
+ mHistoryManager.mSettingsObserver.update(null, USER_SYSTEM);
+
+ // unlock user, verify that history is NOT disabled
+ mHistoryManager.onUserUnlocked(USER_SYSTEM);
+ mHistoryManager.onUserUnlocked(mProfileId);
+
+ assertThat(mHistoryManager.doesHistoryExistForUser(USER_SYSTEM)).isTrue();
+ assertThat(mHistoryManager.doesHistoryExistForUser(mProfileId)).isTrue();
+ verify(mDb, never()).disableHistory();
+ }
+
+ @Test
public void testOnUserUnlocked_cleansUpRemovedPackages() {
String pkg = "pkg";
mHistoryManager.onPackageRemoved(USER_SYSTEM, pkg);
diff --git a/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java b/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java
index b6cdbfb42c2d..64d481a2e6a0 100755
--- a/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java
+++ b/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java
@@ -4394,6 +4394,7 @@ public class NotificationManagerServiceTest extends UiServiceTestCase {
verify(mAppUsageStats, times(1)).reportInterruptiveNotification(
anyString(), anyString(), anyInt());
+ verify(mHistoryManager, times(1)).addNotification(any());
}
@Test
diff --git a/services/tests/wmtests/src/com/android/server/wm/ActivityTestsBase.java b/services/tests/wmtests/src/com/android/server/wm/ActivityTestsBase.java
index b6b3bc6ac104..4634e2d71573 100644
--- a/services/tests/wmtests/src/com/android/server/wm/ActivityTestsBase.java
+++ b/services/tests/wmtests/src/com/android/server/wm/ActivityTestsBase.java
@@ -40,6 +40,7 @@ import android.content.pm.ActivityInfo;
import android.content.pm.ApplicationInfo;
import android.content.res.Configuration;
import android.os.Build;
+import android.os.Bundle;
import android.os.UserHandle;
import android.service.voice.IVoiceInteractionSession;
@@ -112,6 +113,7 @@ class ActivityTestsBase extends SystemServiceTestsBase {
private int mLaunchedFromPid;
private int mLaunchedFromUid;
private WindowProcessController mWpc;
+ private Bundle mIntentExtras;
ActivityBuilder(ActivityTaskManagerService service) {
mService = service;
@@ -127,6 +129,11 @@ class ActivityTestsBase extends SystemServiceTestsBase {
return this;
}
+ ActivityBuilder setIntentExtras(Bundle extras) {
+ mIntentExtras = extras;
+ return this;
+ }
+
static ComponentName getDefaultComponent() {
return ComponentName.createRelative(DEFAULT_COMPONENT_PACKAGE_NAME,
DEFAULT_COMPONENT_PACKAGE_NAME);
@@ -227,10 +234,17 @@ class ActivityTestsBase extends SystemServiceTestsBase {
mTask = new TaskBuilder(mService.mStackSupervisor)
.setComponent(mComponent)
.setStack(mStack).build();
+ } else if (mTask == null && mStack != null && DisplayContent.alwaysCreateStack(
+ mStack.getWindowingMode(), mStack.getActivityType())) {
+ // The stack can be the task root.
+ mTask = mStack;
}
Intent intent = new Intent();
intent.setComponent(mComponent);
+ if (mIntentExtras != null) {
+ intent.putExtras(mIntentExtras);
+ }
final ActivityInfo aInfo = new ActivityInfo();
aInfo.applicationInfo = new ApplicationInfo();
aInfo.applicationInfo.targetSdkVersion = Build.VERSION_CODES.CUR_DEVELOPMENT;
diff --git a/services/tests/wmtests/src/com/android/server/wm/AppWindowTokenTests.java b/services/tests/wmtests/src/com/android/server/wm/AppWindowTokenTests.java
index 683fca46923f..6cc57f4dbf8c 100644
--- a/services/tests/wmtests/src/com/android/server/wm/AppWindowTokenTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/AppWindowTokenTests.java
@@ -34,7 +34,6 @@ import static android.view.WindowManager.LayoutParams.TYPE_BASE_APPLICATION;
import static androidx.test.platform.app.InstrumentationRegistry.getInstrumentation;
-import static com.android.dx.mockito.inline.extended.ExtendedMockito.doNothing;
import static com.android.dx.mockito.inline.extended.ExtendedMockito.doReturn;
import static com.android.server.wm.WindowStateAnimator.STACK_CLIP_AFTER_ANIM;
import static com.android.server.wm.WindowStateAnimator.STACK_CLIP_BEFORE_ANIM;
@@ -209,50 +208,6 @@ public class AppWindowTokenTests extends WindowTestsBase {
}
@Test
- @FlakyTest(bugId = 149760957)
- public void testSizeCompatBounds() {
- // Disable the real configuration resolving because we only simulate partial flow.
- // TODO: Have test use full flow.
- doNothing().when(mTask).computeConfigResourceOverrides(any(), any());
- final Rect fixedBounds = mActivity.getRequestedOverrideConfiguration().windowConfiguration
- .getBounds();
- fixedBounds.set(0, 0, 1200, 1600);
- mActivity.getRequestedOverrideConfiguration().windowConfiguration.setAppBounds(fixedBounds);
- final Configuration newParentConfig = mTask.getConfiguration();
-
- // Change the size of the container to two times smaller with insets.
- newParentConfig.windowConfiguration.setAppBounds(200, 0, 800, 800);
- final Rect containerAppBounds = newParentConfig.windowConfiguration.getAppBounds();
- final Rect containerBounds = newParentConfig.windowConfiguration.getBounds();
- containerBounds.set(0, 0, 600, 800);
- mActivity.onConfigurationChanged(newParentConfig);
-
- assertTrue(mActivity.hasSizeCompatBounds());
- assertEquals(containerAppBounds, mActivity.getBounds());
- assertEquals((float) containerAppBounds.width() / fixedBounds.width(),
- mActivity.getSizeCompatScale(), 0.0001f /* delta */);
-
- // Change the width of the container to two times bigger.
- containerAppBounds.set(0, 0, 2400, 1600);
- containerBounds.set(containerAppBounds);
- mActivity.onConfigurationChanged(newParentConfig);
-
- assertTrue(mActivity.hasSizeCompatBounds());
- // Don't scale up, so the bounds keep the same as the fixed width.
- assertEquals(fixedBounds.width(), mActivity.getBounds().width());
- // Assert the position is horizontal center.
- assertEquals((containerAppBounds.width() - fixedBounds.width()) / 2,
- mActivity.getBounds().left);
- assertEquals(1f, mActivity.getSizeCompatScale(), 0.0001f /* delta */);
-
- // Change the width of the container to fit the fixed bounds.
- containerBounds.set(0, 0, 1200, 2000);
- mActivity.onConfigurationChanged(newParentConfig);
- // Assert don't use fixed bounds because the region is enough.
- assertFalse(mActivity.hasSizeCompatBounds());
- }
-
- @Test
@Presubmit
public void testGetOrientation() {
mActivity.setVisible(true);
diff --git a/services/tests/wmtests/src/com/android/server/wm/InsetsPolicyTest.java b/services/tests/wmtests/src/com/android/server/wm/InsetsPolicyTest.java
index eae007d3a767..5e30477e1e3f 100644
--- a/services/tests/wmtests/src/com/android/server/wm/InsetsPolicyTest.java
+++ b/services/tests/wmtests/src/com/android/server/wm/InsetsPolicyTest.java
@@ -120,7 +120,6 @@ public class InsetsPolicyTest extends WindowTestsBase {
assertNull(controls);
}
- // TODO: adjust this test if we pretend to the app that it's still able to control it.
@Test
public void testControlsForDispatch_forceStatusBarVisible() {
addWindow(TYPE_STATUS_BAR, "statusBar").mAttrs.privateFlags |=
@@ -129,9 +128,9 @@ public class InsetsPolicyTest extends WindowTestsBase {
final InsetsSourceControl[] controls = addAppWindowAndGetControlsForDispatch();
- // The app must not control the status bar.
+ // The focused app window can control both system bars.
assertNotNull(controls);
- assertEquals(1, controls.length);
+ assertEquals(2, controls.length);
}
@Test
@@ -143,9 +142,9 @@ public class InsetsPolicyTest extends WindowTestsBase {
final InsetsSourceControl[] controls = addAppWindowAndGetControlsForDispatch();
- // The app must not control the navigation bar.
+ // The focused app window can control both system bars.
assertNotNull(controls);
- assertEquals(1, controls.length);
+ assertEquals(2, controls.length);
}
@Test
diff --git a/services/tests/wmtests/src/com/android/server/wm/RecentTasksTest.java b/services/tests/wmtests/src/com/android/server/wm/RecentTasksTest.java
index 9a898fda4ef3..66566bc5dff5 100644
--- a/services/tests/wmtests/src/com/android/server/wm/RecentTasksTest.java
+++ b/services/tests/wmtests/src/com/android/server/wm/RecentTasksTest.java
@@ -1020,6 +1020,29 @@ public class RecentTasksTest extends ActivityTestsBase {
verify(controller, times(4)).notifyTaskListUpdated();
}
+ @Test
+ public void testTaskInfo_expectNoExtras() {
+ doNothing().when(mRecentTasks).loadUserRecentsLocked(anyInt());
+ doReturn(true).when(mRecentTasks).isUserRunning(anyInt(), anyInt());
+
+ final Bundle data = new Bundle();
+ data.putInt("key", 100);
+ final Task task1 = createTaskBuilder(".Task").build();
+ final ActivityRecord r1 = new ActivityBuilder(mService)
+ .setTask(task1)
+ .setIntentExtras(data)
+ .build();
+ mRecentTasks.add(r1.getTask());
+
+ final List<RecentTaskInfo> infos = mRecentTasks.getRecentTasks(MAX_VALUE, 0 /* flags */,
+ true /* getTasksAllowed */, TEST_USER_0_ID, 0).getList();
+ assertTrue(infos.size() == 1);
+ for (int i = 0; i < infos.size(); i++) {
+ final Bundle extras = infos.get(i).baseIntent.getExtras();
+ assertTrue(extras == null || extras.isEmpty());
+ }
+ }
+
/**
* Ensures that the raw recent tasks list is in the provided order. Note that the expected tasks
* should be ordered from least to most recent.
@@ -1040,8 +1063,7 @@ public class RecentTasksTest extends ActivityTestsBase {
doNothing().when(mRecentTasks).loadUserRecentsLocked(anyInt());
doReturn(true).when(mRecentTasks).isUserRunning(anyInt(), anyInt());
List<RecentTaskInfo> infos = mRecentTasks.getRecentTasks(MAX_VALUE, getRecentTaskFlags,
- true /* getTasksAllowed */, false /* getDetailedTasks */,
- TEST_USER_0_ID, 0).getList();
+ true /* getTasksAllowed */, TEST_USER_0_ID, 0).getList();
assertTrue(expectedTasks.length == infos.size());
for (int i = 0; i < infos.size(); i++) {
assertTrue(expectedTasks[i].mTaskId == infos.get(i).taskId);
@@ -1329,11 +1351,9 @@ public class RecentTasksTest extends ActivityTestsBase {
@Override
ParceledListSlice<RecentTaskInfo> getRecentTasks(int maxNum, int flags,
- boolean getTasksAllowed,
- boolean getDetailedTasks, int userId, int callingUid) {
+ boolean getTasksAllowed, int userId, int callingUid) {
mLastAllowed = getTasksAllowed;
- return super.getRecentTasks(maxNum, flags, getTasksAllowed, getDetailedTasks, userId,
- callingUid);
+ return super.getRecentTasks(maxNum, flags, getTasksAllowed, userId, callingUid);
}
@Override
diff --git a/services/tests/wmtests/src/com/android/server/wm/RemoteAnimationControllerTest.java b/services/tests/wmtests/src/com/android/server/wm/RemoteAnimationControllerTest.java
index c7f94efdfde0..34ac835ae18d 100644
--- a/services/tests/wmtests/src/com/android/server/wm/RemoteAnimationControllerTest.java
+++ b/services/tests/wmtests/src/com/android/server/wm/RemoteAnimationControllerTest.java
@@ -98,7 +98,7 @@ public class RemoteAnimationControllerTest extends WindowTestsBase {
mDisplayContent.mOpeningApps.add(win.mActivityRecord);
try {
final AnimationAdapter adapter = mController.createRemoteAnimationRecord(win.mActivityRecord,
- new Point(50, 100), new Rect(50, 100, 150, 150), null).mAdapter;
+ new Point(50, 100), null, new Rect(50, 100, 150, 150), null).mAdapter;
adapter.startAnimation(mMockLeash, mMockTransaction, ANIMATION_TYPE_APP_TRANSITION,
mFinishedCallback);
mController.goodToGo();
@@ -136,7 +136,7 @@ public class RemoteAnimationControllerTest extends WindowTestsBase {
public void testCancel() throws Exception {
final WindowState win = createWindow(null /* parent */, TYPE_BASE_APPLICATION, "testWin");
final AnimationAdapter adapter = mController.createRemoteAnimationRecord(win.mActivityRecord,
- new Point(50, 100), new Rect(50, 100, 150, 150), null).mAdapter;
+ new Point(50, 100), null, new Rect(50, 100, 150, 150), null).mAdapter;
adapter.startAnimation(mMockLeash, mMockTransaction, ANIMATION_TYPE_APP_TRANSITION,
mFinishedCallback);
mController.goodToGo();
@@ -150,7 +150,7 @@ public class RemoteAnimationControllerTest extends WindowTestsBase {
public void testTimeout() throws Exception {
final WindowState win = createWindow(null /* parent */, TYPE_BASE_APPLICATION, "testWin");
final AnimationAdapter adapter = mController.createRemoteAnimationRecord(win.mActivityRecord,
- new Point(50, 100), new Rect(50, 100, 150, 150), null).mAdapter;
+ new Point(50, 100), null, new Rect(50, 100, 150, 150), null).mAdapter;
adapter.startAnimation(mMockLeash, mMockTransaction, ANIMATION_TYPE_APP_TRANSITION,
mFinishedCallback);
mController.goodToGo();
@@ -170,7 +170,8 @@ public class RemoteAnimationControllerTest extends WindowTestsBase {
final WindowState win = createWindow(null /* parent */, TYPE_BASE_APPLICATION,
"testWin");
final AnimationAdapter adapter = mController.createRemoteAnimationRecord(
- win.mActivityRecord, new Point(50, 100), new Rect(50, 100, 150, 150), null).mAdapter;
+ win.mActivityRecord, new Point(50, 100), null, new Rect(50, 100, 150, 150),
+ null).mAdapter;
adapter.startAnimation(mMockLeash, mMockTransaction, ANIMATION_TYPE_APP_TRANSITION,
mFinishedCallback);
mController.goodToGo();
@@ -201,7 +202,7 @@ public class RemoteAnimationControllerTest extends WindowTestsBase {
public void testNotReallyStarted() {
final WindowState win = createWindow(null /* parent */, TYPE_BASE_APPLICATION, "testWin");
mController.createRemoteAnimationRecord(win.mActivityRecord,
- new Point(50, 100), new Rect(50, 100, 150, 150), null);
+ new Point(50, 100), null, new Rect(50, 100, 150, 150), null);
mController.goodToGo();
verifyNoMoreInteractionsExceptAsBinder(mMockRunner);
}
@@ -211,9 +212,9 @@ public class RemoteAnimationControllerTest extends WindowTestsBase {
final WindowState win1 = createWindow(null /* parent */, TYPE_BASE_APPLICATION, "testWin1");
final WindowState win2 = createWindow(null /* parent */, TYPE_BASE_APPLICATION, "testWin2");
mController.createRemoteAnimationRecord(win1.mActivityRecord,
- new Point(50, 100), new Rect(50, 100, 150, 150), null);
+ new Point(50, 100), null, new Rect(50, 100, 150, 150), null);
final AnimationAdapter adapter = mController.createRemoteAnimationRecord(win2.mActivityRecord,
- new Point(50, 100), new Rect(50, 100, 150, 150), null).mAdapter;
+ new Point(50, 100), null, new Rect(50, 100, 150, 150), null).mAdapter;
adapter.startAnimation(mMockLeash, mMockTransaction, ANIMATION_TYPE_APP_TRANSITION,
mFinishedCallback);
mController.goodToGo();
@@ -234,7 +235,7 @@ public class RemoteAnimationControllerTest extends WindowTestsBase {
public void testRemovedBeforeStarted() {
final WindowState win = createWindow(null /* parent */, TYPE_BASE_APPLICATION, "testWin");
final AnimationAdapter adapter = mController.createRemoteAnimationRecord(win.mActivityRecord,
- new Point(50, 100), new Rect(50, 100, 150, 150), null).mAdapter;
+ new Point(50, 100), null, new Rect(50, 100, 150, 150), null).mAdapter;
adapter.startAnimation(mMockLeash, mMockTransaction, ANIMATION_TYPE_APP_TRANSITION,
mFinishedCallback);
win.mActivityRecord.removeImmediately();
@@ -250,7 +251,7 @@ public class RemoteAnimationControllerTest extends WindowTestsBase {
mDisplayContent.mChangingContainers.add(win.mActivityRecord);
try {
final RemoteAnimationRecord record = mController.createRemoteAnimationRecord(
- win.mActivityRecord, new Point(50, 100), new Rect(50, 100, 150, 150),
+ win.mActivityRecord, new Point(50, 100), null, new Rect(50, 100, 150, 150),
new Rect(0, 0, 200, 200));
assertNotNull(record.mThumbnailAdapter);
((AnimationAdapter) record.mAdapter)
@@ -304,7 +305,7 @@ public class RemoteAnimationControllerTest extends WindowTestsBase {
mDisplayContent.mOpeningApps.add(win.mActivityRecord);
try {
final AnimationAdapter adapter = mController.createRemoteAnimationRecord(win.mActivityRecord,
- new Point(50, 100), new Rect(50, 100, 150, 150), null).mAdapter;
+ new Point(50, 100), null, new Rect(50, 100, 150, 150), null).mAdapter;
adapter.startAnimation(mMockLeash, mMockTransaction, ANIMATION_TYPE_APP_TRANSITION,
mFinishedCallback);
mController.goodToGo();
@@ -333,7 +334,7 @@ public class RemoteAnimationControllerTest extends WindowTestsBase {
mDisplayContent.mOpeningApps.add(win.mActivityRecord);
try {
final AnimationAdapter adapter = mController.createRemoteAnimationRecord(win.mActivityRecord,
- new Point(50, 100), new Rect(50, 100, 150, 150), null).mAdapter;
+ new Point(50, 100), null, new Rect(50, 100, 150, 150), null).mAdapter;
adapter.startAnimation(mMockLeash, mMockTransaction, ANIMATION_TYPE_APP_TRANSITION,
mFinishedCallback);
mController.goodToGo();
diff --git a/services/tests/wmtests/src/com/android/server/wm/RunningTasksTest.java b/services/tests/wmtests/src/com/android/server/wm/RunningTasksTest.java
index 6272070efea7..0d5565428bf2 100644
--- a/services/tests/wmtests/src/com/android/server/wm/RunningTasksTest.java
+++ b/services/tests/wmtests/src/com/android/server/wm/RunningTasksTest.java
@@ -22,9 +22,11 @@ import static android.app.WindowConfiguration.WINDOWING_MODE_UNDEFINED;
import static com.google.common.truth.Truth.assertThat;
import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
import android.app.ActivityManager.RunningTaskInfo;
import android.content.ComponentName;
+import android.os.Bundle;
import android.platform.test.annotations.Presubmit;
import android.util.ArraySet;
@@ -58,8 +60,7 @@ public class RunningTasksTest extends ActivityTestsBase {
public void testCollectTasksByLastActiveTime() {
// Create a number of stacks with tasks (of incrementing active time)
final ArrayList<DisplayContent> displays = new ArrayList<>();
- final DisplayContent display =
- new TestDisplayContent.Builder(mService, 1000, 2500).build();
+ final DisplayContent display = new TestDisplayContent.Builder(mService, 1000, 2500).build();
displays.add(display);
final int numStacks = 2;
@@ -74,7 +75,7 @@ public class RunningTasksTest extends ActivityTestsBase {
final int numTasks = 10;
int activeTime = 0;
for (int i = 0; i < numTasks; i++) {
- createTask(display.getStackAt(i % numStacks), ".Task" + i, i, activeTime++);
+ createTask(display.getStackAt(i % numStacks), ".Task" + i, i, activeTime++, null);
}
// Ensure that the latest tasks were returned in order of decreasing last active time,
@@ -101,11 +102,39 @@ public class RunningTasksTest extends ActivityTestsBase {
}
}
+ @Test
+ public void testTaskInfo_expectNoExtras() {
+ final DisplayContent display = new TestDisplayContent.Builder(mService, 1000, 2500).build();
+ final int numTasks = 10;
+ for (int i = 0; i < numTasks; i++) {
+ final ActivityStack stack = new StackBuilder(mRootWindowContainer)
+ .setCreateActivity(false)
+ .setDisplay(display)
+ .setOnTop(true)
+ .build();
+ final Bundle data = new Bundle();
+ data.putInt("key", 100);
+ createTask(stack, ".Task" + i, i, i, data);
+ }
+
+ final int numFetchTasks = 5;
+ final ArrayList<RunningTaskInfo> tasks = new ArrayList<>();
+ mRunningTasks.getTasks(numFetchTasks, tasks, ACTIVITY_TYPE_UNDEFINED,
+ WINDOWING_MODE_UNDEFINED, mRootWindowContainer, -1 /* callingUid */,
+ true /* allowed */, true /*crossUser */, PROFILE_IDS);
+ assertThat(tasks).hasSize(numFetchTasks);
+ for (int i = 0; i < tasks.size(); i++) {
+ final Bundle extras = tasks.get(i).baseIntent.getExtras();
+ assertTrue(extras == null || extras.isEmpty());
+ }
+ }
+
+
/**
* Create a task with a single activity in it, with the given last active time.
*/
private Task createTask(ActivityStack stack, String className, int taskId,
- int lastActiveTime) {
+ int lastActiveTime, Bundle extras) {
final Task task = new TaskBuilder(mService.mStackSupervisor)
.setComponent(new ComponentName(mContext.getPackageName(), className))
.setTaskId(taskId)
@@ -115,6 +144,7 @@ public class RunningTasksTest extends ActivityTestsBase {
final ActivityRecord activity = new ActivityBuilder(mService)
.setTask(task)
.setComponent(new ComponentName(mContext.getPackageName(), ".TaskActivity"))
+ .setIntentExtras(extras)
.build();
return task;
}
diff --git a/services/tests/wmtests/src/com/android/server/wm/SizeCompatTests.java b/services/tests/wmtests/src/com/android/server/wm/SizeCompatTests.java
index 890e4ab90ce9..ba4a82fc2d54 100644
--- a/services/tests/wmtests/src/com/android/server/wm/SizeCompatTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/SizeCompatTests.java
@@ -45,6 +45,7 @@ import android.content.res.Configuration;
import android.graphics.Rect;
import android.os.IBinder;
import android.platform.test.annotations.Presubmit;
+import android.view.WindowManager;
import androidx.test.filters.MediumTest;
@@ -73,13 +74,14 @@ public class SizeCompatTests extends ActivityTestsBase {
mActivity = mTask.getTopNonFinishingActivity();
}
- private void ensureActivityConfiguration() {
- mActivity.ensureActivityConfiguration(0 /* globalChanges */, false /* preserveWindow */);
+ private void setUpDisplaySizeWithApp(int dw, int dh) {
+ final TestDisplayContent.Builder builder = new TestDisplayContent.Builder(mService, dw, dh);
+ setUpApp(builder.build());
}
@Test
public void testRestartProcessIfVisible() {
- setUpApp(new TestDisplayContent.Builder(mService, 1000, 2500).build());
+ setUpDisplaySizeWithApp(1000, 2500);
doNothing().when(mSupervisor).scheduleRestartTimeout(mActivity);
mActivity.mVisibleRequested = true;
mActivity.setSavedState(null /* savedState */);
@@ -116,43 +118,54 @@ public class SizeCompatTests extends ActivityTestsBase {
c.windowConfiguration.setWindowingMode(WindowConfiguration.WINDOWING_MODE_FULLSCREEN);
display.onRequestedOverrideConfigurationChanged(c);
- // check if dimensions stay the same
- assertTrue(mActivity.inSizeCompatMode());
+ // Check if dimensions on screen stay the same by scaling.
+ assertScaled();
assertEquals(bounds.width(), mActivity.getBounds().width());
assertEquals(bounds.height(), mActivity.getBounds().height());
assertEquals(density, mActivity.getConfiguration().densityDpi);
}
@Test
- public void testFixedAspectRatioBoundsWithDecor() {
- final int decorHeight = 200; // e.g. The device has cutout.
- setUpApp(new TestDisplayContent.Builder(mService, 600, 800)
- .setNotch(decorHeight).build());
-
- mActivity.info.minAspectRatio = mActivity.info.maxAspectRatio = 1;
+ public void testFixedAspectRatioBoundsWithDecorInSquareDisplay() {
+ final int notchHeight = 100;
+ setUpApp(new TestDisplayContent.Builder(mService, 600, 800).setNotch(notchHeight).build());
+ // Rotation is ignored so because the display size is close to square (700/600<1.333).
+ assertTrue(mActivity.mDisplayContent.ignoreRotationForApps());
+
+ final Rect displayBounds = mActivity.mDisplayContent.getBounds();
+ final float aspectRatio = 1.2f;
+ mActivity.info.minAspectRatio = mActivity.info.maxAspectRatio = aspectRatio;
prepareUnresizable(-1f, SCREEN_ORIENTATION_UNSPECIFIED);
+ final Rect appBounds = mActivity.getWindowConfiguration().getAppBounds();
// The parent configuration doesn't change since the first resolved configuration, so the
- // activity shouldn't be in the size compatibility mode.
- assertFalse(mActivity.inSizeCompatMode());
-
- final Rect appBounds = mActivity.getWindowConfiguration().getAppBounds();
+ // activity should fit in the parent naturally. (size=583x700).
+ assertFitted();
+ final int offsetX = (int) ((1f + displayBounds.width() - appBounds.width()) / 2);
+ // The bounds must be horizontal centered.
+ assertEquals(offsetX, appBounds.left);
+ assertEquals(appBounds.height(), displayBounds.height() - notchHeight);
// Ensure the app bounds keep the declared aspect ratio.
- assertEquals(appBounds.width(), appBounds.height());
+ assertEquals(appBounds.height(), appBounds.width() * aspectRatio, 0.5f /* delta */);
// The decor height should be a part of the effective bounds.
- assertEquals(mActivity.getBounds().height(), appBounds.height() + decorHeight);
+ assertEquals(mActivity.getBounds().height(), appBounds.height() + notchHeight);
- mTask.getConfiguration().windowConfiguration.setRotation(ROTATION_90);
- mActivity.onConfigurationChanged(mTask.getConfiguration());
- // After changing orientation, the aspect ratio should be the same.
- assertEquals(appBounds.width(), appBounds.height());
- // The decor height will be included in width.
- assertEquals(mActivity.getBounds().width(), appBounds.width() + decorHeight);
+ mActivity.setRequestedOrientation(SCREEN_ORIENTATION_LANDSCAPE);
+ assertFitted();
+
+ // After the orientation of activity is changed, even display is not rotated, the aspect
+ // ratio should be the same (bounds=[0, 0 - 600, 600], appBounds=[0, 100 - 600, 600]).
+ assertEquals(appBounds.width(), appBounds.height() * aspectRatio, 0.5f /* delta */);
+ // The notch is still on top.
+ assertEquals(mActivity.getBounds().height(), appBounds.height() + notchHeight);
+
+ mActivity.setRequestedOrientation(SCREEN_ORIENTATION_PORTRAIT);
+ assertFitted();
}
@Test
public void testFixedScreenConfigurationWhenMovingToDisplay() {
- setUpApp(new TestDisplayContent.Builder(mService, 1000, 2500).build());
+ setUpDisplaySizeWithApp(1000, 2500);
// Make a new less-tall display with lower density
final DisplayContent newDisplay =
@@ -175,107 +188,133 @@ public class SizeCompatTests extends ActivityTestsBase {
assertEquals(originalBounds.width(), mActivity.getBounds().width());
assertEquals(originalBounds.height(), mActivity.getBounds().height());
assertEquals(originalDpi, mActivity.getConfiguration().densityDpi);
- assertTrue(mActivity.inSizeCompatMode());
+ assertScaled();
}
@Test
public void testFixedScreenBoundsWhenDisplaySizeChanged() {
- setUpApp(new TestDisplayContent.Builder(mService, 1000, 2500).build());
+ setUpDisplaySizeWithApp(1000, 2500);
prepareUnresizable(-1f /* maxAspect */, SCREEN_ORIENTATION_PORTRAIT);
- assertFalse(mActivity.inSizeCompatMode());
+ assertFitted();
final Rect origBounds = new Rect(mActivity.getBounds());
+ final Rect currentBounds = mActivity.getWindowConfiguration().getBounds();
// Change the size of current display.
resizeDisplay(mStack.getDisplay(), 1000, 2000);
- ensureActivityConfiguration();
- assertEquals(origBounds.width(), mActivity.getWindowConfiguration().getBounds().width());
- assertEquals(origBounds.height(), mActivity.getWindowConfiguration().getBounds().height());
- assertTrue(mActivity.inSizeCompatMode());
+ assertEquals(origBounds.width(), currentBounds.width());
+ assertEquals(origBounds.height(), currentBounds.height());
+ assertScaled();
+
+ // The position of configuration bounds should be the same as compat bounds.
+ assertEquals(mActivity.getBounds().left, currentBounds.left);
+ assertEquals(mActivity.getBounds().top, currentBounds.top);
// Change display size to a different orientation
resizeDisplay(mStack.getDisplay(), 2000, 1000);
- ensureActivityConfiguration();
- assertEquals(origBounds.width(), mActivity.getWindowConfiguration().getBounds().width());
- assertEquals(origBounds.height(), mActivity.getWindowConfiguration().getBounds().height());
+ assertEquals(origBounds.width(), currentBounds.width());
+ assertEquals(origBounds.height(), currentBounds.height());
}
@Test
- public void testLetterboxFullscreenBounds() {
- setUpApp(new TestDisplayContent.Builder(mService, 1000, 2500).build());
-
- // Fill out required fields on default display since WM-side is mocked out
- prepareUnresizable(-1.f /* maxAspect */, SCREEN_ORIENTATION_LANDSCAPE);
- assertFalse(mActivity.inSizeCompatMode());
- assertTrue(mActivity.getBounds().width() > mActivity.getBounds().height());
+ public void testLetterboxFullscreenBoundsAndNotImeAttachable() {
+ final int displayWidth = 2500;
+ setUpDisplaySizeWithApp(displayWidth, 1000);
+
+ final float maxAspect = 1.5f;
+ prepareUnresizable(maxAspect, SCREEN_ORIENTATION_LANDSCAPE);
+ assertFitted();
+
+ final Rect bounds = mActivity.getBounds();
+ assertEquals(bounds.width(), bounds.height() * maxAspect, 0.0001f /* delta */);
+ // The position should be horizontal centered.
+ assertEquals((displayWidth - bounds.width()) / 2, bounds.left);
+
+ final WindowTestUtils.TestWindowState w = new WindowTestUtils.TestWindowState(
+ mService.mWindowManager, mock(Session.class), new TestIWindow(),
+ new WindowManager.LayoutParams(), mActivity);
+ mActivity.addWindow(w);
+ mActivity.mDisplayContent.mInputMethodTarget = w;
+ // Make sure IME cannot attach to the app, otherwise IME window will also be shifted.
+ assertFalse(mActivity.mDisplayContent.isImeAttachedToApp());
}
@Test
public void testMoveToDifferentOrientDisplay() {
- setUpApp(new TestDisplayContent.Builder(mService, 1000, 2500).build());
-
- final DisplayContent newDisplay =
- new TestDisplayContent.Builder(mService, 2000, 1000)
- .setCanRotate(false).build();
-
+ setUpDisplaySizeWithApp(1000, 2500);
prepareUnresizable(-1.f /* maxAspect */, SCREEN_ORIENTATION_PORTRAIT);
- assertFalse(mActivity.inSizeCompatMode());
+ assertFitted();
- final Rect origBounds = new Rect(mActivity.getBounds());
+ final Rect configBounds = mActivity.getWindowConfiguration().getBounds();
+ final int origWidth = configBounds.width();
+ final int origHeight = configBounds.height();
+
+ final int notchHeight = 100;
+ final DisplayContent newDisplay = new TestDisplayContent.Builder(mService, 2000, 1000)
+ .setCanRotate(false).setNotch(notchHeight).build();
// Move the non-resizable activity to the new display.
- mStack.reparent(newDisplay.mDisplayContent, true /* onTop */);
- ensureActivityConfiguration();
- assertEquals(origBounds.width(), mActivity.getWindowConfiguration().getBounds().width());
- assertEquals(origBounds.height(), mActivity.getWindowConfiguration().getBounds().height());
- assertTrue(mActivity.inSizeCompatMode());
+ mStack.reparent(newDisplay, true /* onTop */);
+ // The configuration bounds should keep the same.
+ assertEquals(origWidth, configBounds.width());
+ assertEquals(origHeight, configBounds.height());
+ assertScaled();
+
+ // The scaled bounds should exclude notch area (1000 - 100 == 360 * 2500 / 1000 = 900).
+ assertEquals(newDisplay.getBounds().height() - notchHeight,
+ (int) ((float) mActivity.getBounds().width() * origHeight / origWidth));
}
@Test
public void testFixedOrientRotateCutoutDisplay() {
// Create a display with a notch/cutout
- setUpApp(new TestDisplayContent.Builder(mService, 1000, 2500).setNotch(60).build());
+ final int notchHeight = 60;
+ setUpApp(new TestDisplayContent.Builder(mService, 1000, 2500)
+ .setNotch(notchHeight).build());
+ // Bounds=[0, 0 - 1000, 1460], AppBounds=[0, 60 - 1000, 1460].
prepareUnresizable(1.4f /* maxAspect */, SCREEN_ORIENTATION_PORTRAIT);
- final Rect origBounds = new Rect(mActivity.getBounds());
- final Rect origAppBounds = new Rect(mActivity.getWindowConfiguration().getAppBounds());
+ final Rect currentBounds = mActivity.getWindowConfiguration().getBounds();
+ final Rect appBounds = mActivity.getWindowConfiguration().getAppBounds();
+ final Rect origBounds = new Rect(currentBounds);
+ final Rect origAppBounds = new Rect(appBounds);
- // Rotate the display
- Configuration c = new Configuration();
- mStack.getDisplay().mDisplayContent.getDisplayRotation().setRotation(ROTATION_270);
- mStack.getDisplay().mDisplayContent.computeScreenConfiguration(c);
- mStack.getDisplay().onRequestedOverrideConfigurationChanged(c);
+ // Although the activity is fixed orientation, force rotate the display.
+ rotateDisplay(mActivity.mDisplayContent, ROTATION_270);
+ assertEquals(ROTATION_270, mStack.getWindowConfiguration().getRotation());
+ assertEquals(origBounds.width(), currentBounds.width());
+ // The notch is on horizontal side, so current height changes from 1460 to 1400.
+ assertEquals(origBounds.height() - notchHeight, currentBounds.height());
// Make sure the app size is the same
- assertEquals(ROTATION_270, mStack.getWindowConfiguration().getRotation());
- assertEquals(origBounds.width(), mActivity.getWindowConfiguration().getBounds().width());
- assertEquals(origBounds.height(), mActivity.getWindowConfiguration().getBounds().height());
- assertEquals(origAppBounds.width(),
- mActivity.getWindowConfiguration().getAppBounds().width());
- assertEquals(origAppBounds.height(),
- mActivity.getWindowConfiguration().getAppBounds().height());
+ assertEquals(origAppBounds.width(), appBounds.width());
+ assertEquals(origAppBounds.height(), appBounds.height());
+ // The activity is 1000x1400 and the display is 2500x1000.
+ assertScaled();
+ // The position in configuration should be global coordinates.
+ assertEquals(mActivity.getBounds().left, currentBounds.left);
+ assertEquals(mActivity.getBounds().top, currentBounds.top);
}
@Test
public void testFixedAspOrientChangeOrient() {
- setUpApp(new TestDisplayContent.Builder(mService, 1000, 2500).build());
+ setUpDisplaySizeWithApp(1000, 2500);
- prepareUnresizable(1.4f /* maxAspect */, SCREEN_ORIENTATION_LANDSCAPE);
+ final float maxAspect = 1.4f;
+ prepareUnresizable(maxAspect, SCREEN_ORIENTATION_PORTRAIT);
// The display aspect ratio 2.5 > 1.4 (max of activity), so the size is fitted.
- assertFalse(mActivity.inSizeCompatMode());
+ assertFitted();
final Rect originalBounds = new Rect(mActivity.getBounds());
final Rect originalAppBounds = new Rect(mActivity.getWindowConfiguration().getAppBounds());
- // Change the fixed orientation
- mActivity.mOrientation = SCREEN_ORIENTATION_PORTRAIT;
- mActivity.info.screenOrientation = SCREEN_ORIENTATION_PORTRAIT;
- // TaskRecord's configuration actually depends on the activity config right now for
- // pillarboxing.
- mActivity.getTask().onRequestedOverrideConfigurationChanged(
- mActivity.getTask().getRequestedOverrideConfiguration());
+ assertEquals((int) (originalBounds.width() * maxAspect), originalBounds.height());
+
+ // Change the fixed orientation.
+ mActivity.setRequestedOrientation(SCREEN_ORIENTATION_LANDSCAPE);
+ assertFitted();
assertEquals(originalBounds.width(), mActivity.getBounds().height());
assertEquals(originalBounds.height(), mActivity.getBounds().width());
assertEquals(originalAppBounds.width(),
@@ -286,7 +325,7 @@ public class SizeCompatTests extends ActivityTestsBase {
@Test
public void testFixedScreenLayoutSizeBits() {
- setUpApp(new TestDisplayContent.Builder(mService, 1000, 2500).build());
+ setUpDisplaySizeWithApp(1000, 2500);
final int fixedScreenLayout = Configuration.SCREENLAYOUT_LONG_NO
| Configuration.SCREENLAYOUT_SIZE_NORMAL
| Configuration.SCREENLAYOUT_COMPAT_NEEDED;
@@ -314,7 +353,7 @@ public class SizeCompatTests extends ActivityTestsBase {
@Test
public void testResetNonVisibleActivity() {
- setUpApp(new TestDisplayContent.Builder(mService, 1000, 2500).build());
+ setUpDisplaySizeWithApp(1000, 2500);
prepareUnresizable(1.5f, SCREEN_ORIENTATION_UNSPECIFIED);
final DisplayContent display = mStack.getDisplay();
// Resize the display so the activity is in size compatibility mode.
@@ -325,23 +364,20 @@ public class SizeCompatTests extends ActivityTestsBase {
mActivity.app.setReportedProcState(ActivityManager.PROCESS_STATE_CACHED_ACTIVITY);
// Simulate the display changes orientation.
- final Configuration c = new Configuration();
- display.getDisplayRotation().setRotation(ROTATION_90);
- display.computeScreenConfiguration(c);
- display.onRequestedOverrideConfigurationChanged(c);
+ final Configuration rotatedConfig = rotateDisplay(display, ROTATION_90);
// Size compatibility mode is able to handle orientation change so the process shouldn't be
// restarted and the override configuration won't be cleared.
verify(mActivity, never()).restartProcessIfVisible();
- assertTrue(mActivity.inSizeCompatMode());
+ assertScaled();
// Change display density
display.mBaseDisplayDensity = (int) (0.7f * display.mBaseDisplayDensity);
- display.computeScreenConfiguration(c);
+ display.computeScreenConfiguration(rotatedConfig);
mService.mAmInternal = mock(ActivityManagerInternal.class);
- display.onRequestedOverrideConfigurationChanged(c);
+ display.onRequestedOverrideConfigurationChanged(rotatedConfig);
// The override configuration should be reset and the activity's process will be killed.
- assertFalse(mActivity.inSizeCompatMode());
+ assertFitted();
verify(mActivity).restartProcessIfVisible();
waitHandlerIdle(mService.mH);
verify(mService.mAmInternal).killProcess(
@@ -354,11 +390,11 @@ public class SizeCompatTests extends ActivityTestsBase {
*/
@Test
public void testHandleActivitySizeCompatMode() {
- setUpApp(new TestDisplayContent.Builder(mService, 1000, 2000).build());
+ setUpDisplaySizeWithApp(1000, 2000);
ActivityRecord activity = mActivity;
activity.setState(ActivityStack.ActivityState.RESUMED, "testHandleActivitySizeCompatMode");
prepareUnresizable(-1.f /* maxAspect */, SCREEN_ORIENTATION_PORTRAIT);
- assertFalse(mActivity.inSizeCompatMode());
+ assertFitted();
final ArrayList<IBinder> compatTokens = new ArrayList<>();
mService.getTaskChangeNotificationController().registerTaskStackListener(
@@ -393,7 +429,7 @@ public class SizeCompatTests extends ActivityTestsBase {
@Test
public void testShouldUseSizeCompatModeOnResizableTask() {
- setUpApp(new TestDisplayContent.Builder(mService, 1000, 2500).build());
+ setUpDisplaySizeWithApp(1000, 2500);
// Make the task root resizable.
mActivity.info.resizeMode = ActivityInfo.RESIZE_MODE_RESIZEABLE;
@@ -418,6 +454,29 @@ public class SizeCompatTests extends ActivityTestsBase {
assertFalse(activity.shouldUseSizeCompatMode());
}
+ @Test
+ public void testLaunchWithFixedRotationTransform() {
+ mService.mWindowManager.mIsFixedRotationTransformEnabled = true;
+ final int dw = 1000;
+ final int dh = 2500;
+ setUpDisplaySizeWithApp(dw, dh);
+ mActivity.mDisplayContent.prepareAppTransition(WindowManager.TRANSIT_ACTIVITY_OPEN,
+ false /* alwaysKeepCurrent */);
+ mActivity.mDisplayContent.mOpeningApps.add(mActivity);
+ final float maxAspect = 1.8f;
+ prepareUnresizable(maxAspect, SCREEN_ORIENTATION_LANDSCAPE);
+
+ assertFitted();
+ assertTrue(mActivity.isFixedRotationTransforming());
+ // Display keeps in original orientation.
+ assertEquals(Configuration.ORIENTATION_PORTRAIT,
+ mActivity.mDisplayContent.getConfiguration().orientation);
+ // Activity bounds should be [350, 0 - 2150, 1000] in landscape. Its width=1000*1.8=1800.
+ assertEquals((int) (dw * maxAspect), mActivity.getBounds().width());
+ // The bounds should be horizontal centered: (2500-1900)/2=350.
+ assertEquals((dh - mActivity.getBounds().width()) / 2, mActivity.getBounds().left);
+ }
+
/**
* Setup {@link #mActivity} as a size-compat-mode-able activity with fixed aspect and/or
* orientation.
@@ -429,22 +488,48 @@ public class SizeCompatTests extends ActivityTestsBase {
mActivity.info.maxAspectRatio = maxAspect;
}
if (screenOrientation != SCREEN_ORIENTATION_UNSPECIFIED) {
- mActivity.mOrientation = screenOrientation;
mActivity.info.screenOrientation = screenOrientation;
- // TaskRecord's configuration actually depends on the activity config right now for
- // pillarboxing.
- mActivity.getTask().onRequestedOverrideConfigurationChanged(
- mActivity.getTask().getRequestedOverrideConfiguration());
+ mActivity.setRequestedOrientation(screenOrientation);
+ }
+ // Make sure to use the provided configuration to construct the size compat fields.
+ mActivity.clearSizeCompatMode();
+ mActivity.ensureActivityConfiguration(0 /* globalChanges */, false /* preserveWindow */);
+ // Make sure the display configuration reflects the change of activity.
+ if (mActivity.mDisplayContent.updateOrientation()) {
+ mActivity.mDisplayContent.sendNewConfiguration();
}
- ensureActivityConfiguration();
}
- private void resizeDisplay(DisplayContent display, int width, int height) {
- final DisplayContent displayContent = display.mDisplayContent;
+ /** Asserts that the size of activity is larger than its parent so it is scaling. */
+ private void assertScaled() {
+ assertTrue(mActivity.inSizeCompatMode());
+ assertNotEquals(1f, mActivity.getSizeCompatScale(), 0.0001f /* delta */);
+ }
+
+ /** Asserts that the activity is best fitted in the parent. */
+ private void assertFitted() {
+ final boolean inSizeCompatMode = mActivity.inSizeCompatMode();
+ final String failedConfigInfo = inSizeCompatMode
+ ? ("ParentConfig=" + mActivity.getParent().getConfiguration()
+ + " ActivityConfig=" + mActivity.getConfiguration())
+ : "";
+ assertFalse(failedConfigInfo, inSizeCompatMode);
+ assertFalse(mActivity.hasSizeCompatBounds());
+ }
+
+ private static Configuration rotateDisplay(DisplayContent display, int rotation) {
+ final Configuration c = new Configuration();
+ display.getDisplayRotation().setRotation(rotation);
+ display.computeScreenConfiguration(c);
+ display.onRequestedOverrideConfigurationChanged(c);
+ return c;
+ }
+
+ private static void resizeDisplay(DisplayContent displayContent, int width, int height) {
displayContent.mBaseDisplayWidth = width;
displayContent.mBaseDisplayHeight = height;
- Configuration c = new Configuration();
+ final Configuration c = new Configuration();
displayContent.computeScreenConfiguration(c);
- display.onRequestedOverrideConfigurationChanged(c);
+ displayContent.onRequestedOverrideConfigurationChanged(c);
}
}
diff --git a/services/tests/wmtests/src/com/android/server/wm/TaskOrganizerTests.java b/services/tests/wmtests/src/com/android/server/wm/TaskOrganizerTests.java
index 45b51cf9d2db..48a583cad7a3 100644
--- a/services/tests/wmtests/src/com/android/server/wm/TaskOrganizerTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/TaskOrganizerTests.java
@@ -39,6 +39,7 @@ import static com.android.dx.mockito.inline.extended.ExtendedMockito.when;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNotEquals;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertTrue;
import static org.mockito.ArgumentMatchers.any;
@@ -253,6 +254,30 @@ public class TaskOrganizerTests extends WindowTestsBase {
}
@Test
+ public void testOverrideConfigSize() {
+ removeGlobalMinSizeRestriction();
+ final ActivityStack stack = new ActivityTestsBase.StackBuilder(mWm.mRoot)
+ .setWindowingMode(WINDOWING_MODE_FREEFORM).build();
+ final Task task = stack.getTopMostTask();
+ WindowContainerTransaction t = new WindowContainerTransaction();
+ t.setBounds(task.mRemoteToken, new Rect(10, 10, 100, 100));
+ mWm.mAtmService.mTaskOrganizerController.applyContainerTransaction(t, null);
+ final int origScreenWDp = task.getConfiguration().screenHeightDp;
+ final int origScreenHDp = task.getConfiguration().screenHeightDp;
+ t = new WindowContainerTransaction();
+ // verify that setting config overrides on parent restricts children.
+ t.setScreenSizeDp(stack.mRemoteToken, origScreenWDp, origScreenHDp);
+ t.setBounds(task.mRemoteToken, new Rect(10, 10, 150, 200));
+ mWm.mAtmService.mTaskOrganizerController.applyContainerTransaction(t, null);
+ assertEquals(origScreenHDp, task.getConfiguration().screenHeightDp);
+ t = new WindowContainerTransaction();
+ t.setScreenSizeDp(stack.mRemoteToken, Configuration.SCREEN_WIDTH_DP_UNDEFINED,
+ Configuration.SCREEN_HEIGHT_DP_UNDEFINED);
+ mWm.mAtmService.mTaskOrganizerController.applyContainerTransaction(t, null);
+ assertNotEquals(origScreenHDp, task.getConfiguration().screenHeightDp);
+ }
+
+ @Test
public void testCreateDeleteRootTasks() {
RunningTaskInfo info1 = mWm.mAtmService.mTaskOrganizerController.createRootTask(
Display.DEFAULT_DISPLAY,
@@ -293,8 +318,7 @@ public class TaskOrganizerTests extends WindowTestsBase {
// Info should reflect new membership
List<TaskTile> tiles = getTaskTiles(mDisplayContent);
- info1 = new RunningTaskInfo();
- tiles.get(0).fillTaskInfo(info1);
+ info1 = tiles.get(0).getTaskInfo();
assertEquals(ACTIVITY_TYPE_STANDARD, info1.topActivityType);
// Children inherit configuration
@@ -307,9 +331,8 @@ public class TaskOrganizerTests extends WindowTestsBase {
tile1.removeChild(stack);
assertEquals(mDisplayContent.getWindowingMode(), stack.getWindowingMode());
- info1 = new RunningTaskInfo();
tiles = getTaskTiles(mDisplayContent);
- tiles.get(0).fillTaskInfo(info1);
+ info1 = tiles.get(0).getTaskInfo();
assertEquals(ACTIVITY_TYPE_UNDEFINED, info1.topActivityType);
}
diff --git a/services/tests/wmtests/src/com/android/server/wm/TaskPositionerTests.java b/services/tests/wmtests/src/com/android/server/wm/TaskPositionerTests.java
index 52b465ff4634..ea52d7d4b189 100644
--- a/services/tests/wmtests/src/com/android/server/wm/TaskPositionerTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/TaskPositionerTests.java
@@ -36,7 +36,6 @@ import android.graphics.Rect;
import android.platform.test.annotations.Presubmit;
import android.util.DisplayMetrics;
import android.util.Log;
-import android.view.Display;
import androidx.test.filters.FlakyTest;
import androidx.test.filters.SmallTest;
@@ -71,18 +70,21 @@ public class TaskPositionerTests extends WindowTestsBase {
public void setUp() {
TaskPositioner.setFactory(null);
- final Display display = mDisplayContent.getDisplay();
- final DisplayMetrics dm = new DisplayMetrics();
- display.getMetrics(dm);
+ final DisplayMetrics dm = mDisplayContent.getDisplayMetrics();
// This should be the same calculation as the TaskPositioner uses.
mMinVisibleWidth = dipToPixel(MINIMUM_VISIBLE_WIDTH_IN_DP, dm);
mMinVisibleHeight = dipToPixel(MINIMUM_VISIBLE_HEIGHT_IN_DP, dm);
removeGlobalMinSizeRestriction();
- WindowState win = createWindow(null, TYPE_BASE_APPLICATION, "window");
- mPositioner = new TaskPositioner(mWm, mWm.mAtmService);
-
+ final ActivityStack stack = createTaskStackOnDisplay(mDisplayContent);
+ final ActivityRecord activity = new ActivityTestsBase.ActivityBuilder(stack.mAtmService)
+ .setStack(stack)
+ // In real case, there is no additional level for freeform mode.
+ .setCreateTask(false)
+ .build();
+ final WindowState win = createWindow(null, TYPE_BASE_APPLICATION, activity, "window");
+ mPositioner = new TaskPositioner(mWm);
mPositioner.register(mDisplayContent, win);
win.getRootTask().setWindowingMode(WINDOWING_MODE_FREEFORM);
@@ -109,6 +111,28 @@ public class TaskPositionerTests extends WindowTestsBase {
assertTrue(created[0]);
}
+ /** This tests that the window can move in all directions. */
+ @Test
+ public void testMoveWindow() {
+ final Rect displayBounds = mDisplayContent.getBounds();
+ final int windowSize = Math.min(displayBounds.width(), displayBounds.height()) / 2;
+ final int left = displayBounds.centerX() - windowSize / 2;
+ final int top = displayBounds.centerY() - windowSize / 2;
+ final Rect r = new Rect(left, top, left + windowSize, top + windowSize);
+ mPositioner.mTask.setBounds(r);
+ mPositioner.startDrag(false /* resizing */, false /* preserveOrientation */, left, top);
+
+ // Move upper left.
+ mPositioner.notifyMoveLocked(left - MOUSE_DELTA_X, top - MOUSE_DELTA_Y);
+ r.offset(-MOUSE_DELTA_X, -MOUSE_DELTA_Y);
+ assertBoundsEquals(r, mPositioner.getWindowDragBounds());
+
+ // Move bottom right.
+ mPositioner.notifyMoveLocked(left, top);
+ r.offset(MOUSE_DELTA_X, MOUSE_DELTA_Y);
+ assertBoundsEquals(r, mPositioner.getWindowDragBounds());
+ }
+
/**
* This tests that free resizing will allow to change the orientation as well
* as does some basic tests (e.g. dragging in Y only will keep X stable).
diff --git a/services/tests/wmtests/src/com/android/server/wm/TaskRecordTests.java b/services/tests/wmtests/src/com/android/server/wm/TaskRecordTests.java
index bf24bb0c1dbd..a25acae3c036 100644
--- a/services/tests/wmtests/src/com/android/server/wm/TaskRecordTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/TaskRecordTests.java
@@ -277,8 +277,8 @@ public class TaskRecordTests extends ActivityTestsBase {
public void testFullscreenBoundsForcedOrientation() {
final Rect fullScreenBounds = new Rect(0, 0, 1920, 1080);
final Rect fullScreenBoundsPort = new Rect(0, 0, 1080, 1920);
- DisplayContent display = new TestDisplayContent.Builder(
- mService, fullScreenBounds.width(), fullScreenBounds.height()).build();
+ final DisplayContent display = new TestDisplayContent.Builder(mService,
+ fullScreenBounds.width(), fullScreenBounds.height()).setCanRotate(false).build();
assertTrue(mRootWindowContainer.getDisplayContent(display.mDisplayId) != null);
// Fix the display orientation to landscape which is the natural rotation (0) for the test
// display.
@@ -396,7 +396,7 @@ public class TaskRecordTests extends ActivityTestsBase {
// Setup the display with a top stable inset. The later assertion will ensure the inset is
// excluded from screenHeightDp.
final int statusBarHeight = 100;
- final DisplayContent displayContent = mock(DisplayContent.class);
+ final DisplayContent displayContent = task.mDisplayContent;
final DisplayPolicy policy = mock(DisplayPolicy.class);
doAnswer(invocationOnMock -> {
final Rect insets = invocationOnMock.<Rect>getArgument(0);
@@ -410,9 +410,7 @@ public class TaskRecordTests extends ActivityTestsBase {
// Without limiting to be inside the parent bounds, the out screen size should keep relative
// to the input bounds.
final ActivityRecord.CompatDisplayInsets compatIntsets =
- new ActivityRecord.CompatDisplayInsets(displayContent, new Rect(0, 0,
- displayContent.mBaseDisplayWidth, displayContent.mBaseDisplayHeight),
- false);
+ new ActivityRecord.CompatDisplayInsets(displayContent, task);
task.computeConfigResourceOverrides(inOutConfig, parentConfig, compatIntsets);
assertEquals((shortSide - statusBarHeight) * DENSITY_DEFAULT / parentConfig.densityDpi,
diff --git a/services/tests/wmtests/src/com/android/server/wm/TestDisplayContent.java b/services/tests/wmtests/src/com/android/server/wm/TestDisplayContent.java
index 77af5eec2796..fc8cc96d224c 100644
--- a/services/tests/wmtests/src/com/android/server/wm/TestDisplayContent.java
+++ b/services/tests/wmtests/src/com/android/server/wm/TestDisplayContent.java
@@ -36,18 +36,15 @@ import android.view.DisplayCutout;
import android.view.DisplayInfo;
class TestDisplayContent extends DisplayContent {
- private final ActivityStackSupervisor mSupervisor;
- private TestDisplayContent(ActivityStackSupervisor supervisor, Display display) {
- super(display, supervisor.mService.mRootWindowContainer);
+ private TestDisplayContent(RootWindowContainer rootWindowContainer, Display display) {
+ super(display, rootWindowContainer);
// Normally this comes from display-properties as exposed by WM. Without that, just
// hard-code to FULLSCREEN for tests.
setWindowingMode(WINDOWING_MODE_FULLSCREEN);
- mSupervisor = supervisor;
spyOn(this);
- spyOn(mDisplayContent);
- final DisplayRotation displayRotation = mDisplayContent.getDisplayRotation();
+ final DisplayRotation displayRotation = getDisplayRotation();
spyOn(displayRotation);
doAnswer(invocation -> {
// Bypass all the rotation animation and display freezing stuff for testing and just
@@ -58,12 +55,12 @@ class TestDisplayContent extends DisplayContent {
if (oldRotation == rotation) {
return false;
}
- mDisplayContent.setLayoutNeeded();
+ setLayoutNeeded();
displayRotation.setRotation(rotation);
return true;
}).when(displayRotation).updateRotationUnchecked(anyBoolean());
- final InputMonitor inputMonitor = mDisplayContent.getInputMonitor();
+ final InputMonitor inputMonitor = getInputMonitor();
spyOn(inputMonitor);
doNothing().when(inputMonitor).resumeDispatchingLw(any());
}
@@ -133,9 +130,9 @@ class TestDisplayContent extends DisplayContent {
final Display display = new Display(DisplayManagerGlobal.getInstance(), displayId,
mInfo, DEFAULT_DISPLAY_ADJUSTMENTS);
final TestDisplayContent newDisplay =
- new TestDisplayContent(mService.mStackSupervisor, display);
+ new TestDisplayContent(mService.mRootWindowContainer, display);
// disable the normal system decorations
- final DisplayPolicy displayPolicy = newDisplay.mDisplayContent.getDisplayPolicy();
+ final DisplayPolicy displayPolicy = newDisplay.getDisplayPolicy();
spyOn(displayPolicy);
if (mSystemDecorations) {
doReturn(true).when(newDisplay).supportsSystemDecorations();
@@ -145,13 +142,12 @@ class TestDisplayContent extends DisplayContent {
doReturn(false).when(newDisplay).supportsSystemDecorations();
}
Configuration c = new Configuration();
- newDisplay.mDisplayContent.computeScreenConfiguration(c);
+ newDisplay.computeScreenConfiguration(c);
c.windowConfiguration.setWindowingMode(mWindowingMode);
newDisplay.onRequestedOverrideConfigurationChanged(c);
- // This is a rotating display
- if (mCanRotate) {
- doReturn(false).when(newDisplay.mDisplayContent)
- .handlesOrientationChangeFromDescendant();
+ if (!mCanRotate) {
+ final DisplayRotation displayRotation = newDisplay.getDisplayRotation();
+ doReturn(false).when(displayRotation).respectAppRequestedOrientation();
}
// Please add stubbing before this line. Services will start using this display in other
// threads immediately after adding it to hierarchy. Calling doAnswer() type of stubbing
diff --git a/services/tests/wmtests/src/com/android/server/wm/WindowManagerServiceTests.java b/services/tests/wmtests/src/com/android/server/wm/WindowManagerServiceTests.java
index 35723abb4310..da4bde59a09e 100644
--- a/services/tests/wmtests/src/com/android/server/wm/WindowManagerServiceTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/WindowManagerServiceTests.java
@@ -16,9 +16,16 @@
package com.android.server.wm;
+import static android.view.WindowManager.LayoutParams.TYPE_TOAST;
+
import static androidx.test.platform.app.InstrumentationRegistry.getInstrumentation;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+import static org.mockito.Mockito.mock;
+
import android.content.pm.PackageManager;
+import android.os.IBinder;
import android.platform.test.annotations.Presubmit;
import androidx.test.filters.SmallTest;
@@ -57,4 +64,25 @@ public class WindowManagerServiceTests extends WindowTestsBase {
return getInstrumentation().getTargetContext().getPackageManager().hasSystemFeature(
PackageManager.FEATURE_AUTOMOTIVE);
}
+
+ @Test
+ public void testAddWindowToken() {
+ IBinder token = mock(IBinder.class);
+ mWm.addWindowToken(token, TYPE_TOAST, mDisplayContent.getDisplayId());
+
+ WindowToken windowToken = mWm.mRoot.getWindowToken(token);
+ assertFalse(windowToken.mRoundedCornerOverlay);
+ assertFalse(windowToken.mFromClientToken);
+ }
+
+ @Test
+ public void testAddWindowTokenWithOptions() {
+ IBinder token = mock(IBinder.class);
+ mWm.addWindowTokenWithOptions(token, TYPE_TOAST, mDisplayContent.getDisplayId(),
+ null /* options */, null /* options */);
+
+ WindowToken windowToken = mWm.mRoot.getWindowToken(token);
+ assertFalse(windowToken.mRoundedCornerOverlay);
+ assertTrue(windowToken.mFromClientToken);
+ }
}
diff --git a/services/tests/wmtests/src/com/android/server/wm/WindowTokenTests.java b/services/tests/wmtests/src/com/android/server/wm/WindowTokenTests.java
index e6aed498cf1c..38f643daec27 100644
--- a/services/tests/wmtests/src/com/android/server/wm/WindowTokenTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/WindowTokenTests.java
@@ -25,7 +25,9 @@ import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertTrue;
+import static org.mockito.Mockito.mock;
+import android.os.IBinder;
import android.platform.test.annotations.Presubmit;
import androidx.test.filters.SmallTest;
@@ -129,4 +131,28 @@ public class WindowTokenTests extends WindowTestsBase {
// Verify that the token windows are no longer attached to it.
assertEquals(0, token.getWindowsCount());
}
+
+ /**
+ * Test that {@link WindowToken} constructor parameters is set with expectation.
+ */
+ @Test
+ public void testWindowTokenConstructorSanity() {
+ WindowToken token = new WindowToken(mDisplayContent.mWmService, mock(IBinder.class),
+ TYPE_TOAST, true /* persistOnEmpty */, mDisplayContent,
+ true /* ownerCanManageAppTokens */);
+ assertFalse(token.mRoundedCornerOverlay);
+ assertFalse(token.mFromClientToken);
+
+ token = new WindowToken(mDisplayContent.mWmService, mock(IBinder.class), TYPE_TOAST,
+ true /* persistOnEmpty */, mDisplayContent, true /* ownerCanManageAppTokens */,
+ true /* roundedCornerOverlay */);
+ assertTrue(token.mRoundedCornerOverlay);
+ assertFalse(token.mFromClientToken);
+
+ token = new WindowToken(mDisplayContent.mWmService, mock(IBinder.class), TYPE_TOAST,
+ true /* persistOnEmpty */, mDisplayContent, true /* ownerCanManageAppTokens */,
+ true /* roundedCornerOverlay */, true /* fromClientToken */);
+ assertTrue(token.mRoundedCornerOverlay);
+ assertTrue(token.mFromClientToken);
+ }
}
diff --git a/telecomm/java/android/telecom/Connection.java b/telecomm/java/android/telecom/Connection.java
index 5f33a3d6f1de..9dfa3ac7a5d8 100755
--- a/telecomm/java/android/telecom/Connection.java
+++ b/telecomm/java/android/telecom/Connection.java
@@ -2331,7 +2331,6 @@ public abstract class Connection extends Conferenceable {
* See {@link TelecomManager} for valid values.
*/
public final void setAddress(Uri address, int presentation) {
- checkImmutable();
Log.d(this, "setAddress %s", address);
mAddress = address;
mAddressPresentation = presentation;
@@ -3358,6 +3357,7 @@ public abstract class Connection extends Conferenceable {
private boolean mImmutable = false;
public FailureSignalingConnection(DisconnectCause disconnectCause) {
setDisconnected(disconnectCause);
+ mImmutable = true;
}
public void checkImmutable() {
diff --git a/telephony/java/android/telephony/AccessNetworkConstants.java b/telephony/java/android/telephony/AccessNetworkConstants.java
index 01abb2661f39..558f4cd24471 100644
--- a/telephony/java/android/telephony/AccessNetworkConstants.java
+++ b/telephony/java/android/telephony/AccessNetworkConstants.java
@@ -19,6 +19,10 @@ package android.telephony;
import android.annotation.IntDef;
import android.annotation.SystemApi;
import android.annotation.TestApi;
+import android.hardware.radio.V1_1.EutranBands;
+import android.hardware.radio.V1_1.GeranBands;
+import android.hardware.radio.V1_5.AccessNetwork;
+import android.hardware.radio.V1_5.UtranBands;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
@@ -84,13 +88,13 @@ public final class AccessNetworkConstants {
public @interface RadioAccessNetworkType {}
public static final class AccessNetworkType {
- public static final int UNKNOWN = 0;
- public static final int GERAN = 1;
- public static final int UTRAN = 2;
- public static final int EUTRAN = 3;
- public static final int CDMA2000 = 4;
- public static final int IWLAN = 5;
- public static final int NGRAN = 6;
+ public static final int UNKNOWN = AccessNetwork.UNKNOWN;
+ public static final int GERAN = AccessNetwork.GERAN;
+ public static final int UTRAN = AccessNetwork.UTRAN;
+ public static final int EUTRAN = AccessNetwork.EUTRAN;
+ public static final int CDMA2000 = AccessNetwork.CDMA2000;
+ public static final int IWLAN = AccessNetwork.IWLAN;
+ public static final int NGRAN = AccessNetwork.NGRAN;
/** @hide */
private AccessNetworkType() {}
@@ -115,20 +119,20 @@ public final class AccessNetworkConstants {
* http://www.etsi.org/deliver/etsi_ts/145000_145099/145005/14.00.00_60/ts_145005v140000p.pdf
*/
public static final class GeranBand {
- public static final int BAND_T380 = 1;
- public static final int BAND_T410 = 2;
- public static final int BAND_450 = 3;
- public static final int BAND_480 = 4;
- public static final int BAND_710 = 5;
- public static final int BAND_750 = 6;
- public static final int BAND_T810 = 7;
- public static final int BAND_850 = 8;
- public static final int BAND_P900 = 9;
- public static final int BAND_E900 = 10;
- public static final int BAND_R900 = 11;
- public static final int BAND_DCS1800 = 12;
- public static final int BAND_PCS1900 = 13;
- public static final int BAND_ER900 = 14;
+ public static final int BAND_T380 = GeranBands.BAND_T380;
+ public static final int BAND_T410 = GeranBands.BAND_T410;
+ public static final int BAND_450 = GeranBands.BAND_450;
+ public static final int BAND_480 = GeranBands.BAND_480;
+ public static final int BAND_710 = GeranBands.BAND_710;
+ public static final int BAND_750 = GeranBands.BAND_750;
+ public static final int BAND_T810 = GeranBands.BAND_T810;
+ public static final int BAND_850 = GeranBands.BAND_850;
+ public static final int BAND_P900 = GeranBands.BAND_P900;
+ public static final int BAND_E900 = GeranBands.BAND_E900;
+ public static final int BAND_R900 = GeranBands.BAND_R900;
+ public static final int BAND_DCS1800 = GeranBands.BAND_DCS1800;
+ public static final int BAND_PCS1900 = GeranBands.BAND_PCS1900;
+ public static final int BAND_ER900 = GeranBands.BAND_ER900;
/** @hide */
private GeranBand() {}
@@ -139,28 +143,28 @@ public final class AccessNetworkConstants {
* http://www.etsi.org/deliver/etsi_ts/125100_125199/125104/13.03.00_60/ts_125104v130p.pdf
*/
public static final class UtranBand {
- public static final int BAND_1 = 1;
- public static final int BAND_2 = 2;
- public static final int BAND_3 = 3;
- public static final int BAND_4 = 4;
- public static final int BAND_5 = 5;
- public static final int BAND_6 = 6;
- public static final int BAND_7 = 7;
- public static final int BAND_8 = 8;
- public static final int BAND_9 = 9;
- public static final int BAND_10 = 10;
- public static final int BAND_11 = 11;
- public static final int BAND_12 = 12;
- public static final int BAND_13 = 13;
- public static final int BAND_14 = 14;
+ public static final int BAND_1 = UtranBands.BAND_1;
+ public static final int BAND_2 = UtranBands.BAND_2;
+ public static final int BAND_3 = UtranBands.BAND_3;
+ public static final int BAND_4 = UtranBands.BAND_4;
+ public static final int BAND_5 = UtranBands.BAND_5;
+ public static final int BAND_6 = UtranBands.BAND_6;
+ public static final int BAND_7 = UtranBands.BAND_7;
+ public static final int BAND_8 = UtranBands.BAND_8;
+ public static final int BAND_9 = UtranBands.BAND_9;
+ public static final int BAND_10 = UtranBands.BAND_10;
+ public static final int BAND_11 = UtranBands.BAND_11;
+ public static final int BAND_12 = UtranBands.BAND_12;
+ public static final int BAND_13 = UtranBands.BAND_13;
+ public static final int BAND_14 = UtranBands.BAND_14;
// band 15, 16, 17, 18 are reserved
- public static final int BAND_19 = 19;
- public static final int BAND_20 = 20;
- public static final int BAND_21 = 21;
- public static final int BAND_22 = 22;
+ public static final int BAND_19 = UtranBands.BAND_19;
+ public static final int BAND_20 = UtranBands.BAND_20;
+ public static final int BAND_21 = UtranBands.BAND_21;
+ public static final int BAND_22 = UtranBands.BAND_22;
// band 23, 24 are reserved
- public static final int BAND_25 = 25;
- public static final int BAND_26 = 26;
+ public static final int BAND_25 = UtranBands.BAND_25;
+ public static final int BAND_26 = UtranBands.BAND_26;
// Frequency bands for TD-SCDMA. Defined in 3GPP TS 25.102, Table 5.2.
@@ -169,38 +173,38 @@ public final class AccessNetworkConstants {
* 1900 - 1920 MHz: Uplink and downlink transmission
* 2010 - 2025 MHz: Uplink and downlink transmission
*/
- public static final int BAND_A = 101;
+ public static final int BAND_A = UtranBands.BAND_A;
/**
* Band B
* 1850 - 1910 MHz: Uplink and downlink transmission
* 1930 - 1990 MHz: Uplink and downlink transmission
*/
- public static final int BAND_B = 102;
+ public static final int BAND_B = UtranBands.BAND_B;
/**
* Band C
* 1910 - 1930 MHz: Uplink and downlink transmission
*/
- public static final int BAND_C = 103;
+ public static final int BAND_C = UtranBands.BAND_C;
/**
* Band D
* 2570 - 2620 MHz: Uplink and downlink transmission
*/
- public static final int BAND_D = 104;
+ public static final int BAND_D = UtranBands.BAND_D;
/**
* Band E
* 2300—2400 MHz: Uplink and downlink transmission
*/
- public static final int BAND_E = 105;
+ public static final int BAND_E = UtranBands.BAND_E;
/**
* Band F
* 1880 - 1920 MHz: Uplink and downlink transmission
*/
- public static final int BAND_F = 106;
+ public static final int BAND_F = UtranBands.BAND_F;
/** @hide */
private UtranBand() {}
@@ -211,54 +215,54 @@ public final class AccessNetworkConstants {
* http://www.etsi.org/deliver/etsi_ts/136100_136199/136101/14.03.00_60/ts_136101v140p.pdf
*/
public static final class EutranBand {
- public static final int BAND_1 = 1;
- public static final int BAND_2 = 2;
- public static final int BAND_3 = 3;
- public static final int BAND_4 = 4;
- public static final int BAND_5 = 5;
- public static final int BAND_6 = 6;
- public static final int BAND_7 = 7;
- public static final int BAND_8 = 8;
- public static final int BAND_9 = 9;
- public static final int BAND_10 = 10;
- public static final int BAND_11 = 11;
- public static final int BAND_12 = 12;
- public static final int BAND_13 = 13;
- public static final int BAND_14 = 14;
- public static final int BAND_17 = 17;
- public static final int BAND_18 = 18;
- public static final int BAND_19 = 19;
- public static final int BAND_20 = 20;
- public static final int BAND_21 = 21;
- public static final int BAND_22 = 22;
- public static final int BAND_23 = 23;
- public static final int BAND_24 = 24;
- public static final int BAND_25 = 25;
- public static final int BAND_26 = 26;
- public static final int BAND_27 = 27;
- public static final int BAND_28 = 28;
- public static final int BAND_30 = 30;
- public static final int BAND_31 = 31;
- public static final int BAND_33 = 33;
- public static final int BAND_34 = 34;
- public static final int BAND_35 = 35;
- public static final int BAND_36 = 36;
- public static final int BAND_37 = 37;
- public static final int BAND_38 = 38;
- public static final int BAND_39 = 39;
- public static final int BAND_40 = 40;
- public static final int BAND_41 = 41;
- public static final int BAND_42 = 42;
- public static final int BAND_43 = 43;
- public static final int BAND_44 = 44;
- public static final int BAND_45 = 45;
- public static final int BAND_46 = 46;
- public static final int BAND_47 = 47;
- public static final int BAND_48 = 48;
- public static final int BAND_65 = 65;
- public static final int BAND_66 = 66;
- public static final int BAND_68 = 68;
- public static final int BAND_70 = 70;
+ public static final int BAND_1 = EutranBands.BAND_1;
+ public static final int BAND_2 = EutranBands.BAND_2;
+ public static final int BAND_3 = EutranBands.BAND_3;
+ public static final int BAND_4 = EutranBands.BAND_4;
+ public static final int BAND_5 = EutranBands.BAND_5;
+ public static final int BAND_6 = EutranBands.BAND_6;
+ public static final int BAND_7 = EutranBands.BAND_7;
+ public static final int BAND_8 = EutranBands.BAND_8;
+ public static final int BAND_9 = EutranBands.BAND_9;
+ public static final int BAND_10 = EutranBands.BAND_10;
+ public static final int BAND_11 = EutranBands.BAND_11;
+ public static final int BAND_12 = EutranBands.BAND_12;
+ public static final int BAND_13 = EutranBands.BAND_13;
+ public static final int BAND_14 = EutranBands.BAND_14;
+ public static final int BAND_17 = EutranBands.BAND_17;
+ public static final int BAND_18 = EutranBands.BAND_18;
+ public static final int BAND_19 = EutranBands.BAND_19;
+ public static final int BAND_20 = EutranBands.BAND_20;
+ public static final int BAND_21 = EutranBands.BAND_21;
+ public static final int BAND_22 = EutranBands.BAND_22;
+ public static final int BAND_23 = EutranBands.BAND_23;
+ public static final int BAND_24 = EutranBands.BAND_24;
+ public static final int BAND_25 = EutranBands.BAND_25;
+ public static final int BAND_26 = EutranBands.BAND_26;
+ public static final int BAND_27 = EutranBands.BAND_27;
+ public static final int BAND_28 = EutranBands.BAND_28;
+ public static final int BAND_30 = EutranBands.BAND_30;
+ public static final int BAND_31 = EutranBands.BAND_31;
+ public static final int BAND_33 = EutranBands.BAND_33;
+ public static final int BAND_34 = EutranBands.BAND_34;
+ public static final int BAND_35 = EutranBands.BAND_35;
+ public static final int BAND_36 = EutranBands.BAND_36;
+ public static final int BAND_37 = EutranBands.BAND_37;
+ public static final int BAND_38 = EutranBands.BAND_38;
+ public static final int BAND_39 = EutranBands.BAND_39;
+ public static final int BAND_40 = EutranBands.BAND_40;
+ public static final int BAND_41 = EutranBands.BAND_41;
+ public static final int BAND_42 = EutranBands.BAND_42;
+ public static final int BAND_43 = EutranBands.BAND_43;
+ public static final int BAND_44 = EutranBands.BAND_44;
+ public static final int BAND_45 = EutranBands.BAND_45;
+ public static final int BAND_46 = EutranBands.BAND_46;
+ public static final int BAND_47 = EutranBands.BAND_47;
+ public static final int BAND_48 = EutranBands.BAND_48;
+ public static final int BAND_65 = EutranBands.BAND_65;
+ public static final int BAND_66 = EutranBands.BAND_66;
+ public static final int BAND_68 = EutranBands.BAND_68;
+ public static final int BAND_70 = EutranBands.BAND_70;
/** @hide */
private EutranBand() {};
@@ -304,51 +308,51 @@ public final class AccessNetworkConstants {
*/
public static final class NgranBands {
/** FR1 bands */
- public static final int BAND_1 = 1;
- public static final int BAND_2 = 2;
- public static final int BAND_3 = 3;
- public static final int BAND_5 = 5;
- public static final int BAND_7 = 7;
- public static final int BAND_8 = 8;
- public static final int BAND_12 = 12;
- public static final int BAND_14 = 14;
- public static final int BAND_18 = 18;
- public static final int BAND_20 = 20;
- public static final int BAND_25 = 25;
- public static final int BAND_28 = 28;
- public static final int BAND_29 = 29;
- public static final int BAND_30 = 30;
- public static final int BAND_34 = 34;
- public static final int BAND_38 = 38;
- public static final int BAND_39 = 39;
- public static final int BAND_40 = 40;
- public static final int BAND_41 = 41;
- public static final int BAND_48 = 48;
- public static final int BAND_50 = 50;
- public static final int BAND_51 = 51;
- public static final int BAND_65 = 65;
- public static final int BAND_66 = 66;
- public static final int BAND_70 = 70;
- public static final int BAND_71 = 71;
- public static final int BAND_74 = 74;
- public static final int BAND_75 = 75;
- public static final int BAND_76 = 76;
- public static final int BAND_77 = 77;
- public static final int BAND_78 = 78;
- public static final int BAND_79 = 79;
- public static final int BAND_80 = 80;
- public static final int BAND_81 = 81;
- public static final int BAND_82 = 82;
- public static final int BAND_83 = 83;
- public static final int BAND_84 = 84;
- public static final int BAND_86 = 86;
- public static final int BAND_90 = 90;
+ public static final int BAND_1 = android.hardware.radio.V1_5.NgranBands.BAND_1;
+ public static final int BAND_2 = android.hardware.radio.V1_5.NgranBands.BAND_2;
+ public static final int BAND_3 = android.hardware.radio.V1_5.NgranBands.BAND_3;
+ public static final int BAND_5 = android.hardware.radio.V1_5.NgranBands.BAND_5;
+ public static final int BAND_7 = android.hardware.radio.V1_5.NgranBands.BAND_7;
+ public static final int BAND_8 = android.hardware.radio.V1_5.NgranBands.BAND_8;
+ public static final int BAND_12 = android.hardware.radio.V1_5.NgranBands.BAND_12;
+ public static final int BAND_14 = android.hardware.radio.V1_5.NgranBands.BAND_14;
+ public static final int BAND_18 = android.hardware.radio.V1_5.NgranBands.BAND_18;
+ public static final int BAND_20 = android.hardware.radio.V1_5.NgranBands.BAND_20;
+ public static final int BAND_25 = android.hardware.radio.V1_5.NgranBands.BAND_25;
+ public static final int BAND_28 = android.hardware.radio.V1_5.NgranBands.BAND_28;
+ public static final int BAND_29 = android.hardware.radio.V1_5.NgranBands.BAND_29;
+ public static final int BAND_30 = android.hardware.radio.V1_5.NgranBands.BAND_30;
+ public static final int BAND_34 = android.hardware.radio.V1_5.NgranBands.BAND_34;
+ public static final int BAND_38 = android.hardware.radio.V1_5.NgranBands.BAND_38;
+ public static final int BAND_39 = android.hardware.radio.V1_5.NgranBands.BAND_39;
+ public static final int BAND_40 = android.hardware.radio.V1_5.NgranBands.BAND_40;
+ public static final int BAND_41 = android.hardware.radio.V1_5.NgranBands.BAND_41;
+ public static final int BAND_48 = android.hardware.radio.V1_5.NgranBands.BAND_48;
+ public static final int BAND_50 = android.hardware.radio.V1_5.NgranBands.BAND_50;
+ public static final int BAND_51 = android.hardware.radio.V1_5.NgranBands.BAND_51;
+ public static final int BAND_65 = android.hardware.radio.V1_5.NgranBands.BAND_65;
+ public static final int BAND_66 = android.hardware.radio.V1_5.NgranBands.BAND_66;
+ public static final int BAND_70 = android.hardware.radio.V1_5.NgranBands.BAND_70;
+ public static final int BAND_71 = android.hardware.radio.V1_5.NgranBands.BAND_71;
+ public static final int BAND_74 = android.hardware.radio.V1_5.NgranBands.BAND_74;
+ public static final int BAND_75 = android.hardware.radio.V1_5.NgranBands.BAND_75;
+ public static final int BAND_76 = android.hardware.radio.V1_5.NgranBands.BAND_76;
+ public static final int BAND_77 = android.hardware.radio.V1_5.NgranBands.BAND_77;
+ public static final int BAND_78 = android.hardware.radio.V1_5.NgranBands.BAND_78;
+ public static final int BAND_79 = android.hardware.radio.V1_5.NgranBands.BAND_79;
+ public static final int BAND_80 = android.hardware.radio.V1_5.NgranBands.BAND_80;
+ public static final int BAND_81 = android.hardware.radio.V1_5.NgranBands.BAND_81;
+ public static final int BAND_82 = android.hardware.radio.V1_5.NgranBands.BAND_82;
+ public static final int BAND_83 = android.hardware.radio.V1_5.NgranBands.BAND_83;
+ public static final int BAND_84 = android.hardware.radio.V1_5.NgranBands.BAND_84;
+ public static final int BAND_86 = android.hardware.radio.V1_5.NgranBands.BAND_86;
+ public static final int BAND_90 = android.hardware.radio.V1_5.NgranBands.BAND_90;
/** FR2 bands */
- public static final int BAND_257 = 257;
- public static final int BAND_258 = 258;
- public static final int BAND_260 = 260;
- public static final int BAND_261 = 261;
+ public static final int BAND_257 = android.hardware.radio.V1_5.NgranBands.BAND_257;
+ public static final int BAND_258 = android.hardware.radio.V1_5.NgranBands.BAND_258;
+ public static final int BAND_260 = android.hardware.radio.V1_5.NgranBands.BAND_260;
+ public static final int BAND_261 = android.hardware.radio.V1_5.NgranBands.BAND_261;
/**
* NR Bands
diff --git a/telephony/java/android/telephony/CarrierConfigManager.java b/telephony/java/android/telephony/CarrierConfigManager.java
index c5c08c2ee668..2d31d9593643 100755
--- a/telephony/java/android/telephony/CarrierConfigManager.java
+++ b/telephony/java/android/telephony/CarrierConfigManager.java
@@ -4021,7 +4021,8 @@ public class CarrierConfigManager {
sDefaults.putBoolean(KEY_USE_CALLER_ID_USSD_BOOL, false);
sDefaults.putInt(KEY_CALL_WAITING_SERVICE_CLASS_INT, 1 /* SERVICE_CLASS_VOICE */);
sDefaults.putString(KEY_5G_ICON_CONFIGURATION_STRING,
- "connected_mmwave:5G,connected:5G");
+ "connected_mmwave:5G,connected:5G,not_restricted_rrc_idle:5G,"
+ + "not_restricted_rrc_con:5G");
sDefaults.putInt(KEY_5G_ICON_DISPLAY_GRACE_PERIOD_SEC_INT, 0);
/* Default value is 1 hour. */
sDefaults.putLong(KEY_5G_WATCHDOG_TIME_MS_LONG, 3600000);
diff --git a/telephony/java/android/telephony/CdmaEriInformation.java b/telephony/java/android/telephony/CdmaEriInformation.java
index 1cd9d3048526..fd0b905e9c3e 100644
--- a/telephony/java/android/telephony/CdmaEriInformation.java
+++ b/telephony/java/android/telephony/CdmaEriInformation.java
@@ -40,7 +40,6 @@ import java.lang.annotation.RetentionPolicy;
*
* @hide
*/
-@SystemApi
public final class CdmaEriInformation implements Parcelable {
/** @hide */
@Retention(RetentionPolicy.SOURCE)
diff --git a/telephony/java/android/telephony/ImsManager.java b/telephony/java/android/telephony/ImsManager.java
index d504b381d1a1..34bac5de4c43 100644
--- a/telephony/java/android/telephony/ImsManager.java
+++ b/telephony/java/android/telephony/ImsManager.java
@@ -34,8 +34,9 @@ public class ImsManager {
private Context mContext;
/**
- * <p>Broadcast Action: Indicates that an IMS operation was rejected by the network due to it
- * not being authorized on the network.
+ * <p>Broadcast Action: Indicates that a previously allowed IMS operation was rejected by the
+ * network due to the network returning a "forbidden" response. This may be due to a
+ * provisioning change from the network.
* May include the {@link SubscriptionManager#EXTRA_SUBSCRIPTION_INDEX} extra to also specify
* which subscription the operation was rejected for.
* <p class="note">
@@ -74,17 +75,17 @@ public class ImsManager {
"android.telephony.ims.action.WFC_IMS_REGISTRATION_ERROR";
/**
- * An extra key corresponding to a String value which contains the carrier specific title to be
- * displayed as part of the message shown to the user when there is an error registering for
- * WiFi calling.
+ * An extra key corresponding to a {@link CharSequence} value which contains the carrier
+ * specific title to be displayed as part of the message shown to the user when there is an
+ * error registering for WiFi calling.
*/
public static final String EXTRA_WFC_REGISTRATION_FAILURE_TITLE =
"android.telephony.ims.extra.WFC_REGISTRATION_FAILURE_TITLE";
/**
- * An extra key corresponding to a String value which contains the carrier specific message to
- * be displayed as part of the message shown to the user when there is an error registering for
- * WiFi calling.
+ * An extra key corresponding to a {@link CharSequence} value which contains the carrier
+ * specific message to be displayed as part of the message shown to the user when there is an
+ * error registering for WiFi calling.
*/
public static final String EXTRA_WFC_REGISTRATION_FAILURE_MESSAGE =
"android.telephony.ims.extra.WFC_REGISTRATION_FAILURE_MESSAGE";
diff --git a/telephony/java/android/telephony/ServiceState.java b/telephony/java/android/telephony/ServiceState.java
index 08614b95d7b0..9b1baef1a70a 100644
--- a/telephony/java/android/telephony/ServiceState.java
+++ b/telephony/java/android/telephony/ServiceState.java
@@ -1411,6 +1411,7 @@ public class ServiceState implements Parcelable {
DataSpecificRegistrationInfo dsri = nri.getDataSpecificInfo();
if (dsri != null) {
dsri.setIsUsingCarrierAggregation(ca);
+ addNetworkRegistrationInfo(nri);
}
}
}
diff --git a/telephony/java/android/telephony/SmsManager.java b/telephony/java/android/telephony/SmsManager.java
index 8479db64799c..d3afa4a133a6 100644
--- a/telephony/java/android/telephony/SmsManager.java
+++ b/telephony/java/android/telephony/SmsManager.java
@@ -2939,7 +2939,7 @@ public final class SmsManager {
/**
* Gets the premium SMS permission for the specified package. If the package has never
- * been seen before, the default {@link SmsManager#PREMIUM_SMS_PERMISSION_ASK_USER}
+ * been seen before, the default {@link SmsManager#PREMIUM_SMS_CONSENT_UNKNOWN}
* will be returned.
* @param packageName the name of the package to query permission
* @return one of {@link SmsManager#PREMIUM_SMS_CONSENT_UNKNOWN},
diff --git a/telephony/java/android/telephony/SmsMessage.java b/telephony/java/android/telephony/SmsMessage.java
index 37d3d32efc34..bc5cc9601e05 100644
--- a/telephony/java/android/telephony/SmsMessage.java
+++ b/telephony/java/android/telephony/SmsMessage.java
@@ -20,6 +20,7 @@ import static android.telephony.TelephonyManager.PHONE_TYPE_CDMA;
import android.Manifest;
import android.annotation.IntDef;
+import android.annotation.IntRange;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.annotation.RequiresPermission;
@@ -719,9 +720,9 @@ public class SmsMessage {
* 23.040 9.2.3.24.16
* @param languageShiftTable GSM national language shift table to use, specified by 3GPP
* 23.040 9.2.3.24.15
- * @param refNumber parameter to create SmsHeader
- * @param seqNumber parameter to create SmsHeader
- * @param msgCount parameter to create SmsHeader
+ * @param refNumber reference number of concatenated SMS, specified by 3GPP 23.040 9.2.3.24.1
+ * @param seqNumber sequence number of concatenated SMS, specified by 3GPP 23.040 9.2.3.24.1
+ * @param msgCount count of messages of concatenated SMS, specified by 3GPP 23.040 9.2.3.24.2
* @return a byte[] containing the encoded message
*
* @hide
@@ -730,11 +731,14 @@ public class SmsMessage {
@SystemApi
@NonNull
public static byte[] getSubmitPduEncodedMessage(boolean isTypeGsm,
- @NonNull String destinationAddress,
- @NonNull String message,
- @EncodingSize int encoding, int languageTable,
- int languageShiftTable, int refNumber,
- int seqNumber, int msgCount) {
+ @NonNull String destinationAddress,
+ @NonNull String message,
+ @EncodingSize int encoding,
+ @IntRange(from = 0) int languageTable,
+ @IntRange(from = 0) int languageShiftTable,
+ @IntRange(from = 0, to = 255) int refNumber,
+ @IntRange(from = 1, to = 255) int seqNumber,
+ @IntRange(from = 1, to = 255) int msgCount) {
byte[] data;
SmsHeader.ConcatRef concatRef = new SmsHeader.ConcatRef();
concatRef.refNumber = refNumber;
diff --git a/telephony/java/android/telephony/TelephonyManager.java b/telephony/java/android/telephony/TelephonyManager.java
index 67a2604ba9c7..23a2b9cae125 100644
--- a/telephony/java/android/telephony/TelephonyManager.java
+++ b/telephony/java/android/telephony/TelephonyManager.java
@@ -54,6 +54,7 @@ import android.os.Build;
import android.os.Bundle;
import android.os.Handler;
import android.os.IBinder;
+import android.os.ParcelFileDescriptor;
import android.os.PersistableBundle;
import android.os.Process;
import android.os.RemoteException;
@@ -333,21 +334,6 @@ public class TelephonyManager {
};
/** @hide */
- @IntDef(prefix = {"MODEM_COUNT_"},
- value = {
- MODEM_COUNT_NO_MODEM,
- MODEM_COUNT_SINGLE_MODEM,
- MODEM_COUNT_DUAL_MODEM,
- MODEM_COUNT_TRI_MODEM
- })
- public @interface ModemCount {}
-
- public static final int MODEM_COUNT_NO_MODEM = 0;
- public static final int MODEM_COUNT_SINGLE_MODEM = 1;
- public static final int MODEM_COUNT_DUAL_MODEM = 2;
- public static final int MODEM_COUNT_TRI_MODEM = 3;
-
- /** @hide */
@UnsupportedAppUsage
public TelephonyManager(Context context) {
this(context, SubscriptionManager.DEFAULT_SUBSCRIPTION_ID);
@@ -465,22 +451,22 @@ public class TelephonyManager {
* Returns 2 for Dual standby mode (Dual SIM functionality).
* Returns 3 for Tri standby mode (Tri SIM functionality).
*/
- public @ModemCount int getActiveModemCount() {
+ public int getActiveModemCount() {
int modemCount = 1;
switch (getMultiSimConfiguration()) {
case UNKNOWN:
- modemCount = MODEM_COUNT_SINGLE_MODEM;
+ modemCount = 1;
// check for voice and data support, 0 if not supported
if (!isVoiceCapable() && !isSmsCapable() && !isDataCapable()) {
- modemCount = MODEM_COUNT_NO_MODEM;
+ modemCount = 0;
}
break;
case DSDS:
case DSDA:
- modemCount = MODEM_COUNT_DUAL_MODEM;
+ modemCount = 2;
break;
case TSTS:
- modemCount = MODEM_COUNT_TRI_MODEM;
+ modemCount = 3;
break;
}
return modemCount;
@@ -493,7 +479,7 @@ public class TelephonyManager {
* dual-SIM capable device operating in single SIM mode (only one logical modem is turned on),
* {@link #getActiveModemCount} returns 1 while this API returns 2.
*/
- public @ModemCount int getSupportedModemCount() {
+ public int getSupportedModemCount() {
return TelephonyProperties.max_active_modems().orElse(getActiveModemCount());
}
@@ -2833,6 +2819,17 @@ public class TelephonyManager {
}
}
+ /**
+ * @hide
+ * @deprecated Use {@link #getNetworkCountryIso(int)} instead.
+ */
+ @Deprecated
+ @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.Q,
+ publicAlternatives = "Use {@link #getNetworkCountryIso(int)} instead.")
+ public String getNetworkCountryIsoForPhone(int phoneId) {
+ return getNetworkCountryIso(phoneId);
+ }
+
/*
* When adding a network type to the list below, make sure to add the correct icon to
* MobileSignalController.mapIconSets() as well as NETWORK_TYPES
@@ -5609,7 +5606,6 @@ public class TelephonyManager {
* @hide
*/
@RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE)
- @SystemApi
@NonNull
public CdmaEriInformation getCdmaEriInformation() {
return new CdmaEriInformation(
@@ -11652,11 +11648,9 @@ public class TelephonyManager {
}
/**
- * Override the file path for testing OTA emergency number database in a file partition.
+ * Override the file path for OTA emergency number database in a file partition.
*
- * @param otaFilePath The test OTA emergency number database file path;
- * if "RESET", recover the original database file partition.
- * Format: <root file folder>@<file path>
+ * @param otaParcelFileDescriptor parcelable file descriptor for OTA emergency number database.
*
* <p> Requires permission:
* {@link android.Manifest.permission#READ_ACTIVE_EMERGENCY_SESSION}
@@ -11666,16 +11660,42 @@ public class TelephonyManager {
@RequiresPermission(android.Manifest.permission.READ_ACTIVE_EMERGENCY_SESSION)
@SystemApi
@TestApi
- public void updateTestOtaEmergencyNumberDbFilePath(@NonNull String otaFilePath) {
+ public void updateOtaEmergencyNumberDbFilePath(
+ @NonNull ParcelFileDescriptor otaParcelFileDescriptor) {
try {
ITelephony telephony = getITelephony();
if (telephony != null) {
- telephony.updateTestOtaEmergencyNumberDbFilePath(otaFilePath);
+ telephony.updateOtaEmergencyNumberDbFilePath(otaParcelFileDescriptor);
} else {
throw new IllegalStateException("telephony service is null.");
}
} catch (RemoteException ex) {
- Log.e(TAG, "notifyOtaEmergencyNumberDatabaseInstalled RemoteException", ex);
+ Log.e(TAG, "updateOtaEmergencyNumberDbFilePath RemoteException", ex);
+ ex.rethrowAsRuntimeException();
+ }
+ }
+
+ /**
+ * Reset the file path to default for OTA emergency number database in a file partition.
+ *
+ * <p> Requires permission:
+ * {@link android.Manifest.permission#READ_ACTIVE_EMERGENCY_SESSION}
+ *
+ * @hide
+ */
+ @RequiresPermission(android.Manifest.permission.READ_ACTIVE_EMERGENCY_SESSION)
+ @SystemApi
+ @TestApi
+ public void resetOtaEmergencyNumberDbFilePath() {
+ try {
+ ITelephony telephony = getITelephony();
+ if (telephony != null) {
+ telephony.resetOtaEmergencyNumberDbFilePath();
+ } else {
+ throw new IllegalStateException("telephony service is null.");
+ }
+ } catch (RemoteException ex) {
+ Log.e(TAG, "resetOtaEmergencyNumberDbFilePath RemoteException", ex);
ex.rethrowAsRuntimeException();
}
}
@@ -12658,7 +12678,8 @@ public class TelephonyManager {
* {@hide}
*/
@SystemApi
- public boolean isCurrentSimOperator(@NonNull String mccmnc, @MvnoType int mvnoType,
+ @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE)
+ public boolean matchesCurrentSimOperator(@NonNull String mccmnc, @MvnoType int mvnoType,
@Nullable String mvnoMatchData) {
try {
if (!mccmnc.equals(getSimOperator())) {
diff --git a/telephony/java/android/telephony/ims/ImsCallProfile.java b/telephony/java/android/telephony/ims/ImsCallProfile.java
index 9c1be48e247a..1597cd5a2f89 100644
--- a/telephony/java/android/telephony/ims/ImsCallProfile.java
+++ b/telephony/java/android/telephony/ims/ImsCallProfile.java
@@ -18,7 +18,6 @@ package android.telephony.ims;
import android.annotation.IntDef;
import android.annotation.NonNull;
-import android.annotation.Nullable;
import android.annotation.SystemApi;
import android.annotation.TestApi;
import android.compat.annotation.UnsupportedAppUsage;
@@ -718,11 +717,16 @@ public final class ImsCallProfile implements Parcelable {
* @return A {@link Bundle} containing proprietary call extras that were not set by the
* platform.
*/
- public @Nullable Bundle getProprietaryCallExtras() {
+ public @NonNull Bundle getProprietaryCallExtras() {
if (mCallExtras == null) {
- return null;
+ return new Bundle();
+ }
+ Bundle proprietaryExtras = mCallExtras.getBundle(EXTRA_OEM_EXTRAS);
+ if (proprietaryExtras == null) {
+ return new Bundle();
}
- return mCallExtras.getBundle(EXTRA_OEM_EXTRAS);
+ // Make a copy so users do not accidentally change this copy of the extras.
+ return new Bundle(proprietaryExtras);
}
public ImsStreamMediaProfile getMediaProfile() {
diff --git a/telephony/java/android/telephony/ims/ImsCallSessionListener.java b/telephony/java/android/telephony/ims/ImsCallSessionListener.java
index 025721c89f70..81af99fb40b7 100644
--- a/telephony/java/android/telephony/ims/ImsCallSessionListener.java
+++ b/telephony/java/android/telephony/ims/ImsCallSessionListener.java
@@ -58,7 +58,7 @@ public class ImsCallSessionListener {
try {
mListener.callSessionProgressing(profile);
} catch (RemoteException e) {
- throw new RuntimeException(e);
+ e.rethrowFromSystemServer();
}
}
@@ -71,7 +71,7 @@ public class ImsCallSessionListener {
try {
mListener.callSessionInitiated(profile);
} catch (RemoteException e) {
- throw new RuntimeException(e);
+ e.rethrowFromSystemServer();
}
}
@@ -85,7 +85,7 @@ public class ImsCallSessionListener {
try {
mListener.callSessionInitiatedFailed(reasonInfo);
} catch (RemoteException e) {
- throw new RuntimeException(e);
+ e.rethrowFromSystemServer();
}
}
@@ -98,7 +98,7 @@ public class ImsCallSessionListener {
try {
mListener.callSessionTerminated(reasonInfo);
} catch (RemoteException e) {
- throw new RuntimeException(e);
+ e.rethrowFromSystemServer();
}
}
@@ -115,7 +115,7 @@ public class ImsCallSessionListener {
try {
mListener.callSessionHeld(profile);
} catch (RemoteException e) {
- throw new RuntimeException(e);
+ e.rethrowFromSystemServer();
}
}
@@ -128,7 +128,7 @@ public class ImsCallSessionListener {
try {
mListener.callSessionHoldFailed(reasonInfo);
} catch (RemoteException e) {
- throw new RuntimeException(e);
+ e.rethrowFromSystemServer();
}
}
@@ -141,7 +141,7 @@ public class ImsCallSessionListener {
try {
mListener.callSessionHoldReceived(profile);
} catch (RemoteException e) {
- throw new RuntimeException(e);
+ e.rethrowFromSystemServer();
}
}
@@ -155,7 +155,7 @@ public class ImsCallSessionListener {
try {
mListener.callSessionResumed(profile);
} catch (RemoteException e) {
- throw new RuntimeException(e);
+ e.rethrowFromSystemServer();
}
}
@@ -169,7 +169,7 @@ public class ImsCallSessionListener {
try {
mListener.callSessionResumeFailed(reasonInfo);
} catch (RemoteException e) {
- throw new RuntimeException(e);
+ e.rethrowFromSystemServer();
}
}
@@ -182,7 +182,7 @@ public class ImsCallSessionListener {
try {
mListener.callSessionResumeReceived(profile);
} catch (RemoteException e) {
- throw new RuntimeException(e);
+ e.rethrowFromSystemServer();
}
}
@@ -201,7 +201,7 @@ public class ImsCallSessionListener {
mListener.callSessionMergeStarted(newSession != null ?
newSession.getServiceImpl() : null, profile);
} catch (RemoteException e) {
- throw new RuntimeException(e);
+ e.rethrowFromSystemServer();
}
}
@@ -216,7 +216,7 @@ public class ImsCallSessionListener {
try {
mListener.callSessionMergeStarted(newSession, profile);
} catch (RemoteException e) {
- throw new RuntimeException(e);
+ e.rethrowFromSystemServer();
}
}
@@ -232,7 +232,7 @@ public class ImsCallSessionListener {
mListener.callSessionMergeComplete(newSession != null ?
newSession.getServiceImpl() : null);
} catch (RemoteException e) {
- throw new RuntimeException(e);
+ e.rethrowFromSystemServer();
}
}
@@ -247,7 +247,7 @@ public class ImsCallSessionListener {
try {
mListener.callSessionMergeComplete(newSession);
} catch (RemoteException e) {
- throw new RuntimeException(e);
+ e.rethrowFromSystemServer();
}
}
@@ -260,7 +260,7 @@ public class ImsCallSessionListener {
try {
mListener.callSessionMergeFailed(reasonInfo);
} catch (RemoteException e) {
- throw new RuntimeException(e);
+ e.rethrowFromSystemServer();
}
}
@@ -273,7 +273,7 @@ public class ImsCallSessionListener {
try {
mListener.callSessionUpdated(profile);
} catch (RemoteException e) {
- throw new RuntimeException(e);
+ e.rethrowFromSystemServer();
}
}
@@ -286,7 +286,7 @@ public class ImsCallSessionListener {
try {
mListener.callSessionUpdateFailed(reasonInfo);
} catch (RemoteException e) {
- throw new RuntimeException(e);
+ e.rethrowFromSystemServer();
}
}
@@ -299,7 +299,7 @@ public class ImsCallSessionListener {
try {
mListener.callSessionUpdateReceived(profile);
} catch (RemoteException e) {
- throw new RuntimeException(e);
+ e.rethrowFromSystemServer();
}
}
@@ -319,7 +319,7 @@ public class ImsCallSessionListener {
mListener.callSessionConferenceExtended(
newSession != null ? newSession.getServiceImpl() : null, profile);
} catch (RemoteException e) {
- throw new RuntimeException(e);
+ e.rethrowFromSystemServer();
}
}
@@ -333,7 +333,7 @@ public class ImsCallSessionListener {
try {
mListener.callSessionConferenceExtended(newSession, profile);
} catch (RemoteException e) {
- throw new RuntimeException(e);
+ e.rethrowFromSystemServer();
}
}
@@ -347,7 +347,7 @@ public class ImsCallSessionListener {
try {
mListener.callSessionConferenceExtendFailed(reasonInfo);
} catch (RemoteException e) {
- throw new RuntimeException(e);
+ e.rethrowFromSystemServer();
}
}
@@ -364,7 +364,7 @@ public class ImsCallSessionListener {
mListener.callSessionConferenceExtendReceived(newSession != null
? newSession.getServiceImpl() : null, profile);
} catch (RemoteException e) {
- throw new RuntimeException(e);
+ e.rethrowFromSystemServer();
}
}
@@ -379,7 +379,7 @@ public class ImsCallSessionListener {
try {
mListener.callSessionConferenceExtendReceived(newSession, profile);
} catch (RemoteException e) {
- throw new RuntimeException(e);
+ e.rethrowFromSystemServer();
}
}
@@ -391,7 +391,7 @@ public class ImsCallSessionListener {
try {
mListener.callSessionInviteParticipantsRequestDelivered();
} catch (RemoteException e) {
- throw new RuntimeException(e);
+ e.rethrowFromSystemServer();
}
}
@@ -407,7 +407,7 @@ public class ImsCallSessionListener {
try {
mListener.callSessionInviteParticipantsRequestFailed(reasonInfo);
} catch (RemoteException e) {
- throw new RuntimeException(e);
+ e.rethrowFromSystemServer();
}
}
@@ -419,7 +419,7 @@ public class ImsCallSessionListener {
try {
mListener.callSessionRemoveParticipantsRequestDelivered();
} catch (RemoteException e) {
- throw new RuntimeException(e);
+ e.rethrowFromSystemServer();
}
}
@@ -435,7 +435,7 @@ public class ImsCallSessionListener {
try {
mListener.callSessionInviteParticipantsRequestFailed(reasonInfo);
} catch (RemoteException e) {
- throw new RuntimeException(e);
+ e.rethrowFromSystemServer();
}
}
@@ -448,7 +448,7 @@ public class ImsCallSessionListener {
try {
mListener.callSessionConferenceStateUpdated(state);
} catch (RemoteException e) {
- throw new RuntimeException(e);
+ e.rethrowFromSystemServer();
}
}
@@ -465,7 +465,7 @@ public class ImsCallSessionListener {
try {
mListener.callSessionUssdMessageReceived(mode, ussdMessage);
} catch (RemoteException e) {
- throw new RuntimeException(e);
+ e.rethrowFromSystemServer();
}
}
@@ -501,7 +501,7 @@ public class ImsCallSessionListener {
try {
mListener.callSessionMayHandover(srcNetworkType, targetNetworkType);
} catch (RemoteException e) {
- throw new RuntimeException(e);
+ e.rethrowFromSystemServer();
}
}
@@ -537,7 +537,7 @@ public class ImsCallSessionListener {
try {
mListener.callSessionHandover(srcNetworkType, targetNetworkType, reasonInfo);
} catch (RemoteException e) {
- throw new RuntimeException(e);
+ e.rethrowFromSystemServer();
}
}
@@ -570,7 +570,7 @@ public class ImsCallSessionListener {
try {
mListener.callSessionHandoverFailed(srcNetworkType, targetNetworkType, reasonInfo);
} catch (RemoteException e) {
- throw new RuntimeException(e);
+ e.rethrowFromSystemServer();
}
}
@@ -587,7 +587,7 @@ public class ImsCallSessionListener {
try {
mListener.callSessionTtyModeReceived(mode);
} catch (RemoteException e) {
- throw new RuntimeException(e);
+ e.rethrowFromSystemServer();
}
}
@@ -600,7 +600,7 @@ public class ImsCallSessionListener {
try {
mListener.callSessionMultipartyStateChanged(isMultiParty);
} catch (RemoteException e) {
- throw new RuntimeException(e);
+ e.rethrowFromSystemServer();
}
}
@@ -614,7 +614,7 @@ public class ImsCallSessionListener {
try {
mListener.callSessionSuppServiceReceived(suppSrvNotification);
} catch (RemoteException e) {
- throw new RuntimeException(e);
+ e.rethrowFromSystemServer();
}
}
@@ -628,7 +628,7 @@ public class ImsCallSessionListener {
try {
mListener.callSessionRttModifyRequestReceived(callProfile);
} catch (RemoteException e) {
- throw new RuntimeException(e);
+ e.rethrowFromSystemServer();
}
}
@@ -641,7 +641,7 @@ public class ImsCallSessionListener {
try {
mListener.callSessionRttModifyResponseReceived(status);
} catch (RemoteException e) {
- throw new RuntimeException(e);
+ e.rethrowFromSystemServer();
}
}
@@ -654,7 +654,7 @@ public class ImsCallSessionListener {
try {
mListener.callSessionRttMessageReceived(rttMessage);
} catch (RemoteException e) {
- throw new RuntimeException(e);
+ e.rethrowFromSystemServer();
}
}
@@ -667,7 +667,7 @@ public class ImsCallSessionListener {
try {
mListener.callSessionRttAudioIndicatorChanged(profile);
} catch (RemoteException e) {
- throw new RuntimeException(e);
+ e.rethrowFromSystemServer();
}
}
@@ -680,7 +680,7 @@ public class ImsCallSessionListener {
try {
mListener.callQualityChanged(callQuality);
} catch (RemoteException e) {
- throw new RuntimeException(e);
+ e.rethrowFromSystemServer();
}
}
}
diff --git a/telephony/java/android/telephony/ims/ImsUtListener.java b/telephony/java/android/telephony/ims/ImsUtListener.java
index bc12404461c7..460a032ce7e0 100644
--- a/telephony/java/android/telephony/ims/ImsUtListener.java
+++ b/telephony/java/android/telephony/ims/ImsUtListener.java
@@ -49,7 +49,8 @@ public class ImsUtListener {
* {@link ImsSsInfo#CLIR_STATUS_TEMPORARILY_RESTRICTED}, and
* {@link ImsSsInfo#CLIR_STATUS_TEMPORARILY_ALLOWED}.
* @deprecated Use {@link #onLineIdentificationSupplementaryServiceResponse(int, ImsSsInfo)}
- * instead.
+ * instead, this key has been added for backwards compatibility with older proprietary
+ * implementations only and is being phased out.
*/
@Deprecated
public static final String BUNDLE_KEY_CLIR = "queryClir";
@@ -60,7 +61,8 @@ public class ImsUtListener {
* response. The value will be an instance of {@link ImsSsInfo}, which contains the response to
* the query.
* @deprecated Use {@link #onLineIdentificationSupplementaryServiceResponse(int, ImsSsInfo)}
- * instead.
+ * instead, this key has been added for backwards compatibility with older proprietary
+ * implementations only and is being phased out.
*/
@Deprecated
public static final String BUNDLE_KEY_SSINFO = "imsSsInfo";
@@ -123,7 +125,7 @@ public class ImsUtListener {
try {
mServiceInterface.lineIdentificationSupplementaryServiceResponse(id, configuration);
} catch (RemoteException e) {
- Log.w(LOG_TAG, "onLineIdentificationSupplementaryServicesResponse: remote exception");
+ e.rethrowFromSystemServer();
}
}
diff --git a/telephony/java/android/telephony/ims/ProvisioningManager.java b/telephony/java/android/telephony/ims/ProvisioningManager.java
index 037084608d26..00fa94201297 100644
--- a/telephony/java/android/telephony/ims/ProvisioningManager.java
+++ b/telephony/java/android/telephony/ims/ProvisioningManager.java
@@ -305,13 +305,13 @@ public class ProvisioningManager {
/**
* An integer key associated with the carrier configured expiration time in seconds for
- * RCS presence published offline availability in RCS presence.
+ * published offline availability in RCS presence provided, which is provided to the network.
* <p>
* Value is in Integer format.
* @see #setProvisioningIntValue(int, int)
* @see #getProvisioningIntValue(int)
*/
- public static final int KEY_RCS_PUBLISH_TIMER_EXTENDED_SEC = 16;
+ public static final int KEY_RCS_PUBLISH_OFFLINE_AVAILABILITY_TIMER_SEC = 16;
/**
* An integer key associated with whether or not capability discovery is provisioned for this
@@ -326,8 +326,10 @@ public class ProvisioningManager {
public static final int KEY_RCS_CAPABILITY_DISCOVERY_ENABLED = 17;
/**
- * An integer key associated with the period of time the capability information of each contact
- * is cached on the device.
+ * An integer key associated with the period of time in seconds the capability information of
+ * each contact is cached on the device.
+ * <p>
+ * Seconds are used because this is usually measured in the span of days.
* <p>
* Value is in Integer format.
* @see #setProvisioningIntValue(int, int)
@@ -337,7 +339,8 @@ public class ProvisioningManager {
/**
* An integer key associated with the period of time in seconds that the availability
- * information of a contact is cached on the device.
+ * information of a contact is cached on the device, which is based on the carrier provisioning
+ * configuration from the network.
* <p>
* Value is in Integer format.
* @see #setProvisioningIntValue(int, int)
@@ -347,7 +350,8 @@ public class ProvisioningManager {
/**
* An integer key associated with the carrier configured interval in seconds expected between
- * successive capability polling attempts.
+ * successive capability polling attempts, which is based on the carrier provisioning
+ * configuration from the network.
* <p>
* Value is in Integer format.
* @see #setProvisioningIntValue(int, int)
@@ -357,7 +361,7 @@ public class ProvisioningManager {
/**
* An integer key representing the minimum time allowed between two consecutive presence publish
- * messages from the device.
+ * messages from the device in milliseconds.
* <p>
* Value is in Integer format.
* @see #setProvisioningIntValue(int, int)
@@ -378,7 +382,7 @@ public class ProvisioningManager {
/**
* An integer associated with the expiration timer used during the SIP subscription of a
* Request Contained List (RCL), which is used to retrieve the RCS capabilities of the contact
- * book.
+ * book. This timer value is sent in seconds to the network.
* <p>
* Value is in Integer format.
* @see #setProvisioningIntValue(int, int)
@@ -470,7 +474,8 @@ public class ProvisioningManager {
public static final int KEY_SIP_KEEP_ALIVE_ENABLED = 32;
/**
- * Registration retry Base Time value in seconds.
+ * Registration retry Base Time value in seconds, which is based off of the carrier
+ * configuration.
* Value is in Integer format.
* @see #setProvisioningIntValue(int, int)
* @see #getProvisioningIntValue(int)
@@ -478,7 +483,8 @@ public class ProvisioningManager {
public static final int KEY_REGISTRATION_RETRY_BASE_TIME_SEC = 33;
/**
- * Registration retry Max Time value in seconds.
+ * Registration retry Max Time value in seconds, which is based off of the carrier
+ * configuration.
* Value is in Integer format.
* @see #setProvisioningIntValue(int, int)
* @see #getProvisioningIntValue(int)
diff --git a/telephony/java/android/telephony/ims/RcsUceAdapter.java b/telephony/java/android/telephony/ims/RcsUceAdapter.java
index 58e9b7008050..30306c7f9dea 100644
--- a/telephony/java/android/telephony/ims/RcsUceAdapter.java
+++ b/telephony/java/android/telephony/ims/RcsUceAdapter.java
@@ -24,12 +24,10 @@ import android.annotation.RequiresPermission;
import android.annotation.SystemApi;
import android.annotation.TestApi;
import android.content.Context;
-import android.database.ContentObserver;
import android.net.Uri;
import android.os.Binder;
import android.os.IBinder;
import android.os.RemoteException;
-import android.provider.Telephony;
import android.telephony.TelephonyFrameworkInitializer;
import android.telephony.ims.aidl.IImsRcsController;
import android.telephony.ims.aidl.IRcsUceControllerCallback;
@@ -138,7 +136,7 @@ public class RcsUceAdapter {
* UCE.
* @hide
*/
- public static final int PUBLISH_STATE_200_OK = 1;
+ public static final int PUBLISH_STATE_OK = 1;
/**
* The hasn't published its capabilities since boot or hasn't gotten any publish response yet.
@@ -178,7 +176,7 @@ public class RcsUceAdapter {
/**@hide*/
@Retention(RetentionPolicy.SOURCE)
@IntDef(prefix = "PUBLISH_STATE_", value = {
- PUBLISH_STATE_200_OK,
+ PUBLISH_STATE_OK,
PUBLISH_STATE_NOT_PUBLISHED,
PUBLISH_STATE_VOLTE_PROVISION_ERROR,
PUBLISH_STATE_RCS_PROVISION_ERROR,
@@ -305,7 +303,7 @@ public class RcsUceAdapter {
* Gets the last publish result from the UCE service if the device is using an RCS presence
* server.
* @return The last publish result from the UCE service. If the device is using SIP OPTIONS,
- * this method will return {@link #PUBLISH_STATE_200_OK} as well.
+ * this method will return {@link #PUBLISH_STATE_OK} as well.
* @throws ImsException if the subscription associated with this instance of
* {@link RcsUceAdapter} is valid, but the ImsService associated with the subscription is not
* available. This can happen if the ImsService has crashed, for example, or if the subscription
diff --git a/telephony/java/com/android/ims/ImsConfig.java b/telephony/java/com/android/ims/ImsConfig.java
index 96f77d809183..d0cec52dfc86 100644
--- a/telephony/java/com/android/ims/ImsConfig.java
+++ b/telephony/java/com/android/ims/ImsConfig.java
@@ -270,11 +270,12 @@ public class ImsConfig {
/**
* Requested expiration for Published Offline availability.
* Value is in Integer format.
- * @deprecated use {@link ProvisioningManager#KEY_RCS_PUBLISH_TIMER_EXTENDED_SEC}.
+ * @deprecated use
+ * {@link ProvisioningManager#KEY_RCS_PUBLISH_OFFLINE_AVAILABILITY_TIMER_SEC}.
*/
@Deprecated
public static final int PUBLISH_TIMER_EXTENDED =
- ProvisioningManager.KEY_RCS_PUBLISH_TIMER_EXTENDED_SEC;
+ ProvisioningManager.KEY_RCS_PUBLISH_OFFLINE_AVAILABILITY_TIMER_SEC;
/**
*
diff --git a/telephony/java/com/android/internal/telephony/ITelephony.aidl b/telephony/java/com/android/internal/telephony/ITelephony.aidl
index af5089f8e0d9..dcf339c1be2f 100644
--- a/telephony/java/com/android/internal/telephony/ITelephony.aidl
+++ b/telephony/java/com/android/internal/telephony/ITelephony.aidl
@@ -22,6 +22,7 @@ import android.content.IntentSender;
import android.os.Bundle;
import android.os.IBinder;
import android.os.Messenger;
+import android.os.ParcelFileDescriptor;
import android.os.ResultReceiver;
import android.os.WorkSource;
import android.net.NetworkStats;
@@ -2121,9 +2122,14 @@ interface ITelephony {
void notifyOtaEmergencyNumberDbInstalled();
/**
- * Override the file partition name for testing OTA emergency number database.
+ * Override a customized file partition name for OTA emergency number database.
*/
- void updateTestOtaEmergencyNumberDbFilePath(String otaFilePath);
+ void updateOtaEmergencyNumberDbFilePath(in ParcelFileDescriptor otaParcelFileDescriptor);
+
+ /**
+ * Reset file partition to default for OTA emergency number database.
+ */
+ void resetOtaEmergencyNumberDbFilePath();
/**
* Enable or disable a logical modem stack associated with the slotIndex.
diff --git a/tests/BootImageProfileTest/src/com/android/bootimageprofile/BootImageProfileTest.java b/tests/BootImageProfileTest/src/com/android/bootimageprofile/BootImageProfileTest.java
index 61f3dbaff1a3..4ecca2dc4c39 100644
--- a/tests/BootImageProfileTest/src/com/android/bootimageprofile/BootImageProfileTest.java
+++ b/tests/BootImageProfileTest/src/com/android/bootimageprofile/BootImageProfileTest.java
@@ -78,13 +78,12 @@ public class BootImageProfileTest implements IDeviceTest {
return false;
}
String res = mTestDevice.executeShellCommand("kill -s SIGUSR1 " + pid).trim();
- assertTrue("kill SIGUSR1: " + res, res.length() == 0);
- return true;
+ return res.length() == 0;
}
@Test
public void testSystemServerProfile() throws Exception {
- final int numIterations = 20;
+ final int numIterations = 30;
String res;
// Set properties and wait for them to be readable.
for (int i = 1; i <= numIterations; ++i) {
diff --git a/tests/Codegen/src/com/android/codegentest/HierrarchicalDataClassBase.java b/tests/Codegen/src/com/android/codegentest/HierrarchicalDataClassBase.java
index 339df93bbca7..475305eb83a2 100644
--- a/tests/Codegen/src/com/android/codegentest/HierrarchicalDataClassBase.java
+++ b/tests/Codegen/src/com/android/codegentest/HierrarchicalDataClassBase.java
@@ -32,7 +32,7 @@ public class HierrarchicalDataClassBase implements Parcelable {
- // Code below generated by codegen v1.0.14.
+ // Code below generated by codegen v1.0.15.
//
// DO NOT MODIFY!
// CHECKSTYLE:OFF Generated code
@@ -51,7 +51,7 @@ public class HierrarchicalDataClassBase implements Parcelable {
}
@DataClass.Generated.Member
- public HierrarchicalDataClassBase setBaseData(int value) {
+ public HierrarchicalDataClassBase setBaseData( int value) {
mBaseData = value;
return this;
}
@@ -98,8 +98,8 @@ public class HierrarchicalDataClassBase implements Parcelable {
};
@DataClass.Generated(
- time = 1574122837821L,
- codegenVersion = "1.0.14",
+ time = 1582685650576L,
+ codegenVersion = "1.0.15",
sourceFile = "frameworks/base/tests/Codegen/src/com/android/codegentest/HierrarchicalDataClassBase.java",
inputSignatures = "private int mBaseData\nclass HierrarchicalDataClassBase extends java.lang.Object implements [android.os.Parcelable]\n@com.android.internal.util.DataClass(genConstructor=false, genSetters=true)")
@Deprecated
diff --git a/tests/Codegen/src/com/android/codegentest/HierrarchicalDataClassChild.java b/tests/Codegen/src/com/android/codegentest/HierrarchicalDataClassChild.java
index 69e06b21ce5e..150b324d1a30 100644
--- a/tests/Codegen/src/com/android/codegentest/HierrarchicalDataClassChild.java
+++ b/tests/Codegen/src/com/android/codegentest/HierrarchicalDataClassChild.java
@@ -46,7 +46,7 @@ public class HierrarchicalDataClassChild extends HierrarchicalDataClassBase {
- // Code below generated by codegen v1.0.14.
+ // Code below generated by codegen v1.0.15.
//
// DO NOT MODIFY!
// CHECKSTYLE:OFF Generated code
@@ -120,8 +120,8 @@ public class HierrarchicalDataClassChild extends HierrarchicalDataClassBase {
};
@DataClass.Generated(
- time = 1574122838768L,
- codegenVersion = "1.0.14",
+ time = 1582685651560L,
+ codegenVersion = "1.0.15",
sourceFile = "frameworks/base/tests/Codegen/src/com/android/codegentest/HierrarchicalDataClassChild.java",
inputSignatures = "private @android.annotation.NonNull java.lang.String mChildData\nclass HierrarchicalDataClassChild extends com.android.codegentest.HierrarchicalDataClassBase implements []\n@com.android.internal.util.DataClass(genParcelable=true, genConstructor=false, genSetters=true)")
@Deprecated
diff --git a/tests/Codegen/src/com/android/codegentest/ParcelAllTheThingsDataClass.java b/tests/Codegen/src/com/android/codegentest/ParcelAllTheThingsDataClass.java
index ca128beb53d9..30871566c269 100644
--- a/tests/Codegen/src/com/android/codegentest/ParcelAllTheThingsDataClass.java
+++ b/tests/Codegen/src/com/android/codegentest/ParcelAllTheThingsDataClass.java
@@ -54,7 +54,7 @@ public class ParcelAllTheThingsDataClass implements Parcelable {
- // Code below generated by codegen v1.0.14.
+ // Code below generated by codegen v1.0.15.
//
// DO NOT MODIFY!
// CHECKSTYLE:OFF Generated code
@@ -355,7 +355,7 @@ public class ParcelAllTheThingsDataClass implements Parcelable {
}
@DataClass.Generated.Member
- public @NonNull Builder setNullableBoolean(@SuppressWarnings({ "WeakerAccess" }) @Nullable Boolean value) {
+ public @NonNull Builder setNullableBoolean(@SuppressWarnings({ "WeakerAccess" }) @NonNull Boolean value) {
checkNotUsed();
mBuilderFieldsSet |= 0x80;
mNullableBoolean = value;
@@ -412,8 +412,8 @@ public class ParcelAllTheThingsDataClass implements Parcelable {
}
@DataClass.Generated(
- time = 1574122836960L,
- codegenVersion = "1.0.14",
+ time = 1582685649678L,
+ codegenVersion = "1.0.15",
sourceFile = "frameworks/base/tests/Codegen/src/com/android/codegentest/ParcelAllTheThingsDataClass.java",
inputSignatures = " @android.annotation.NonNull java.lang.String[] mStringArray\n @android.annotation.NonNull int[] mIntArray\n @android.annotation.NonNull java.util.List<java.lang.String> mStringList\n @android.annotation.NonNull java.util.Map<java.lang.String,com.android.codegentest.SampleWithCustomBuilder> mMap\n @android.annotation.NonNull java.util.Map<java.lang.String,java.lang.String> mStringMap\n @android.annotation.NonNull android.util.SparseArray<com.android.codegentest.SampleWithCustomBuilder> mSparseArray\n @android.annotation.NonNull android.util.SparseIntArray mSparseIntArray\n @java.lang.SuppressWarnings({\"WeakerAccess\"}) @android.annotation.Nullable java.lang.Boolean mNullableBoolean\nclass ParcelAllTheThingsDataClass extends java.lang.Object implements [android.os.Parcelable]\n@com.android.internal.util.DataClass(genBuilder=true, genAidl=false, genToString=true)")
@Deprecated
diff --git a/tests/Codegen/src/com/android/codegentest/SampleDataClass.java b/tests/Codegen/src/com/android/codegentest/SampleDataClass.java
index c850bf8002c0..8d421bfa492a 100644
--- a/tests/Codegen/src/com/android/codegentest/SampleDataClass.java
+++ b/tests/Codegen/src/com/android/codegentest/SampleDataClass.java
@@ -342,7 +342,7 @@ public final class SampleDataClass implements Parcelable {
- // Code below generated by codegen v1.0.14.
+ // Code below generated by codegen v1.0.15.
//
// DO NOT MODIFY!
// CHECKSTYLE:OFF Generated code
@@ -512,7 +512,7 @@ public final class SampleDataClass implements Parcelable {
@Nullable LinkAddress[] linkAddresses5,
@StringRes int stringRes,
@android.annotation.IntRange(from = 0, to = 6) int dayOfWeek,
- @Size(2) @NonNull @Each @FloatRange(from = 0f) float[] coords) {
+ @Size(2) @NonNull @FloatRange(from = 0f) float[] coords) {
this.mNum = num;
this.mNum2 = num2;
this.mNum4 = num4;
@@ -790,7 +790,7 @@ public final class SampleDataClass implements Parcelable {
* @see AnnotationValidations#validate(Class, Size, int, String, int)
*/
@DataClass.Generated.Member
- public @Size(2) @NonNull @Each @FloatRange(from = 0f) float[] getCoords() {
+ public @Size(2) @NonNull @FloatRange(from = 0f) float[] getCoords() {
return mCoords;
}
@@ -820,7 +820,7 @@ public final class SampleDataClass implements Parcelable {
* pieces in multiple places for each field.
*/
@DataClass.Generated.Member
- public SampleDataClass setNum(int value) {
+ public SampleDataClass setNum( int value) {
mNum = value;
return this;
}
@@ -832,7 +832,7 @@ public final class SampleDataClass implements Parcelable {
* @see #mNum2 ..and so should blocks at the bottom, e.g. {@code @see} blocks.
*/
@DataClass.Generated.Member
- public SampleDataClass setNum2(int value) {
+ public SampleDataClass setNum2( int value) {
mNum2 = value;
return this;
}
@@ -846,7 +846,7 @@ public final class SampleDataClass implements Parcelable {
* @hide
*/
@DataClass.Generated.Member
- public SampleDataClass setNum4(int value) {
+ public SampleDataClass setNum4( int value) {
mNum4 = value;
return this;
}
@@ -855,7 +855,7 @@ public final class SampleDataClass implements Parcelable {
* {@link Nullable} or {@link NonNull} annotation is required on all non-primitive fields.
*/
@DataClass.Generated.Member
- public SampleDataClass setName(@Nullable String value) {
+ public SampleDataClass setName(@NonNull String value) {
mName = value;
return this;
}
@@ -892,7 +892,7 @@ public final class SampleDataClass implements Parcelable {
* E.g. {@link Parcelable} subclasses, {@link String}, {@link int}, {@link boolean}, etc.
*/
@DataClass.Generated.Member
- public SampleDataClass setOtherParcelable(@Nullable AccessibilityNodeInfo value) {
+ public SampleDataClass setOtherParcelable(@NonNull AccessibilityNodeInfo value) {
mOtherParcelable = value;
return this;
}
@@ -957,7 +957,7 @@ public final class SampleDataClass implements Parcelable {
* @see Builder#setLinkAddresses4(LinkAddress...)
*/
@DataClass.Generated.Member
- public SampleDataClass setLinkAddresses4(@Nullable LinkAddress... value) {
+ public SampleDataClass setLinkAddresses4(@NonNull LinkAddress... value) {
mLinkAddresses4 = value;
return this;
}
@@ -1070,7 +1070,7 @@ public final class SampleDataClass implements Parcelable {
* @see AnnotationValidations#validate(Class, Size, int, String, int)
*/
@DataClass.Generated.Member
- public SampleDataClass setCoords(@Size(2) @NonNull @Each @FloatRange(from = 0f) float... value) {
+ public SampleDataClass setCoords(@Size(2) @NonNull @FloatRange(from = 0f) float... value) {
mCoords = value;
AnnotationValidations.validate(
Size.class, null, mCoords.length,
@@ -1451,7 +1451,7 @@ public final class SampleDataClass implements Parcelable {
private @Nullable LinkAddress[] mLinkAddresses5;
private @StringRes int mStringRes;
private @android.annotation.IntRange(from = 0, to = 6) int mDayOfWeek;
- private @Size(2) @NonNull @Each @FloatRange(from = 0f) float[] mCoords;
+ private @Size(2) @NonNull @FloatRange(from = 0f) float[] mCoords;
private long mBuilderFieldsSet = 0L;
@@ -1549,7 +1549,7 @@ public final class SampleDataClass implements Parcelable {
* {@link Nullable} or {@link NonNull} annotation is required on all non-primitive fields.
*/
@DataClass.Generated.Member
- public @NonNull Builder setName(@Nullable String value) {
+ public @NonNull Builder setName(@NonNull String value) {
checkNotUsed();
mBuilderFieldsSet |= 0x8;
mName = value;
@@ -1588,7 +1588,7 @@ public final class SampleDataClass implements Parcelable {
* E.g. {@link Parcelable} subclasses, {@link String}, {@link int}, {@link boolean}, etc.
*/
@DataClass.Generated.Member
- public @NonNull Builder setOtherParcelable(@Nullable AccessibilityNodeInfo value) {
+ public @NonNull Builder setOtherParcelable(@NonNull AccessibilityNodeInfo value) {
checkNotUsed();
mBuilderFieldsSet |= 0x40;
mOtherParcelable = value;
@@ -1674,7 +1674,7 @@ public final class SampleDataClass implements Parcelable {
* @see Builder#setLinkAddresses4(LinkAddress...)
*/
@DataClass.Generated.Member
- public @NonNull Builder setLinkAddresses4(@Nullable LinkAddress... value) {
+ public @NonNull Builder setLinkAddresses4(@NonNull LinkAddress... value) {
checkNotUsed();
mBuilderFieldsSet |= 0x800;
mLinkAddresses4 = value;
@@ -1733,7 +1733,7 @@ public final class SampleDataClass implements Parcelable {
* Final fields suppress generating a setter (when setters are requested).
*/
@DataClass.Generated.Member
- public @NonNull Builder setLinkAddresses5(@Nullable LinkAddress... value) {
+ public @NonNull Builder setLinkAddresses5(@NonNull LinkAddress... value) {
checkNotUsed();
mBuilderFieldsSet |= 0x10000;
mLinkAddresses5 = value;
@@ -1785,7 +1785,7 @@ public final class SampleDataClass implements Parcelable {
* @see AnnotationValidations#validate(Class, Size, int, String, int)
*/
@DataClass.Generated.Member
- public @NonNull Builder setCoords(@Size(2) @NonNull @Each @FloatRange(from = 0f) float... value) {
+ public @NonNull Builder setCoords(@Size(2) @NonNull @FloatRange(from = 0f) float... value) {
checkNotUsed();
mBuilderFieldsSet |= 0x80000;
mCoords = value;
@@ -1872,8 +1872,8 @@ public final class SampleDataClass implements Parcelable {
}
@DataClass.Generated(
- time = 1574122835009L,
- codegenVersion = "1.0.14",
+ time = 1582685647656L,
+ codegenVersion = "1.0.15",
sourceFile = "frameworks/base/tests/Codegen/src/com/android/codegentest/SampleDataClass.java",
inputSignatures = "public static final java.lang.String STATE_NAME_UNDEFINED\npublic static final java.lang.String STATE_NAME_ON\npublic static final java.lang.String STATE_NAME_OFF\npublic static final int STATE_UNDEFINED\npublic static final int STATE_ON\npublic static final int STATE_OFF\npublic static final @com.android.codegentest.SampleDataClass.RequestFlags int FLAG_MANUAL_REQUEST\npublic static final @com.android.codegentest.SampleDataClass.RequestFlags int FLAG_COMPATIBILITY_MODE_REQUEST\npublic static final @com.android.codegentest.SampleDataClass.RequestFlags int FLAG_AUGMENTED_REQUEST\nprivate int mNum\nprivate int mNum2\nprivate int mNum4\nprivate @android.annotation.Nullable java.lang.String mName\nprivate @android.annotation.NonNull java.lang.String mName2\nprivate @android.annotation.NonNull java.lang.String mName4\nprivate @android.annotation.Nullable android.view.accessibility.AccessibilityNodeInfo mOtherParcelable\nprivate @com.android.internal.util.DataClass.ParcelWith(com.android.codegentest.MyDateParcelling.class) @android.annotation.NonNull java.util.Date mDate\nprivate @com.android.internal.util.DataClass.ParcelWith(com.android.internal.util.Parcelling.BuiltIn.ForPattern.class) @android.annotation.NonNull java.util.regex.Pattern mPattern\nprivate @android.annotation.NonNull java.util.List<android.net.LinkAddress> mLinkAddresses2\nprivate @com.android.internal.util.DataClass.PluralOf(\"linkAddress\") @android.annotation.NonNull java.util.ArrayList<android.net.LinkAddress> mLinkAddresses\nprivate @android.annotation.Nullable android.net.LinkAddress[] mLinkAddresses4\nprivate @com.android.codegentest.SampleDataClass.StateName @android.annotation.NonNull java.lang.String mStateName\nprivate @com.android.codegentest.SampleDataClass.RequestFlags int mFlags\nprivate @com.android.codegentest.SampleDataClass.State int mState\npublic @android.annotation.NonNull java.lang.CharSequence charSeq\nprivate final @android.annotation.Nullable android.net.LinkAddress[] mLinkAddresses5\nprivate transient android.net.LinkAddress[] mLinkAddresses6\ntransient int[] mTmpStorage\nprivate @android.annotation.StringRes int mStringRes\nprivate @android.annotation.IntRange(from=0L, to=6L) int mDayOfWeek\nprivate @android.annotation.Size(2L) @android.annotation.NonNull @com.android.internal.util.DataClass.Each @android.annotation.FloatRange(from=0.0) float[] mCoords\nprivate static java.lang.String defaultName4()\nprivate int[] lazyInitTmpStorage()\npublic android.net.LinkAddress[] getLinkAddresses4()\nprivate boolean patternEquals(java.util.regex.Pattern)\nprivate int patternHashCode()\nprivate void onConstructed()\npublic void dump(java.io.PrintWriter)\nclass SampleDataClass extends java.lang.Object implements [android.os.Parcelable]\n@com.android.internal.util.DataClass(genBuilder=true, genConstructor=true, genEqualsHashCode=true, genToString=true, genForEachField=true, genSetters=true)")
@Deprecated
diff --git a/tests/Codegen/src/com/android/codegentest/SampleWithCustomBuilder.java b/tests/Codegen/src/com/android/codegentest/SampleWithCustomBuilder.java
index 2de848c83eda..d9fe1fd5a465 100644
--- a/tests/Codegen/src/com/android/codegentest/SampleWithCustomBuilder.java
+++ b/tests/Codegen/src/com/android/codegentest/SampleWithCustomBuilder.java
@@ -85,7 +85,7 @@ public class SampleWithCustomBuilder implements Parcelable {
- // Code below generated by codegen v1.0.14.
+ // Code below generated by codegen v1.0.15.
//
// DO NOT MODIFY!
// CHECKSTYLE:OFF Generated code
@@ -253,8 +253,8 @@ public class SampleWithCustomBuilder implements Parcelable {
}
@DataClass.Generated(
- time = 1574122835982L,
- codegenVersion = "1.0.14",
+ time = 1582685648622L,
+ codegenVersion = "1.0.15",
sourceFile = "frameworks/base/tests/Codegen/src/com/android/codegentest/SampleWithCustomBuilder.java",
inputSignatures = " long delayAmount\n @android.annotation.NonNull java.util.concurrent.TimeUnit delayUnit\n long creationTimestamp\nprivate static java.util.concurrent.TimeUnit unparcelDelayUnit(android.os.Parcel)\nprivate void parcelDelayUnit(android.os.Parcel,int)\nclass SampleWithCustomBuilder extends java.lang.Object implements [android.os.Parcelable]\n@com.android.internal.util.DataClass(genBuilder=true, genAidl=false, genToString=true)\nabstract com.android.codegentest.SampleWithCustomBuilder.Builder setDelayAmount(long)\npublic abstract com.android.codegentest.SampleWithCustomBuilder.Builder setDelayUnit(java.util.concurrent.TimeUnit)\npublic com.android.codegentest.SampleWithCustomBuilder.Builder setDelay(long,java.util.concurrent.TimeUnit)\nclass BaseBuilder extends java.lang.Object implements []")
@Deprecated
diff --git a/tests/Codegen/src/com/android/codegentest/SampleWithNestedDataClasses.java b/tests/Codegen/src/com/android/codegentest/SampleWithNestedDataClasses.java
index 0deffe44838f..f98d7b05c2d3 100644
--- a/tests/Codegen/src/com/android/codegentest/SampleWithNestedDataClasses.java
+++ b/tests/Codegen/src/com/android/codegentest/SampleWithNestedDataClasses.java
@@ -36,7 +36,7 @@ public class SampleWithNestedDataClasses {
- // Code below generated by codegen v1.0.14.
+ // Code below generated by codegen v1.0.15.
//
// DO NOT MODIFY!
// CHECKSTYLE:OFF Generated code
@@ -135,8 +135,8 @@ public class SampleWithNestedDataClasses {
};
@DataClass.Generated(
- time = 1574122840588L,
- codegenVersion = "1.0.14",
+ time = 1582685653406L,
+ codegenVersion = "1.0.15",
sourceFile = "frameworks/base/tests/Codegen/src/com/android/codegentest/SampleWithNestedDataClasses.java",
inputSignatures = " @android.annotation.NonNull java.lang.String mBar\nclass NestedDataClass extends java.lang.Object implements [android.os.Parcelable]\n@com.android.internal.util.DataClass(genEqualsHashCode=true)")
@Deprecated
@@ -160,7 +160,7 @@ public class SampleWithNestedDataClasses {
- // Code below generated by codegen v1.0.14.
+ // Code below generated by codegen v1.0.15.
//
// DO NOT MODIFY!
// CHECKSTYLE:OFF Generated code
@@ -259,8 +259,8 @@ public class SampleWithNestedDataClasses {
};
@DataClass.Generated(
- time = 1574122840597L,
- codegenVersion = "1.0.14",
+ time = 1582685653415L,
+ codegenVersion = "1.0.15",
sourceFile = "frameworks/base/tests/Codegen/src/com/android/codegentest/SampleWithNestedDataClasses.java",
inputSignatures = " @android.annotation.NonNull long mBaz2\nclass NestedDataClass3 extends java.lang.Object implements [android.os.Parcelable]\n@com.android.internal.util.DataClass(genEqualsHashCode=true)")
@Deprecated
@@ -274,7 +274,7 @@ public class SampleWithNestedDataClasses {
- // Code below generated by codegen v1.0.14.
+ // Code below generated by codegen v1.0.15.
//
// DO NOT MODIFY!
// CHECKSTYLE:OFF Generated code
@@ -373,8 +373,8 @@ public class SampleWithNestedDataClasses {
};
@DataClass.Generated(
- time = 1574122840608L,
- codegenVersion = "1.0.14",
+ time = 1582685653420L,
+ codegenVersion = "1.0.15",
sourceFile = "frameworks/base/tests/Codegen/src/com/android/codegentest/SampleWithNestedDataClasses.java",
inputSignatures = " @android.annotation.NonNull java.lang.String mBaz\nclass NestedDataClass2 extends java.lang.Object implements [android.os.Parcelable]\n@com.android.internal.util.DataClass(genEqualsHashCode=true)")
@Deprecated
diff --git a/tests/Codegen/src/com/android/codegentest/StaleDataclassDetectorFalsePositivesTest.java b/tests/Codegen/src/com/android/codegentest/StaleDataclassDetectorFalsePositivesTest.java
index 712722b123af..6b4fc2fa157f 100644
--- a/tests/Codegen/src/com/android/codegentest/StaleDataclassDetectorFalsePositivesTest.java
+++ b/tests/Codegen/src/com/android/codegentest/StaleDataclassDetectorFalsePositivesTest.java
@@ -51,7 +51,7 @@ public class StaleDataclassDetectorFalsePositivesTest {
- // Code below generated by codegen v1.0.14.
+ // Code below generated by codegen v1.0.15.
//
// DO NOT MODIFY!
// CHECKSTYLE:OFF Generated code
@@ -65,8 +65,8 @@ public class StaleDataclassDetectorFalsePositivesTest {
@DataClass.Generated(
- time = 1574122839646L,
- codegenVersion = "1.0.14",
+ time = 1582685652436L,
+ codegenVersion = "1.0.15",
sourceFile = "frameworks/base/tests/Codegen/src/com/android/codegentest/StaleDataclassDetectorFalsePositivesTest.java",
inputSignatures = "public @android.annotation.NonNull java.lang.String someMethod(int)\nclass StaleDataclassDetectorFalsePositivesTest extends java.lang.Object implements []\n@com.android.internal.util.DataClass(genConstructor=false, genBuilder=false)")
@Deprecated
diff --git a/tests/PackageWatchdog/src/com/android/server/ExplicitHealthCheckServiceTest.java b/tests/PackageWatchdog/src/com/android/server/ExplicitHealthCheckServiceTest.java
new file mode 100644
index 000000000000..2fbfeba47b13
--- /dev/null
+++ b/tests/PackageWatchdog/src/com/android/server/ExplicitHealthCheckServiceTest.java
@@ -0,0 +1,61 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import static org.mockito.Mockito.spy;
+
+import android.content.Intent;
+import android.os.IBinder;
+import android.os.RemoteCallback;
+import android.service.watchdog.ExplicitHealthCheckService;
+import android.service.watchdog.IExplicitHealthCheckService;
+
+import org.junit.Before;
+import org.junit.Test;
+
+import java.util.concurrent.CountDownLatch;
+
+public class ExplicitHealthCheckServiceTest {
+
+ private ExplicitHealthCheckService mExplicitHealthCheckService;
+ private static final String PACKAGE_NAME = "com.test.package";
+
+ @Before
+ public void setup() throws Exception {
+ mExplicitHealthCheckService = spy(ExplicitHealthCheckService.class);
+ }
+
+ /**
+ * Test to verify that the correct information is sent in the callback when a package has
+ * passed an explicit health check.
+ */
+ @Test
+ public void testNotifyHealthCheckPassed() throws Exception {
+ IBinder binder = mExplicitHealthCheckService.onBind(new Intent());
+ CountDownLatch countDownLatch = new CountDownLatch(1);
+ RemoteCallback callback = new RemoteCallback(result -> {
+ assertThat(result.get(ExplicitHealthCheckService.EXTRA_HEALTH_CHECK_PASSED_PACKAGE))
+ .isEqualTo(PACKAGE_NAME);
+ countDownLatch.countDown();
+ });
+ IExplicitHealthCheckService.Stub.asInterface(binder).setCallback(callback);
+ mExplicitHealthCheckService.notifyHealthCheckPassed(PACKAGE_NAME);
+ countDownLatch.await();
+ }
+}
diff --git a/tests/PackageWatchdog/src/com/android/server/PackageWatchdogTest.java b/tests/PackageWatchdog/src/com/android/server/PackageWatchdogTest.java
index 8cc8cf4d2a97..819fc020e397 100644
--- a/tests/PackageWatchdog/src/com/android/server/PackageWatchdogTest.java
+++ b/tests/PackageWatchdog/src/com/android/server/PackageWatchdogTest.java
@@ -1063,6 +1063,52 @@ public class PackageWatchdogTest {
assertThat(bootObserver2.mitigatedBootLoop()).isFalse();
}
+ /**
+ * Test to verify that Package Watchdog syncs health check requests with the controller
+ * correctly, and that the requests are only synced when the set of observed packages
+ * changes.
+ */
+ @Test
+ public void testSyncHealthCheckRequests() {
+ TestController testController = spy(TestController.class);
+ testController.setSupportedPackages(List.of(APP_A, APP_B, APP_C));
+ PackageWatchdog watchdog = createWatchdog(testController, true);
+
+ TestObserver testObserver1 = new TestObserver(OBSERVER_NAME_1);
+ watchdog.registerHealthObserver(testObserver1);
+ watchdog.startObservingHealth(testObserver1, List.of(APP_A), LONG_DURATION);
+ mTestLooper.dispatchAll();
+
+ TestObserver testObserver2 = new TestObserver(OBSERVER_NAME_2);
+ watchdog.registerHealthObserver(testObserver2);
+ watchdog.startObservingHealth(testObserver2, List.of(APP_B), LONG_DURATION);
+ mTestLooper.dispatchAll();
+
+ TestObserver testObserver3 = new TestObserver(OBSERVER_NAME_3);
+ watchdog.registerHealthObserver(testObserver3);
+ watchdog.startObservingHealth(testObserver3, List.of(APP_C), LONG_DURATION);
+ mTestLooper.dispatchAll();
+
+ watchdog.unregisterHealthObserver(testObserver1);
+ mTestLooper.dispatchAll();
+
+ watchdog.unregisterHealthObserver(testObserver2);
+ mTestLooper.dispatchAll();
+
+ watchdog.unregisterHealthObserver(testObserver3);
+ mTestLooper.dispatchAll();
+
+ List<Set> expectedSyncRequests = List.of(
+ Set.of(APP_A),
+ Set.of(APP_A, APP_B),
+ Set.of(APP_A, APP_B, APP_C),
+ Set.of(APP_B, APP_C),
+ Set.of(APP_C),
+ Set.of()
+ );
+ assertThat(testController.getSyncRequests()).isEqualTo(expectedSyncRequests);
+ }
+
private void adoptShellPermissions(String... permissions) {
InstrumentationRegistry
.getInstrumentation()
@@ -1219,6 +1265,7 @@ public class PackageWatchdogTest {
private Consumer<String> mPassedConsumer;
private Consumer<List<PackageConfig>> mSupportedConsumer;
private Runnable mNotifySyncRunnable;
+ private List<Set> mSyncRequests = new ArrayList<>();
@Override
public void setEnabled(boolean enabled) {
@@ -1238,6 +1285,7 @@ public class PackageWatchdogTest {
@Override
public void syncRequests(Set<String> packages) {
+ mSyncRequests.add(packages);
mRequestedPackages.clear();
if (mIsEnabled) {
packages.retainAll(mSupportedPackages);
@@ -1268,6 +1316,10 @@ public class PackageWatchdogTest {
return Collections.emptyList();
}
}
+
+ public List<Set> getSyncRequests() {
+ return mSyncRequests;
+ }
}
private static class TestClock implements PackageWatchdog.SystemClock {
diff --git a/tests/RollbackTest/RollbackTest/src/com/android/tests/rollback/StagedRollbackTest.java b/tests/RollbackTest/RollbackTest/src/com/android/tests/rollback/StagedRollbackTest.java
index 70be83f216da..a616c61b34f8 100644
--- a/tests/RollbackTest/RollbackTest/src/com/android/tests/rollback/StagedRollbackTest.java
+++ b/tests/RollbackTest/RollbackTest/src/com/android/tests/rollback/StagedRollbackTest.java
@@ -127,18 +127,12 @@ public class StagedRollbackTest {
/**
* Test rollbacks of staged installs involving only apks with bad update.
- * Trigger rollback phase. This is expected to fail due to watchdog
- * rebooting the test out from under it.
+ * Trigger rollback phase.
*/
@Test
public void testBadApkOnly_Phase3() throws Exception {
// One more crash to trigger rollback
RollbackUtils.sendCrashBroadcast(TestApp.A, 1);
-
- // We expect the device to be rebooted automatically. Wait for that to happen.
- // This device method will fail and the host will catch the assertion.
- // If reboot doesn't happen, the host will fail the assertion.
- Thread.sleep(TimeUnit.SECONDS.toMillis(120));
}
/**
diff --git a/tests/RollbackTest/StagedRollbackTest/src/com/android/tests/rollback/host/StagedRollbackTest.java b/tests/RollbackTest/StagedRollbackTest/src/com/android/tests/rollback/host/StagedRollbackTest.java
index 4afebb58c105..282f012dbf6f 100644
--- a/tests/RollbackTest/StagedRollbackTest/src/com/android/tests/rollback/host/StagedRollbackTest.java
+++ b/tests/RollbackTest/StagedRollbackTest/src/com/android/tests/rollback/host/StagedRollbackTest.java
@@ -22,7 +22,6 @@ import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertTrue;
import static org.junit.Assume.assumeTrue;
-import static org.testng.Assert.assertThrows;
import com.android.compatibility.common.tradefed.build.CompatibilityBuildHelper;
import com.android.tradefed.testtype.DeviceJUnit4ClassRunner;
@@ -136,7 +135,10 @@ public class StagedRollbackTest extends BaseHostJUnit4Test {
getDevice().reboot();
runPhase("testBadApkOnly_Phase2");
- assertThrows(AssertionError.class, () -> runPhase("testBadApkOnly_Phase3"));
+ // Trigger rollback and wait for reboot to happen
+ runPhase("testBadApkOnly_Phase3");
+ assertTrue(getDevice().waitForDeviceNotAvailable(TimeUnit.MINUTES.toMillis(2)));
+
getDevice().waitForDeviceAvailable();
runPhase("testBadApkOnly_Phase4");
diff --git a/tests/net/common/java/android/net/CaptivePortalTest.java b/tests/net/common/java/android/net/CaptivePortalTest.java
index ca4ba63142a2..7a60cc105a26 100644
--- a/tests/net/common/java/android/net/CaptivePortalTest.java
+++ b/tests/net/common/java/android/net/CaptivePortalTest.java
@@ -18,19 +18,26 @@ package android.net;
import static org.junit.Assert.assertEquals;
+import android.os.Build;
import android.os.RemoteException;
import androidx.test.filters.SmallTest;
import androidx.test.runner.AndroidJUnit4;
import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
+import com.android.testutils.DevSdkIgnoreRule;
+import com.android.testutils.DevSdkIgnoreRule.IgnoreUpTo;
+import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;
@RunWith(AndroidJUnit4.class)
@SmallTest
public class CaptivePortalTest {
+ @Rule
+ public final DevSdkIgnoreRule ignoreRule = new DevSdkIgnoreRule();
+
private static final int DEFAULT_TIMEOUT_MS = 5000;
private static final String TEST_PACKAGE_NAME = "com.google.android.test";
@@ -84,6 +91,7 @@ public class CaptivePortalTest {
assertEquals(result.mCode, CaptivePortal.APP_RETURN_WANTED_AS_IS);
}
+ @IgnoreUpTo(Build.VERSION_CODES.Q)
@Test
public void testReevaluateNetwork() {
final MyCaptivePortalImpl result = runCaptivePortalTest(c -> c.reevaluateNetwork());
diff --git a/tests/net/common/java/android/net/LinkAddressTest.java b/tests/net/common/java/android/net/LinkAddressTest.java
index 06c6301d66f3..99dac1439b34 100644
--- a/tests/net/common/java/android/net/LinkAddressTest.java
+++ b/tests/net/common/java/android/net/LinkAddressTest.java
@@ -28,8 +28,8 @@ import static android.system.OsConstants.RT_SCOPE_SITE;
import static android.system.OsConstants.RT_SCOPE_UNIVERSE;
import static com.android.testutils.MiscAssertsKt.assertEqualBothWays;
+import static com.android.testutils.MiscAssertsKt.assertFieldCountEquals;
import static com.android.testutils.MiscAssertsKt.assertNotEqualEitherWay;
-import static com.android.testutils.ParcelUtilsKt.assertParcelSane;
import static com.android.testutils.ParcelUtilsKt.assertParcelingIsLossless;
import static org.junit.Assert.assertEquals;
@@ -38,11 +38,17 @@ import static org.junit.Assert.assertNotEquals;
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;
+import android.os.Build;
import android.os.SystemClock;
import androidx.test.filters.SmallTest;
import androidx.test.runner.AndroidJUnit4;
+import com.android.testutils.DevSdkIgnoreRule;
+import com.android.testutils.DevSdkIgnoreRule.IgnoreAfter;
+import com.android.testutils.DevSdkIgnoreRule.IgnoreUpTo;
+
+import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;
@@ -57,6 +63,8 @@ import java.util.List;
@RunWith(AndroidJUnit4.class)
@SmallTest
public class LinkAddressTest {
+ @Rule
+ public final DevSdkIgnoreRule ignoreRule = new DevSdkIgnoreRule();
private static final String V4 = "192.0.2.1";
private static final String V6 = "2001:db8::1";
@@ -318,15 +326,29 @@ public class LinkAddressTest {
l = new LinkAddress(V6_ADDRESS, 64, 123, 456);
assertParcelingIsLossless(l);
- l = new LinkAddress(V6_ADDRESS, 64, 123, 456,
- 1L, 3600000L);
- assertParcelingIsLossless(l);
l = new LinkAddress(V4 + "/28", IFA_F_PERMANENT, RT_SCOPE_LINK);
- assertParcelSane(l, 6);
+ assertParcelingIsLossless(l);
}
- @Test
+ @Test @IgnoreUpTo(Build.VERSION_CODES.Q)
+ public void testLifetimeParceling() {
+ final LinkAddress l = new LinkAddress(V6_ADDRESS, 64, 123, 456, 1L, 3600000L);
+ assertParcelingIsLossless(l);
+ }
+
+ @Test @IgnoreAfter(Build.VERSION_CODES.Q)
+ public void testFieldCount_Q() {
+ assertFieldCountEquals(4, LinkAddress.class);
+ }
+
+ @Test @IgnoreUpTo(Build.VERSION_CODES.Q)
+ public void testFieldCount() {
+ // Make sure any new field is covered by the above parceling tests when changing this number
+ assertFieldCountEquals(6, LinkAddress.class);
+ }
+
+ @Test @IgnoreUpTo(Build.VERSION_CODES.Q)
public void testDeprecationTime() {
try {
new LinkAddress(V6_ADDRESS, 64, 0, 456,
@@ -347,7 +369,7 @@ public class LinkAddressTest {
} catch (IllegalArgumentException expected) { }
}
- @Test
+ @Test @IgnoreUpTo(Build.VERSION_CODES.Q)
public void testExpirationTime() {
try {
new LinkAddress(V6_ADDRESS, 64, 0, 456,
@@ -366,10 +388,13 @@ public class LinkAddressTest {
public void testGetFlags() {
LinkAddress l = new LinkAddress(V6_ADDRESS, 64, 123, RT_SCOPE_HOST);
assertEquals(123, l.getFlags());
+ }
+ @Test @IgnoreUpTo(Build.VERSION_CODES.Q)
+ public void testGetFlags_Deprecation() {
// Test if deprecated bit was added/remove automatically based on the provided deprecation
// time
- l = new LinkAddress(V6_ADDRESS, 64, 0, RT_SCOPE_HOST,
+ LinkAddress l = new LinkAddress(V6_ADDRESS, 64, 0, RT_SCOPE_HOST,
1L, LinkAddress.LIFETIME_PERMANENT);
// Check if the flag is added automatically.
assertTrue((l.getFlags() & IFA_F_DEPRECATED) != 0);
@@ -458,8 +483,11 @@ public class LinkAddressTest {
(IFA_F_TEMPORARY|IFA_F_TENTATIVE|IFA_F_OPTIMISTIC),
RT_SCOPE_UNIVERSE);
assertGlobalPreferred(l, "v6,global,tempaddr+optimistic");
+ }
- l = new LinkAddress(V6_ADDRESS, 64, IFA_F_DEPRECATED,
+ @Test @IgnoreUpTo(Build.VERSION_CODES.Q)
+ public void testIsGlobalPreferred_DeprecatedInFuture() {
+ final LinkAddress l = new LinkAddress(V6_ADDRESS, 64, IFA_F_DEPRECATED,
RT_SCOPE_UNIVERSE, SystemClock.elapsedRealtime() + 100000,
SystemClock.elapsedRealtime() + 200000);
// Although the deprecated bit is set, but the deprecation time is in the future, test
diff --git a/tests/net/common/java/android/net/LinkPropertiesTest.java b/tests/net/common/java/android/net/LinkPropertiesTest.java
index f25fd4daf829..48b65e592f39 100644
--- a/tests/net/common/java/android/net/LinkPropertiesTest.java
+++ b/tests/net/common/java/android/net/LinkPropertiesTest.java
@@ -315,7 +315,7 @@ public class LinkPropertiesTest {
source.addDnsServer(DNS1);
source.addDnsServer(DNS2);
// set 2 gateways
- source.addRoute(new RouteInfo(GATEWAY1));
+ source.addRoute(new RouteInfo(LINKADDRV4, GATEWAY1));
source.addRoute(new RouteInfo(GATEWAY2));
source.setMtu(MTU);
@@ -327,7 +327,7 @@ public class LinkPropertiesTest {
target.addDnsServer(DNS2);
target.addDnsServer(DNS1);
target.addRoute(new RouteInfo(GATEWAY2));
- target.addRoute(new RouteInfo(GATEWAY1));
+ target.addRoute(new RouteInfo(LINKADDRV4, GATEWAY1));
target.setMtu(MTU);
assertLinkPropertiesEqual(source, target);
@@ -364,12 +364,13 @@ public class LinkPropertiesTest {
@Test
public void testRouteInterfaces() {
- LinkAddress prefix = new LinkAddress(address("2001:db8::"), 32);
+ LinkAddress prefix1 = new LinkAddress(address("2001:db8:1::"), 48);
+ LinkAddress prefix2 = new LinkAddress(address("2001:db8:2::"), 48);
InetAddress address = ADDRV6;
// Add a route with no interface to a LinkProperties with no interface. No errors.
LinkProperties lp = new LinkProperties();
- RouteInfo r = new RouteInfo(prefix, address, null);
+ RouteInfo r = new RouteInfo(prefix1, address, null);
assertTrue(lp.addRoute(r));
assertEquals(1, lp.getRoutes().size());
assertAllRoutesHaveInterface(null, lp);
@@ -379,7 +380,7 @@ public class LinkPropertiesTest {
assertEquals(1, lp.getRoutes().size());
// Add a route with an interface. Expect an exception.
- r = new RouteInfo(prefix, address, "wlan0");
+ r = new RouteInfo(prefix2, address, "wlan0");
try {
lp.addRoute(r);
fail("Adding wlan0 route to LP with no interface, expect exception");
@@ -398,7 +399,7 @@ public class LinkPropertiesTest {
} catch (IllegalArgumentException expected) {}
// If the interface name matches, the route is added.
- r = new RouteInfo(prefix, null, "wlan0");
+ r = new RouteInfo(prefix2, null, "wlan0");
lp.setInterfaceName("wlan0");
lp.addRoute(r);
assertEquals(2, lp.getRoutes().size());
@@ -423,10 +424,12 @@ public class LinkPropertiesTest {
assertEquals(3, lp.compareAllRoutes(lp2).added.size());
assertEquals(3, lp.compareAllRoutes(lp2).removed.size());
- // Check remove works
- lp.removeRoute(new RouteInfo(prefix, address, null));
+ // Remove route with incorrect interface, no route removed.
+ lp.removeRoute(new RouteInfo(prefix2, null, null));
assertEquals(3, lp.getRoutes().size());
- lp.removeRoute(new RouteInfo(prefix, address, "wlan0"));
+
+ // Check remove works when interface is correct.
+ lp.removeRoute(new RouteInfo(prefix2, null, "wlan0"));
assertEquals(2, lp.getRoutes().size());
assertAllRoutesHaveInterface("wlan0", lp);
assertAllRoutesNotHaveInterface("p2p0", lp);
diff --git a/tests/net/common/java/android/net/NetworkAgentConfigTest.kt b/tests/net/common/java/android/net/NetworkAgentConfigTest.kt
index d250ad3a2b12..173dbd1271f8 100644
--- a/tests/net/common/java/android/net/NetworkAgentConfigTest.kt
+++ b/tests/net/common/java/android/net/NetworkAgentConfigTest.kt
@@ -16,16 +16,23 @@
package android.net
+import android.os.Build
import androidx.test.filters.SmallTest
import androidx.test.runner.AndroidJUnit4
+import com.android.testutils.DevSdkIgnoreRule
+import com.android.testutils.DevSdkIgnoreRule.IgnoreUpTo
import com.android.testutils.assertParcelSane
+import org.junit.Rule
import org.junit.Test
import org.junit.runner.RunWith
@RunWith(AndroidJUnit4::class)
@SmallTest
class NetworkAgentConfigTest {
- @Test
+ @Rule @JvmField
+ val ignoreRule = DevSdkIgnoreRule()
+
+ @Test @IgnoreUpTo(Build.VERSION_CODES.Q)
fun testParcelNetworkAgentConfig() {
val config = NetworkAgentConfig.Builder().apply {
setExplicitlySelected(true)
diff --git a/tests/net/common/java/android/net/NetworkScoreTest.kt b/tests/net/common/java/android/net/NetworkScoreTest.kt
deleted file mode 100644
index 30836b7c9be1..000000000000
--- a/tests/net/common/java/android/net/NetworkScoreTest.kt
+++ /dev/null
@@ -1,104 +0,0 @@
-/*
- * Copyright (C) 2019 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.net
-
-import android.os.Parcelable
-import androidx.test.filters.SmallTest
-import androidx.test.runner.AndroidJUnit4
-import com.android.testutils.assertParcelSane
-import org.junit.Assert.assertEquals
-import org.junit.Assert.assertFalse
-import org.junit.Assert.assertNotEquals
-import org.junit.Assert.assertTrue
-import org.junit.Test
-import org.junit.runner.RunWith
-
-private const val TEST_SCORE = 80
-private const val KEY_DEFAULT_CAPABILITIES = "DEFAULT_CAPABILITIES"
-
-@RunWith(AndroidJUnit4::class)
-@SmallTest
-class NetworkScoreTest {
- @Test
- fun testParcelNetworkScore() {
- val networkScore = NetworkScore()
- val defaultCap = NetworkCapabilities()
- networkScore.putExtension(KEY_DEFAULT_CAPABILITIES, defaultCap)
- assertEquals(defaultCap, networkScore.getExtension(KEY_DEFAULT_CAPABILITIES))
- networkScore.putIntExtension(NetworkScore.LEGACY_SCORE, TEST_SCORE)
- assertEquals(TEST_SCORE, networkScore.getIntExtension(NetworkScore.LEGACY_SCORE))
- assertParcelSane(networkScore, 1)
- }
-
- @Test
- fun testNullKeyAndValue() {
- val networkScore = NetworkScore()
- val defaultCap = NetworkCapabilities()
- networkScore.putIntExtension(null, TEST_SCORE)
- assertEquals(TEST_SCORE, networkScore.getIntExtension(null))
- networkScore.putExtension(null, defaultCap)
- assertEquals(defaultCap, networkScore.getExtension(null))
- networkScore.putExtension(null, null)
- val result: Parcelable? = networkScore.getExtension(null)
- assertEquals(null, result)
- }
-
- @Test
- fun testRemoveExtension() {
- val networkScore = NetworkScore()
- val defaultCap = NetworkCapabilities()
- networkScore.putExtension(KEY_DEFAULT_CAPABILITIES, defaultCap)
- networkScore.putIntExtension(NetworkScore.LEGACY_SCORE, TEST_SCORE)
- assertEquals(defaultCap, networkScore.getExtension(KEY_DEFAULT_CAPABILITIES))
- assertEquals(TEST_SCORE, networkScore.getIntExtension(NetworkScore.LEGACY_SCORE))
- networkScore.removeExtension(KEY_DEFAULT_CAPABILITIES)
- networkScore.removeExtension(NetworkScore.LEGACY_SCORE)
- val result: Parcelable? = networkScore.getExtension(KEY_DEFAULT_CAPABILITIES)
- assertEquals(null, result)
- assertEquals(0, networkScore.getIntExtension(NetworkScore.LEGACY_SCORE))
- }
-
- @Test
- fun testEqualsNetworkScore() {
- val ns1 = NetworkScore()
- val ns2 = NetworkScore()
- assertTrue(ns1.equals(ns2))
- assertEquals(ns1.hashCode(), ns2.hashCode())
-
- ns1.putIntExtension(NetworkScore.LEGACY_SCORE, TEST_SCORE)
- assertFalse(ns1.equals(ns2))
- assertNotEquals(ns1.hashCode(), ns2.hashCode())
- ns2.putIntExtension(NetworkScore.LEGACY_SCORE, TEST_SCORE)
- assertTrue(ns1.equals(ns2))
- assertEquals(ns1.hashCode(), ns2.hashCode())
-
- val defaultCap = NetworkCapabilities()
- ns1.putExtension(KEY_DEFAULT_CAPABILITIES, defaultCap)
- assertFalse(ns1.equals(ns2))
- assertNotEquals(ns1.hashCode(), ns2.hashCode())
- ns2.putExtension(KEY_DEFAULT_CAPABILITIES, defaultCap)
- assertTrue(ns1.equals(ns2))
- assertEquals(ns1.hashCode(), ns2.hashCode())
-
- ns1.putIntExtension(null, 10)
- assertFalse(ns1.equals(ns2))
- assertNotEquals(ns1.hashCode(), ns2.hashCode())
- ns2.putIntExtension(null, 10)
- assertTrue(ns1.equals(ns2))
- assertEquals(ns1.hashCode(), ns2.hashCode())
- }
-}
diff --git a/tests/net/java/com/android/server/ConnectivityServiceTest.java b/tests/net/java/com/android/server/ConnectivityServiceTest.java
index 4e75f2a273a9..8c0c36b89bf9 100644
--- a/tests/net/java/com/android/server/ConnectivityServiceTest.java
+++ b/tests/net/java/com/android/server/ConnectivityServiceTest.java
@@ -2751,9 +2751,6 @@ public class ConnectivityServiceTest {
// Expect NET_CAPABILITY_VALIDATED onAvailable callback.
validatedCallback.expectAvailableDoubleValidatedCallbacks(mWiFiNetworkAgent);
- // Expect no notification to be shown when captive portal disappears by itself
- verify(mNotificationManager, never()).notifyAsUser(
- anyString(), eq(NotificationType.LOGGED_IN.eventId), any(), any());
// Break network connectivity.
// Expect NET_CAPABILITY_VALIDATED onLost callback.
@@ -2815,8 +2812,6 @@ public class ConnectivityServiceTest {
mWiFiNetworkAgent.mNetworkMonitor.forceReevaluation(Process.myUid());
validatedCallback.expectAvailableCallbacksValidated(mWiFiNetworkAgent);
captivePortalCallback.expectCallback(CallbackEntry.LOST, mWiFiNetworkAgent);
- verify(mNotificationManager, times(1)).notifyAsUser(anyString(),
- eq(NotificationType.LOGGED_IN.eventId), any(), eq(UserHandle.ALL));
mCm.unregisterNetworkCallback(validatedCallback);
mCm.unregisterNetworkCallback(captivePortalCallback);
@@ -5927,6 +5922,12 @@ public class ConnectivityServiceTest {
final LinkAddress myIpv6 = new LinkAddress("2001:db8:1::1/64");
final String kNat64PrefixString = "2001:db8:64:64:64:64::";
final IpPrefix kNat64Prefix = new IpPrefix(InetAddress.getByName(kNat64PrefixString), 96);
+ final RouteInfo defaultRoute = new RouteInfo((IpPrefix) null, myIpv6.getAddress(),
+ MOBILE_IFNAME);
+ final RouteInfo ipv6Subnet = new RouteInfo(myIpv6, null, MOBILE_IFNAME);
+ final RouteInfo ipv4Subnet = new RouteInfo(myIpv4, null, MOBILE_IFNAME);
+ final RouteInfo stackedDefault = new RouteInfo((IpPrefix) null, myIpv4.getAddress(),
+ CLAT_PREFIX + MOBILE_IFNAME);
final NetworkRequest networkRequest = new NetworkRequest.Builder()
.addTransportType(TRANSPORT_CELLULAR)
@@ -5939,15 +5940,13 @@ public class ConnectivityServiceTest {
final LinkProperties cellLp = new LinkProperties();
cellLp.setInterfaceName(MOBILE_IFNAME);
cellLp.addLinkAddress(myIpv6);
- cellLp.addRoute(new RouteInfo((IpPrefix) null, myIpv6.getAddress(), MOBILE_IFNAME));
- cellLp.addRoute(new RouteInfo(myIpv6, null, MOBILE_IFNAME));
+ cellLp.addRoute(defaultRoute);
+ cellLp.addRoute(ipv6Subnet);
mCellNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_CELLULAR, cellLp);
reset(mNetworkManagementService);
reset(mMockDnsResolver);
reset(mMockNetd);
reset(mBatteryStatsService);
- when(mNetworkManagementService.getInterfaceConfig(CLAT_PREFIX + MOBILE_IFNAME))
- .thenReturn(getClatInterfaceConfig(myIpv4));
// Connect with ipv6 link properties. Expect prefix discovery to be started.
mCellNetworkAgent.connect(true);
@@ -5955,6 +5954,7 @@ public class ConnectivityServiceTest {
waitForIdle();
verify(mMockNetd, times(1)).networkCreatePhysical(eq(cellNetId), anyInt());
+ assertRoutesAdded(cellNetId, ipv6Subnet, defaultRoute);
verify(mMockDnsResolver, times(1)).createNetworkCache(eq(cellNetId));
verify(mBatteryStatsService).noteNetworkInterfaceType(cellLp.getInterfaceName(),
TYPE_MOBILE);
@@ -5970,6 +5970,7 @@ public class ConnectivityServiceTest {
cellLp.addLinkAddress(myIpv4);
mCellNetworkAgent.sendLinkProperties(cellLp);
networkCallback.expectCallback(CallbackEntry.LINK_PROPERTIES_CHANGED, mCellNetworkAgent);
+ assertRoutesAdded(cellNetId, ipv4Subnet);
verify(mMockDnsResolver, times(1)).stopPrefix64Discovery(cellNetId);
verify(mMockDnsResolver, atLeastOnce()).setResolverConfiguration(any());
@@ -5980,15 +5981,18 @@ public class ConnectivityServiceTest {
verifyNoMoreInteractions(mMockNetd);
verifyNoMoreInteractions(mMockDnsResolver);
+ reset(mNetworkManagementService);
reset(mMockNetd);
reset(mMockDnsResolver);
+ when(mNetworkManagementService.getInterfaceConfig(CLAT_PREFIX + MOBILE_IFNAME))
+ .thenReturn(getClatInterfaceConfig(myIpv4));
// Remove IPv4 address. Expect prefix discovery to be started again.
cellLp.removeLinkAddress(myIpv4);
- cellLp.removeRoute(new RouteInfo(myIpv4, null, MOBILE_IFNAME));
mCellNetworkAgent.sendLinkProperties(cellLp);
networkCallback.expectCallback(CallbackEntry.LINK_PROPERTIES_CHANGED, mCellNetworkAgent);
verify(mMockDnsResolver, times(1)).startPrefix64Discovery(cellNetId);
+ assertRoutesRemoved(cellNetId, ipv4Subnet);
// When NAT64 prefix discovery succeeds, LinkProperties are updated and clatd is started.
Nat464Xlat clat = getNat464Xlat(mCellNetworkAgent);
@@ -6007,6 +6011,7 @@ public class ConnectivityServiceTest {
List<LinkProperties> stackedLps = mCm.getLinkProperties(mCellNetworkAgent.getNetwork())
.getStackedLinks();
assertEquals(makeClatLinkProperties(myIpv4), stackedLps.get(0));
+ assertRoutesAdded(cellNetId, stackedDefault);
// Change trivial linkproperties and see if stacked link is preserved.
cellLp.addDnsServer(InetAddress.getByName("8.8.8.8"));
@@ -6032,9 +6037,10 @@ public class ConnectivityServiceTest {
// Add ipv4 address, expect that clatd and prefix discovery are stopped and stacked
// linkproperties are cleaned up.
cellLp.addLinkAddress(myIpv4);
- cellLp.addRoute(new RouteInfo(myIpv4, null, MOBILE_IFNAME));
+ cellLp.addRoute(ipv4Subnet);
mCellNetworkAgent.sendLinkProperties(cellLp);
networkCallback.expectCallback(CallbackEntry.LINK_PROPERTIES_CHANGED, mCellNetworkAgent);
+ assertRoutesAdded(cellNetId, ipv4Subnet);
verify(mMockNetd, times(1)).clatdStop(MOBILE_IFNAME);
verify(mMockDnsResolver, times(1)).stopPrefix64Discovery(cellNetId);
@@ -6045,6 +6051,7 @@ public class ConnectivityServiceTest {
expected.setNat64Prefix(kNat64Prefix);
assertEquals(expected, actualLpAfterIpv4);
assertEquals(0, actualLpAfterIpv4.getStackedLinks().size());
+ assertRoutesRemoved(cellNetId, stackedDefault);
// The interface removed callback happens but has no effect after stop is called.
clat.interfaceRemoved(CLAT_PREFIX + MOBILE_IFNAME);
@@ -6052,8 +6059,11 @@ public class ConnectivityServiceTest {
verifyNoMoreInteractions(mMockNetd);
verifyNoMoreInteractions(mMockDnsResolver);
+ reset(mNetworkManagementService);
reset(mMockNetd);
reset(mMockDnsResolver);
+ when(mNetworkManagementService.getInterfaceConfig(CLAT_PREFIX + MOBILE_IFNAME))
+ .thenReturn(getClatInterfaceConfig(myIpv4));
// Stopping prefix discovery causes netd to tell us that the NAT64 prefix is gone.
mService.mNetdEventCallback.onNat64PrefixEvent(cellNetId, false /* added */,
@@ -6067,6 +6077,7 @@ public class ConnectivityServiceTest {
cellLp.removeDnsServer(InetAddress.getByName("8.8.8.8"));
mCellNetworkAgent.sendLinkProperties(cellLp);
networkCallback.expectCallback(CallbackEntry.LINK_PROPERTIES_CHANGED, mCellNetworkAgent);
+ assertRoutesRemoved(cellNetId, ipv4Subnet); // Directly-connected routes auto-added.
verify(mMockDnsResolver, times(1)).startPrefix64Discovery(cellNetId);
mService.mNetdEventCallback.onNat64PrefixEvent(cellNetId, true /* added */,
kNat64PrefixString, 96);
@@ -6078,15 +6089,20 @@ public class ConnectivityServiceTest {
clat.interfaceLinkStateChanged(CLAT_PREFIX + MOBILE_IFNAME, true);
networkCallback.expectLinkPropertiesThat(mCellNetworkAgent,
(lp) -> lp.getStackedLinks().size() == 1 && lp.getNat64Prefix() != null);
+ assertRoutesAdded(cellNetId, stackedDefault);
// NAT64 prefix is removed. Expect that clat is stopped.
mService.mNetdEventCallback.onNat64PrefixEvent(cellNetId, false /* added */,
kNat64PrefixString, 96);
networkCallback.expectLinkPropertiesThat(mCellNetworkAgent,
(lp) -> lp.getStackedLinks().size() == 0 && lp.getNat64Prefix() == null);
+ assertRoutesRemoved(cellNetId, ipv4Subnet, stackedDefault);
+
+ // Stop has no effect because clat is already stopped.
verify(mMockNetd, times(1)).clatdStop(MOBILE_IFNAME);
networkCallback.expectLinkPropertiesThat(mCellNetworkAgent,
(lp) -> lp.getStackedLinks().size() == 0);
+ verifyNoMoreInteractions(mMockNetd);
// Clean up.
mCellNetworkAgent.disconnect();
@@ -6654,6 +6670,20 @@ public class ConnectivityServiceTest {
}
}
+ private void assertRoutesAdded(int netId, RouteInfo... routes) throws Exception {
+ InOrder inOrder = inOrder(mNetworkManagementService);
+ for (int i = 0; i < routes.length; i++) {
+ inOrder.verify(mNetworkManagementService).addRoute(eq(netId), eq(routes[i]));
+ }
+ }
+
+ private void assertRoutesRemoved(int netId, RouteInfo... routes) throws Exception {
+ InOrder inOrder = inOrder(mNetworkManagementService);
+ for (int i = 0; i < routes.length; i++) {
+ inOrder.verify(mNetworkManagementService).removeRoute(eq(netId), eq(routes[i]));
+ }
+ }
+
@Test
public void testRegisterUnregisterConnectivityDiagnosticsCallback() throws Exception {
final NetworkRequest wifiRequest =
@@ -6715,7 +6745,7 @@ public class ConnectivityServiceTest {
public void testCheckConnectivityDiagnosticsPermissionsNetworkStack() throws Exception {
final NetworkAgentInfo naiWithoutUid =
new NetworkAgentInfo(
- null, null, null, null, null, new NetworkCapabilities(), null,
+ null, null, null, null, null, new NetworkCapabilities(), 0,
mServiceContext, null, null, mService, null, null, null, 0);
mServiceContext.setPermission(
@@ -6731,7 +6761,7 @@ public class ConnectivityServiceTest {
public void testCheckConnectivityDiagnosticsPermissionsNoLocationPermission() throws Exception {
final NetworkAgentInfo naiWithoutUid =
new NetworkAgentInfo(
- null, null, null, null, null, new NetworkCapabilities(), null,
+ null, null, null, null, null, new NetworkCapabilities(), 0,
mServiceContext, null, null, mService, null, null, null, 0);
mServiceContext.setPermission(android.Manifest.permission.NETWORK_STACK, PERMISSION_DENIED);
@@ -6747,7 +6777,7 @@ public class ConnectivityServiceTest {
public void testCheckConnectivityDiagnosticsPermissionsActiveVpn() throws Exception {
final NetworkAgentInfo naiWithoutUid =
new NetworkAgentInfo(
- null, null, null, null, null, new NetworkCapabilities(), null,
+ null, null, null, null, null, new NetworkCapabilities(), 0,
mServiceContext, null, null, mService, null, null, null, 0);
setupLocationPermissions(Build.VERSION_CODES.Q, true, AppOpsManager.OPSTR_FINE_LOCATION,
@@ -6773,7 +6803,7 @@ public class ConnectivityServiceTest {
nc.setAdministratorUids(Arrays.asList(Process.myUid()));
final NetworkAgentInfo naiWithUid =
new NetworkAgentInfo(
- null, null, null, null, null, nc, null, mServiceContext, null, null,
+ null, null, null, null, null, nc, 0, mServiceContext, null, null,
mService, null, null, null, 0);
setupLocationPermissions(Build.VERSION_CODES.Q, true, AppOpsManager.OPSTR_FINE_LOCATION,
@@ -6795,7 +6825,7 @@ public class ConnectivityServiceTest {
nc.setAdministratorUids(Arrays.asList(Process.myUid()));
final NetworkAgentInfo naiWithUid =
new NetworkAgentInfo(
- null, null, null, null, null, nc, null, mServiceContext, null, null,
+ null, null, null, null, null, nc, 0, mServiceContext, null, null,
mService, null, null, null, 0);
setupLocationPermissions(Build.VERSION_CODES.Q, true, AppOpsManager.OPSTR_FINE_LOCATION,
diff --git a/tests/net/java/com/android/server/connectivity/LingerMonitorTest.java b/tests/net/java/com/android/server/connectivity/LingerMonitorTest.java
index e863266c4b49..24a87177224e 100644
--- a/tests/net/java/com/android/server/connectivity/LingerMonitorTest.java
+++ b/tests/net/java/com/android/server/connectivity/LingerMonitorTest.java
@@ -38,7 +38,6 @@ import android.net.Network;
import android.net.NetworkCapabilities;
import android.net.NetworkInfo;
import android.net.NetworkProvider;
-import android.net.NetworkScore;
import android.os.INetworkManagementService;
import android.text.format.DateUtils;
@@ -353,10 +352,8 @@ public class LingerMonitorTest {
NetworkCapabilities caps = new NetworkCapabilities();
caps.addCapability(0);
caps.addTransportType(transport);
- NetworkScore ns = new NetworkScore();
- ns.putIntExtension(NetworkScore.LEGACY_SCORE, 50);
NetworkAgentInfo nai = new NetworkAgentInfo(null, null, new Network(netId), info, null,
- caps, ns, mCtx, null, null /* config */, mConnService, mNetd, mDnsResolver, mNMS,
+ caps, 50, mCtx, null, null /* config */, mConnService, mNetd, mDnsResolver, mNMS,
NetworkProvider.ID_NONE);
nai.everValidated = true;
return nai;
diff --git a/tests/net/java/com/android/server/connectivity/NetworkNotificationManagerTest.java b/tests/net/java/com/android/server/connectivity/NetworkNotificationManagerTest.java
index d57f2250fc5c..47db5d431671 100644
--- a/tests/net/java/com/android/server/connectivity/NetworkNotificationManagerTest.java
+++ b/tests/net/java/com/android/server/connectivity/NetworkNotificationManagerTest.java
@@ -238,20 +238,6 @@ public class NetworkNotificationManagerTest {
}
@Test
- public void testSameLevelNotifications() {
- final int id = 101;
- final String tag = NetworkNotificationManager.tagFor(id);
-
- mManager.showNotification(id, LOGGED_IN, mWifiNai, mCellNai, null, false);
- verify(mNotificationManager, times(1))
- .notifyAsUser(eq(tag), eq(LOGGED_IN.eventId), any(), any());
-
- mManager.showNotification(id, LOST_INTERNET, mWifiNai, mCellNai, null, false);
- verify(mNotificationManager, times(1))
- .notifyAsUser(eq(tag), eq(LOST_INTERNET.eventId), any(), any());
- }
-
- @Test
public void testClearNotificationByType() {
final int id = 101;
final String tag = NetworkNotificationManager.tagFor(id);
@@ -259,31 +245,25 @@ public class NetworkNotificationManagerTest {
// clearNotification(int id, NotificationType notifyType) will check if given type is equal
// to previous type or not. If they are equal then clear the notification; if they are not
// equal then return.
-
- mManager.showNotification(id, LOGGED_IN, mWifiNai, mCellNai, null, false);
+ mManager.showNotification(id, NO_INTERNET, mWifiNai, mCellNai, null, false);
verify(mNotificationManager, times(1))
- .notifyAsUser(eq(tag), eq(LOGGED_IN.eventId), any(), any());
+ .notifyAsUser(eq(tag), eq(NO_INTERNET.eventId), any(), any());
- // Previous notification is LOGGED_IN and given type is LOGGED_IN too. The notification
+ // Previous notification is NO_INTERNET and given type is NO_INTERNET too. The notification
// should be cleared.
- mManager.clearNotification(id, LOGGED_IN);
+ mManager.clearNotification(id, NO_INTERNET);
verify(mNotificationManager, times(1))
- .cancelAsUser(eq(tag), eq(LOGGED_IN.eventId), any());
-
- mManager.showNotification(id, LOGGED_IN, mWifiNai, mCellNai, null, false);
- verify(mNotificationManager, times(2))
- .notifyAsUser(eq(tag), eq(LOGGED_IN.eventId), any(), any());
+ .cancelAsUser(eq(tag), eq(NO_INTERNET.eventId), any());
- // LOST_INTERNET notification popup after LOGGED_IN notification.
- mManager.showNotification(id, LOST_INTERNET, mWifiNai, mCellNai, null, false);
+ // SIGN_IN is popped-up.
+ mManager.showNotification(id, SIGN_IN, mWifiNai, mCellNai, null, false);
verify(mNotificationManager, times(1))
- .notifyAsUser(eq(tag), eq(LOST_INTERNET.eventId), any(), any());
+ .notifyAsUser(eq(tag), eq(SIGN_IN.eventId), any(), any());
- // Previous notification is LOST_INTERNET and given type is LOGGED_IN. The notification
- // shouldn't be cleared.
- mManager.clearNotification(id, LOGGED_IN);
- // LOST_INTERNET shouldn't be cleared.
+ // The notification type is not matching previous one, PARTIAL_CONNECTIVITY won't be
+ // cleared.
+ mManager.clearNotification(id, PARTIAL_CONNECTIVITY);
verify(mNotificationManager, never())
- .cancelAsUser(eq(tag), eq(LOST_INTERNET.eventId), any());
+ .cancelAsUser(eq(tag), eq(PARTIAL_CONNECTIVITY.eventId), any());
}
}
diff --git a/tools/codegen/src/com/android/codegen/ClassPrinter.kt b/tools/codegen/src/com/android/codegen/ClassPrinter.kt
index c7c80bab67bf..b90e1bb3e7e7 100644
--- a/tools/codegen/src/com/android/codegen/ClassPrinter.kt
+++ b/tools/codegen/src/com/android/codegen/ClassPrinter.kt
@@ -100,7 +100,7 @@ class ClassPrinter(
?: emptyMap()
val internalAnnotations = setOf(ParcelWith, DataClassEnum, PluralOf, UnsupportedAppUsage,
- DataClassSuppressConstDefs)
+ DataClassSuppressConstDefs, MaySetToNull, Each, DataClass)
val knownNonValidationAnnotations = internalAnnotations + Each + Nullable
/**
diff --git a/tools/codegen/src/com/android/codegen/FieldInfo.kt b/tools/codegen/src/com/android/codegen/FieldInfo.kt
index ebfbbd8163b5..02ebaef90f0b 100644
--- a/tools/codegen/src/com/android/codegen/FieldInfo.kt
+++ b/tools/codegen/src/com/android/codegen/FieldInfo.kt
@@ -147,9 +147,19 @@ data class FieldInfo(
val sParcelling by lazy { customParcellingClass?.let { "sParcellingFor$NameUpperCamel" } }
val SetterParamType = if (isArray) "$FieldInnerType..." else Type
- val annotatedTypeForSetterParam by lazy {
- (annotationsNoInternal + SetterParamType).joinToString(" ")
+ val annotationsForSetterParam by lazy {
+ buildList<String> {
+ addAll(annotationsNoInternal)
+ classPrinter {
+ if ("@$Nullable" in annotations
+ && "@$MaySetToNull" !in annotations) {
+ remove("@$Nullable")
+ add("@$NonNull")
+ }
+ }
+ }.joinToString(" ")
}
+ val annotatedTypeForSetterParam by lazy { "$annotationsForSetterParam $SetterParamType" }
// Utilities
diff --git a/tools/codegen/src/com/android/codegen/Generators.kt b/tools/codegen/src/com/android/codegen/Generators.kt
index 8fe243ff68cb..5a96cf1d9bdb 100644
--- a/tools/codegen/src/com/android/codegen/Generators.kt
+++ b/tools/codegen/src/com/android/codegen/Generators.kt
@@ -315,7 +315,7 @@ private fun ClassPrinter.generateBuilderSetters(visibility: String) {
generateBuilderMethod(
name = setterName,
defVisibility = visibility,
- paramAnnotations = annotationsNoInternal.joinToString(" "),
+ paramAnnotations = annotationsForSetterParam,
paramTypes = listOf(SetterParamType),
genJavadoc = { generateFieldJavadoc() }) {
+"checkNotUsed();"
diff --git a/tools/codegen/src/com/android/codegen/ImportsProvider.kt b/tools/codegen/src/com/android/codegen/ImportsProvider.kt
index c830aaa0df3d..27dd9587db25 100644
--- a/tools/codegen/src/com/android/codegen/ImportsProvider.kt
+++ b/tools/codegen/src/com/android/codegen/ImportsProvider.kt
@@ -39,6 +39,7 @@ interface ImportsProvider {
val ParcelWith: String get() { return classRef("com.android.internal.util.DataClass.ParcelWith") }
val PluralOf: String get() { return classRef("com.android.internal.util.DataClass.PluralOf") }
val Each: String get() { return classRef("com.android.internal.util.DataClass.Each") }
+ val MaySetToNull: String get() { return classRef("com.android.internal.util.DataClass.MaySetToNull") }
val DataClassGenerated: String get() { return classRef("com.android.internal.util.DataClass.Generated") }
val DataClassSuppressConstDefs: String get() { return classRef("com.android.internal.util.DataClass.SuppressConstDefsGeneration") }
val DataClassSuppress: String get() { return classRef("com.android.internal.util.DataClass.Suppress") }
diff --git a/tools/codegen/src/com/android/codegen/SharedConstants.kt b/tools/codegen/src/com/android/codegen/SharedConstants.kt
index 74c86f4551f8..6f740cd663e3 100644
--- a/tools/codegen/src/com/android/codegen/SharedConstants.kt
+++ b/tools/codegen/src/com/android/codegen/SharedConstants.kt
@@ -1,7 +1,7 @@
package com.android.codegen
const val CODEGEN_NAME = "codegen"
-const val CODEGEN_VERSION = "1.0.14"
+const val CODEGEN_VERSION = "1.0.15"
const val CANONICAL_BUILDER_CLASS = "Builder"
const val BASE_BUILDER_CLASS = "BaseBuilder"
diff --git a/tools/stats_log_api_gen/Android.bp b/tools/stats_log_api_gen/Android.bp
index 843e82023afe..cbf6fe88e565 100644
--- a/tools/stats_log_api_gen/Android.bp
+++ b/tools/stats_log_api_gen/Android.bp
@@ -26,11 +26,9 @@ cc_binary_host {
"java_writer_q.cpp",
"main.cpp",
"native_writer.cpp",
- "native_writer_q.cpp",
"utils.cpp",
],
cflags: [
- //"-DSTATS_SCHEMA_LEGACY",
"-Wall",
"-Werror",
],
diff --git a/tools/stats_log_api_gen/Collation.cpp b/tools/stats_log_api_gen/Collation.cpp
index 8bccd7150050..66c4b1488b83 100644
--- a/tools/stats_log_api_gen/Collation.cpp
+++ b/tools/stats_log_api_gen/Collation.cpp
@@ -53,8 +53,7 @@ AtomDecl::AtomDecl(const AtomDecl &that)
uidField(that.uidField),
whitelisted(that.whitelisted),
binaryFields(that.binaryFields),
- hasModule(that.hasModule),
- moduleName(that.moduleName) {}
+ moduleNames(that.moduleNames) {}
AtomDecl::AtomDecl(int c, const string& n, const string& m)
:code(c),
@@ -237,6 +236,16 @@ int collate_atom(const Descriptor *atom, AtomDecl *atomDecl,
errorCount++;
continue;
}
+
+ if (field->is_repeated() &&
+ !(javaType == JAVA_TYPE_ATTRIBUTION_CHAIN || javaType == JAVA_TYPE_KEY_VALUE_PAIR)) {
+ print_error(field,
+ "Repeated fields are not supported in atoms. Please make field %s not "
+ "repeated.\n",
+ field->name().c_str());
+ errorCount++;
+ continue;
+ }
}
// Check that if there's an attribution chain, it's at position 1.
@@ -432,9 +441,9 @@ int collate_atoms(const Descriptor *descriptor, Atoms *atoms) {
atomDecl.whitelisted = true;
}
- if (atomField->options().HasExtension(os::statsd::module)) {
- atomDecl.hasModule = true;
- atomDecl.moduleName = atomField->options().GetExtension(os::statsd::module);
+ for (int j = 0; j < atomField->options().ExtensionSize(os::statsd::module); ++j) {
+ const string moduleName = atomField->options().GetExtension(os::statsd::module, j);
+ atomDecl.moduleNames.insert(moduleName);
}
vector<java_type_t> signature;
@@ -443,36 +452,15 @@ int collate_atoms(const Descriptor *descriptor, Atoms *atoms) {
errorCount++;
}
- // Add the signature if does not already exist.
- auto signature_to_modules_it = atoms->signatures_to_modules.find(signature);
- if (signature_to_modules_it == atoms->signatures_to_modules.end()) {
- set<string> modules;
- if (atomDecl.hasModule) {
- modules.insert(atomDecl.moduleName);
- }
- atoms->signatures_to_modules[signature] = modules;
- } else {
- if (atomDecl.hasModule) {
- signature_to_modules_it->second.insert(atomDecl.moduleName);
- }
- }
+ atoms->signatures_to_modules[signature].insert(
+ atomDecl.moduleNames.begin(), atomDecl.moduleNames.end());
atoms->decls.insert(atomDecl);
AtomDecl nonChainedAtomDecl(atomField->number(), atomField->name(), atom->name());
vector<java_type_t> nonChainedSignature;
if (get_non_chained_node(atom, &nonChainedAtomDecl, &nonChainedSignature)) {
- auto it = atoms->non_chained_signatures_to_modules.find(nonChainedSignature);
- if (it == atoms->non_chained_signatures_to_modules.end()) {
- set<string> modules_non_chained;
- if (atomDecl.hasModule) {
- modules_non_chained.insert(atomDecl.moduleName);
- }
- atoms->non_chained_signatures_to_modules[nonChainedSignature] = modules_non_chained;
- } else {
- if (atomDecl.hasModule) {
- it->second.insert(atomDecl.moduleName);
- }
- }
+ atoms->non_chained_signatures_to_modules[nonChainedSignature].insert(
+ atomDecl.moduleNames.begin(), atomDecl.moduleNames.end());
atoms->non_chained_decls.insert(nonChainedAtomDecl);
}
diff --git a/tools/stats_log_api_gen/Collation.h b/tools/stats_log_api_gen/Collation.h
index 65d8e3efee5b..ace85e06f12d 100644
--- a/tools/stats_log_api_gen/Collation.h
+++ b/tools/stats_log_api_gen/Collation.h
@@ -98,8 +98,7 @@ struct AtomDecl {
vector<int> binaryFields;
- bool hasModule = false;
- string moduleName;
+ set<string> moduleNames;
AtomDecl();
AtomDecl(const AtomDecl& that);
diff --git a/tools/stats_log_api_gen/atoms_info_writer.cpp b/tools/stats_log_api_gen/atoms_info_writer.cpp
index 984c929f63bd..58f13a4c1934 100644
--- a/tools/stats_log_api_gen/atoms_info_writer.cpp
+++ b/tools/stats_log_api_gen/atoms_info_writer.cpp
@@ -58,19 +58,25 @@ static void write_atoms_info_header_body(FILE* out, const Atoms& atoms) {
}
static void write_atoms_info_cpp_body(FILE* out, const Atoms& atoms) {
- std::set<string> kTruncatingAtomNames = {"mobile_radio_power_state_changed",
- "audio_state_changed",
- "call_state_changed",
- "phone_signal_strength_changed",
- "mobile_bytes_transfer_by_fg_bg",
- "mobile_bytes_transfer"};
+ std::set<string> kTruncatingAtomNames = {
+ "mobile_radio_power_state_changed",
+ "audio_state_changed",
+ "call_state_changed",
+ "phone_signal_strength_changed",
+ "mobile_bytes_transfer_by_fg_bg",
+ "mobile_bytes_transfer"
+ };
fprintf(out,
"const std::set<int> "
"AtomsInfo::kTruncatingTimestampAtomBlackList = {\n");
- for (set<string>::const_iterator blacklistedAtom = kTruncatingAtomNames.begin();
- blacklistedAtom != kTruncatingAtomNames.end(); blacklistedAtom++) {
- fprintf(out, " %s,\n", make_constant_name(*blacklistedAtom).c_str());
+ for (set<AtomDecl>::const_iterator atom = atoms.decls.begin();
+ atom != atoms.decls.end(); atom++) {
+ if (kTruncatingAtomNames.find(atom->name) != kTruncatingAtomNames.end()) {
+ const string constant = make_constant_name(atom->name);
+ fprintf(out, " %d, // %s\n", atom->code, constant.c_str());
+ }
}
+
fprintf(out, "};\n");
fprintf(out, "\n");
@@ -81,8 +87,8 @@ static void write_atoms_info_cpp_body(FILE* out, const Atoms& atoms) {
for (vector<AtomField>::const_iterator field = atom->fields.begin();
field != atom->fields.end(); field++) {
if (field->javaType == JAVA_TYPE_ATTRIBUTION_CHAIN) {
- string constant = make_constant_name(atom->name);
- fprintf(out, " %s,\n", constant.c_str());
+ const string constant = make_constant_name(atom->name);
+ fprintf(out, " %d, // %s\n", atom->code, constant.c_str());
break;
}
}
@@ -96,8 +102,8 @@ static void write_atoms_info_cpp_body(FILE* out, const Atoms& atoms) {
for (set<AtomDecl>::const_iterator atom = atoms.decls.begin();
atom != atoms.decls.end(); atom++) {
if (atom->whitelisted) {
- string constant = make_constant_name(atom->name);
- fprintf(out, " %s,\n", constant.c_str());
+ const string constant = make_constant_name(atom->name);
+ fprintf(out, " %d, // %s\n", atom->code, constant.c_str());
}
}
@@ -105,7 +111,7 @@ static void write_atoms_info_cpp_body(FILE* out, const Atoms& atoms) {
fprintf(out, "\n");
fprintf(out, "static std::map<int, int> getAtomUidField() {\n");
- fprintf(out, " std::map<int, int> uidField;\n");
+ fprintf(out, " std::map<int, int> uidField;\n");
for (set<AtomDecl>::const_iterator atom = atoms.decls.begin();
atom != atoms.decls.end(); atom++) {
if (atom->uidField == 0) {
@@ -115,8 +121,8 @@ static void write_atoms_info_cpp_body(FILE* out, const Atoms& atoms) {
"\n // Adding uid field for atom "
"(%d)%s\n",
atom->code, atom->name.c_str());
- fprintf(out, " uidField[static_cast<int>(%s)] = %d;\n",
- make_constant_name(atom->name).c_str(), atom->uidField);
+ fprintf(out, " uidField[%d /* %s */] = %d;\n",
+ atom->code, make_constant_name(atom->name).c_str(), atom->uidField);
}
fprintf(out, " return uidField;\n");
@@ -140,8 +146,8 @@ static void write_atoms_info_cpp_body(FILE* out, const Atoms& atoms) {
"\n // Adding primary and exclusive fields for atom "
"(%d)%s\n",
atom->code, atom->name.c_str());
- fprintf(out, " opt = &(options[static_cast<int>(%s)]);\n",
- make_constant_name(atom->name).c_str());
+ fprintf(out, " opt = &(options[%d /* %s */]);\n",
+ atom->code, make_constant_name(atom->name).c_str());
fprintf(out, " opt->primaryFields.reserve(%lu);\n", atom->primaryFields.size());
for (const auto& field : atom->primaryFields) {
fprintf(out, " opt->primaryFields.push_back(%d);\n", field);
@@ -185,8 +191,8 @@ static void write_atoms_info_cpp_body(FILE* out, const Atoms& atoms) {
atom->code, atom->name.c_str());
for (const auto& field : atom->binaryFields) {
- fprintf(out, " options[static_cast<int>(%s)].push_back(%d);\n",
- make_constant_name(atom->name).c_str(), field);
+ fprintf(out, " options[%d /* %s */].push_back(%d);\n",
+ atom->code, make_constant_name(atom->name).c_str(), field);
}
}
@@ -222,12 +228,11 @@ int write_atoms_info_header(FILE* out, const Atoms &atoms, const string& namespa
}
int write_atoms_info_cpp(FILE *out, const Atoms &atoms, const string& namespaceStr,
- const string& importHeader, const string& statslogHeader) {
+ const string& importHeader) {
// Print prelude
fprintf(out, "// This file is autogenerated\n");
fprintf(out, "\n");
fprintf(out, "#include <%s>\n", importHeader.c_str());
- fprintf(out, "#include <%s>\n", statslogHeader.c_str());
fprintf(out, "\n");
write_namespace(out, namespaceStr);
diff --git a/tools/stats_log_api_gen/atoms_info_writer.h b/tools/stats_log_api_gen/atoms_info_writer.h
index 12ac862871ef..d04e65a1b060 100644
--- a/tools/stats_log_api_gen/atoms_info_writer.h
+++ b/tools/stats_log_api_gen/atoms_info_writer.h
@@ -27,7 +27,7 @@ namespace stats_log_api_gen {
using namespace std;
int write_atoms_info_cpp(FILE* out, const Atoms& atoms, const string& namespaceStr,
- const string& importHeader, const string& statslogHeader);
+ const string& importHeader);
int write_atoms_info_header(FILE* out, const Atoms& atoms, const string& namespaceStr);
diff --git a/tools/stats_log_api_gen/java_writer.cpp b/tools/stats_log_api_gen/java_writer.cpp
index c29936b96c14..209d511c8a05 100644
--- a/tools/stats_log_api_gen/java_writer.cpp
+++ b/tools/stats_log_api_gen/java_writer.cpp
@@ -59,9 +59,6 @@ static int write_java_methods(
}
// Print method signature.
- if (DEFAULT_MODULE_NAME == moduleName) {
- fprintf(out, " /** @hide */\n");
- }
fprintf(out, " public static void write(int code");
vector<java_type_t> signature = signature_to_modules_it->first;
int argIndex = 1;
@@ -273,9 +270,6 @@ int write_stats_log_java(FILE* out, const Atoms& atoms, const AtomDecl &attribut
fprintf(out, "\n");
fprintf(out, "/**\n");
fprintf(out, " * Utility class for logging statistics events.\n");
- if (DEFAULT_MODULE_NAME == moduleName) {
- fprintf(out, " * @hide\n");
- }
fprintf(out, " */\n");
fprintf(out, "public class %s {\n", javaClass.c_str());
diff --git a/tools/stats_log_api_gen/java_writer_q.cpp b/tools/stats_log_api_gen/java_writer_q.cpp
index 12c050d8ef8d..8f2112a03e46 100644
--- a/tools/stats_log_api_gen/java_writer_q.cpp
+++ b/tools/stats_log_api_gen/java_writer_q.cpp
@@ -609,69 +609,5 @@ int write_stats_log_java_q_for_module(FILE* out, const Atoms& atoms,
return errors;
}
-#if defined(STATS_SCHEMA_LEGACY)
-static void write_java_method(
- FILE* out,
- const string& method_name,
- const map<vector<java_type_t>, set<string>>& signatures_to_modules,
- const AtomDecl &attributionDecl) {
-
- for (auto signature_to_modules_it = signatures_to_modules.begin();
- signature_to_modules_it != signatures_to_modules.end(); signature_to_modules_it++) {
- vector<java_type_t> signature = signature_to_modules_it->first;
- fprintf(out, " /** @hide */\n");
- fprintf(out, " public static native int %s(int code", method_name.c_str());
- int argIndex = 1;
- for (vector<java_type_t>::const_iterator arg = signature.begin();
- arg != signature.end(); arg++) {
- if (*arg == JAVA_TYPE_ATTRIBUTION_CHAIN) {
- for (auto chainField : attributionDecl.fields) {
- fprintf(out, ", %s[] %s",
- java_type_name(chainField.javaType), chainField.name.c_str());
- }
- } else if (*arg == JAVA_TYPE_KEY_VALUE_PAIR) {
- fprintf(out, ", android.util.SparseArray<Object> valueMap");
- } else {
- fprintf(out, ", %s arg%d", java_type_name(*arg), argIndex);
- }
- argIndex++;
- }
- fprintf(out, ");\n");
- fprintf(out, "\n");
- }
-}
-
-int write_stats_log_java_q(FILE* out, const Atoms& atoms, const AtomDecl &attributionDecl,
- const bool supportWorkSource) {
- // Print prelude
- fprintf(out, "// This file is autogenerated\n");
- fprintf(out, "\n");
- fprintf(out, "package android.util;\n");
- fprintf(out, "\n");
- fprintf(out, "\n");
- fprintf(out, "/**\n");
- fprintf(out, " * API For logging statistics events.\n");
- fprintf(out, " * @hide\n");
- fprintf(out, " */\n");
- fprintf(out, "public class StatsLogInternal {\n");
- write_java_atom_codes(out, atoms, DEFAULT_MODULE_NAME);
-
- write_java_enum_values(out, atoms, DEFAULT_MODULE_NAME);
-
- // Print write methods
- fprintf(out, " // Write methods\n");
- write_java_method(out, "write", atoms.signatures_to_modules, attributionDecl);
- write_java_method(out, "write_non_chained", atoms.non_chained_signatures_to_modules,
- attributionDecl);
- if (supportWorkSource) {
- write_java_work_source_methods(out, atoms.signatures_to_modules, DEFAULT_MODULE_NAME);
- }
-
- fprintf(out, "}\n");
-
- return 0;
-}
-#endif
-
} // namespace stats_log_api_gen
} // namespace android
diff --git a/tools/stats_log_api_gen/java_writer_q.h b/tools/stats_log_api_gen/java_writer_q.h
index 7d734df1e118..6ccb225ce973 100644
--- a/tools/stats_log_api_gen/java_writer_q.h
+++ b/tools/stats_log_api_gen/java_writer_q.h
@@ -49,9 +49,5 @@ int write_stats_log_java_q_for_module(FILE* out, const Atoms& atoms,
const AtomDecl &attributionDecl, const string& moduleName, const string& javaClass,
const string& javaPackage, const bool supportWorkSource);
-#if defined(STATS_SCHEMA_LEGACY)
-int write_stats_log_java_q(FILE* out, const Atoms& atoms, const AtomDecl &attributionDecl,
- const bool supportWorkSource);
-#endif
} // namespace stats_log_api_gen
} // namespace android
diff --git a/tools/stats_log_api_gen/main.cpp b/tools/stats_log_api_gen/main.cpp
index ddbf22c7f12a..e9723a114e88 100644
--- a/tools/stats_log_api_gen/main.cpp
+++ b/tools/stats_log_api_gen/main.cpp
@@ -1,10 +1,7 @@
-
#include "Collation.h"
#include "atoms_info_writer.h"
-#if !defined(STATS_SCHEMA_LEGACY)
#include "java_writer.h"
-#endif
#include "java_writer_q.h"
#include "native_writer.h"
#include "utils.h"
@@ -28,463 +25,6 @@ namespace stats_log_api_gen {
using android::os::statsd::Atom;
-// Hide the JNI write helpers that are not used in the new schema.
-// TODO(b/145100015): Remove this and other JNI related functionality once StatsEvent migration is
-// complete.
-#if defined(STATS_SCHEMA_LEGACY)
-// JNI helpers.
-static const char*
-jni_type_name(java_type_t type)
-{
- switch (type) {
- case JAVA_TYPE_BOOLEAN:
- return "jboolean";
- case JAVA_TYPE_INT:
- case JAVA_TYPE_ENUM:
- return "jint";
- case JAVA_TYPE_LONG:
- return "jlong";
- case JAVA_TYPE_FLOAT:
- return "jfloat";
- case JAVA_TYPE_DOUBLE:
- return "jdouble";
- case JAVA_TYPE_STRING:
- return "jstring";
- case JAVA_TYPE_BYTE_ARRAY:
- return "jbyteArray";
- default:
- return "UNKNOWN";
- }
-}
-
-static const char*
-jni_array_type_name(java_type_t type)
-{
- switch (type) {
- case JAVA_TYPE_INT:
- return "jintArray";
- case JAVA_TYPE_FLOAT:
- return "jfloatArray";
- case JAVA_TYPE_STRING:
- return "jobjectArray";
- default:
- return "UNKNOWN";
- }
-}
-
-static string
-jni_function_name(const string& method_name, const vector<java_type_t>& signature)
-{
- string result("StatsLog_" + method_name);
- for (vector<java_type_t>::const_iterator arg = signature.begin();
- arg != signature.end(); arg++) {
- switch (*arg) {
- case JAVA_TYPE_BOOLEAN:
- result += "_boolean";
- break;
- case JAVA_TYPE_INT:
- case JAVA_TYPE_ENUM:
- result += "_int";
- break;
- case JAVA_TYPE_LONG:
- result += "_long";
- break;
- case JAVA_TYPE_FLOAT:
- result += "_float";
- break;
- case JAVA_TYPE_DOUBLE:
- result += "_double";
- break;
- case JAVA_TYPE_STRING:
- result += "_String";
- break;
- case JAVA_TYPE_ATTRIBUTION_CHAIN:
- result += "_AttributionChain";
- break;
- case JAVA_TYPE_KEY_VALUE_PAIR:
- result += "_KeyValuePairs";
- break;
- case JAVA_TYPE_BYTE_ARRAY:
- result += "_bytes";
- break;
- default:
- result += "_UNKNOWN";
- break;
- }
- }
- return result;
-}
-
-static const char*
-java_type_signature(java_type_t type)
-{
- switch (type) {
- case JAVA_TYPE_BOOLEAN:
- return "Z";
- case JAVA_TYPE_INT:
- case JAVA_TYPE_ENUM:
- return "I";
- case JAVA_TYPE_LONG:
- return "J";
- case JAVA_TYPE_FLOAT:
- return "F";
- case JAVA_TYPE_DOUBLE:
- return "D";
- case JAVA_TYPE_STRING:
- return "Ljava/lang/String;";
- case JAVA_TYPE_BYTE_ARRAY:
- return "[B";
- default:
- return "UNKNOWN";
- }
-}
-
-static string
-jni_function_signature(const vector<java_type_t>& signature, const AtomDecl &attributionDecl)
-{
- string result("(I");
- for (vector<java_type_t>::const_iterator arg = signature.begin();
- arg != signature.end(); arg++) {
- if (*arg == JAVA_TYPE_ATTRIBUTION_CHAIN) {
- for (auto chainField : attributionDecl.fields) {
- result += "[";
- result += java_type_signature(chainField.javaType);
- }
- } else if (*arg == JAVA_TYPE_KEY_VALUE_PAIR) {
- result += "Landroid/util/SparseArray;";
- } else {
- result += java_type_signature(*arg);
- }
- }
- result += ")I";
- return result;
-}
-
-static void write_key_value_map_jni(FILE* out) {
- fprintf(out, " std::map<int, int32_t> int32_t_map;\n");
- fprintf(out, " std::map<int, int64_t> int64_t_map;\n");
- fprintf(out, " std::map<int, float> float_map;\n");
- fprintf(out, " std::map<int, char const*> string_map;\n\n");
-
- fprintf(out, " jclass jmap_class = env->FindClass(\"android/util/SparseArray\");\n");
-
- fprintf(out, " jmethodID jget_size_method = env->GetMethodID(jmap_class, \"size\", \"()I\");\n");
- fprintf(out, " jmethodID jget_key_method = env->GetMethodID(jmap_class, \"keyAt\", \"(I)I\");\n");
- fprintf(out, " jmethodID jget_value_method = env->GetMethodID(jmap_class, \"valueAt\", \"(I)Ljava/lang/Object;\");\n\n");
-
-
- fprintf(out, " std::vector<std::unique_ptr<ScopedUtfChars>> scoped_ufs;\n\n");
-
- fprintf(out, " jclass jint_class = env->FindClass(\"java/lang/Integer\");\n");
- fprintf(out, " jclass jlong_class = env->FindClass(\"java/lang/Long\");\n");
- fprintf(out, " jclass jfloat_class = env->FindClass(\"java/lang/Float\");\n");
- fprintf(out, " jclass jstring_class = env->FindClass(\"java/lang/String\");\n");
- fprintf(out, " jmethodID jget_int_method = env->GetMethodID(jint_class, \"intValue\", \"()I\");\n");
- fprintf(out, " jmethodID jget_long_method = env->GetMethodID(jlong_class, \"longValue\", \"()J\");\n");
- fprintf(out, " jmethodID jget_float_method = env->GetMethodID(jfloat_class, \"floatValue\", \"()F\");\n\n");
-
- fprintf(out, " jint jsize = env->CallIntMethod(value_map, jget_size_method);\n");
- fprintf(out, " for(int i = 0; i < jsize; i++) {\n");
- fprintf(out, " jint key = env->CallIntMethod(value_map, jget_key_method, i);\n");
- fprintf(out, " jobject jvalue_obj = env->CallObjectMethod(value_map, jget_value_method, i);\n");
- fprintf(out, " if (jvalue_obj == NULL) { continue; }\n");
- fprintf(out, " if (env->IsInstanceOf(jvalue_obj, jint_class)) {\n");
- fprintf(out, " int32_t_map[key] = env->CallIntMethod(jvalue_obj, jget_int_method);\n");
- fprintf(out, " } else if (env->IsInstanceOf(jvalue_obj, jlong_class)) {\n");
- fprintf(out, " int64_t_map[key] = env->CallLongMethod(jvalue_obj, jget_long_method);\n");
- fprintf(out, " } else if (env->IsInstanceOf(jvalue_obj, jfloat_class)) {\n");
- fprintf(out, " float_map[key] = env->CallFloatMethod(jvalue_obj, jget_float_method);\n");
- fprintf(out, " } else if (env->IsInstanceOf(jvalue_obj, jstring_class)) {\n");
- fprintf(out, " std::unique_ptr<ScopedUtfChars> utf(new ScopedUtfChars(env, (jstring)jvalue_obj));\n");
- fprintf(out, " if (utf->c_str() != NULL) { string_map[key] = utf->c_str(); }\n");
- fprintf(out, " scoped_ufs.push_back(std::move(utf));\n");
- fprintf(out, " }\n");
- fprintf(out, " }\n");
-}
-
-static int
-write_stats_log_jni_method(FILE* out, const string& java_method_name, const string& cpp_method_name,
- const map<vector<java_type_t>, set<string>>& signatures_to_modules,
- const AtomDecl &attributionDecl) {
- // Print write methods
- for (auto signature_to_modules_it = signatures_to_modules.begin();
- signature_to_modules_it != signatures_to_modules.end(); signature_to_modules_it++) {
- vector<java_type_t> signature = signature_to_modules_it->first;
- int argIndex;
-
- fprintf(out, "static int\n");
- fprintf(out, "%s(JNIEnv* env, jobject clazz UNUSED, jint code",
- jni_function_name(java_method_name, signature).c_str());
- argIndex = 1;
- for (vector<java_type_t>::const_iterator arg = signature.begin();
- arg != signature.end(); arg++) {
- if (*arg == JAVA_TYPE_ATTRIBUTION_CHAIN) {
- for (auto chainField : attributionDecl.fields) {
- fprintf(out, ", %s %s", jni_array_type_name(chainField.javaType),
- chainField.name.c_str());
- }
- } else if (*arg == JAVA_TYPE_KEY_VALUE_PAIR) {
- fprintf(out, ", jobject value_map");
- } else {
- fprintf(out, ", %s arg%d", jni_type_name(*arg), argIndex);
- }
- argIndex++;
- }
- fprintf(out, ")\n");
-
- fprintf(out, "{\n");
-
- // Prepare strings
- argIndex = 1;
- bool hadStringOrChain = false;
- bool isKeyValuePairAtom = false;
- for (vector<java_type_t>::const_iterator arg = signature.begin();
- arg != signature.end(); arg++) {
- if (*arg == JAVA_TYPE_STRING) {
- hadStringOrChain = true;
- fprintf(out, " const char* str%d;\n", argIndex);
- fprintf(out, " if (arg%d != NULL) {\n", argIndex);
- fprintf(out, " str%d = env->GetStringUTFChars(arg%d, NULL);\n",
- argIndex, argIndex);
- fprintf(out, " } else {\n");
- fprintf(out, " str%d = NULL;\n", argIndex);
- fprintf(out, " }\n");
- } else if (*arg == JAVA_TYPE_BYTE_ARRAY) {
- hadStringOrChain = true;
- fprintf(out, " jbyte* jbyte_array%d;\n", argIndex);
- fprintf(out, " const char* str%d;\n", argIndex);
- fprintf(out, " int str%d_length = 0;\n", argIndex);
- fprintf(out,
- " if (arg%d != NULL && env->GetArrayLength(arg%d) > "
- "0) {\n",
- argIndex, argIndex);
- fprintf(out,
- " jbyte_array%d = "
- "env->GetByteArrayElements(arg%d, NULL);\n",
- argIndex, argIndex);
- fprintf(out,
- " str%d_length = env->GetArrayLength(arg%d);\n",
- argIndex, argIndex);
- fprintf(out,
- " str%d = "
- "reinterpret_cast<char*>(env->GetByteArrayElements(arg%"
- "d, NULL));\n",
- argIndex, argIndex);
- fprintf(out, " } else {\n");
- fprintf(out, " jbyte_array%d = NULL;\n", argIndex);
- fprintf(out, " str%d = NULL;\n", argIndex);
- fprintf(out, " }\n");
-
- fprintf(out,
- " android::util::BytesField bytesField%d(str%d, "
- "str%d_length);",
- argIndex, argIndex, argIndex);
-
- } else if (*arg == JAVA_TYPE_ATTRIBUTION_CHAIN) {
- hadStringOrChain = true;
- for (auto chainField : attributionDecl.fields) {
- fprintf(out, " size_t %s_length = env->GetArrayLength(%s);\n",
- chainField.name.c_str(), chainField.name.c_str());
- if (chainField.name != attributionDecl.fields.front().name) {
- fprintf(out, " if (%s_length != %s_length) {\n",
- chainField.name.c_str(),
- attributionDecl.fields.front().name.c_str());
- fprintf(out, " return -EINVAL;\n");
- fprintf(out, " }\n");
- }
- if (chainField.javaType == JAVA_TYPE_INT) {
- fprintf(out, " jint* %s_array = env->GetIntArrayElements(%s, NULL);\n",
- chainField.name.c_str(), chainField.name.c_str());
- } else if (chainField.javaType == JAVA_TYPE_STRING) {
- fprintf(out, " std::vector<%s> %s_vec;\n",
- cpp_type_name(chainField.javaType), chainField.name.c_str());
- fprintf(out, " std::vector<ScopedUtfChars*> scoped_%s_vec;\n",
- chainField.name.c_str());
- fprintf(out, " for (size_t i = 0; i < %s_length; ++i) {\n",
- chainField.name.c_str());
- fprintf(out, " jstring jstr = "
- "(jstring)env->GetObjectArrayElement(%s, i);\n",
- chainField.name.c_str());
- fprintf(out, " if (jstr == NULL) {\n");
- fprintf(out, " %s_vec.push_back(NULL);\n",
- chainField.name.c_str());
- fprintf(out, " } else {\n");
- fprintf(out, " ScopedUtfChars* scoped_%s = "
- "new ScopedUtfChars(env, jstr);\n",
- chainField.name.c_str());
- fprintf(out, " %s_vec.push_back(scoped_%s->c_str());\n",
- chainField.name.c_str(), chainField.name.c_str());
- fprintf(out, " scoped_%s_vec.push_back(scoped_%s);\n",
- chainField.name.c_str(), chainField.name.c_str());
- fprintf(out, " }\n");
- fprintf(out, " }\n");
- }
- fprintf(out, "\n");
- }
- } else if (*arg == JAVA_TYPE_KEY_VALUE_PAIR) {
- isKeyValuePairAtom = true;
- }
- argIndex++;
- }
- // Emit this to quiet the unused parameter warning if there were no strings or attribution
- // chains.
- if (!hadStringOrChain && !isKeyValuePairAtom) {
- fprintf(out, " (void)env;\n");
- }
- if (isKeyValuePairAtom) {
- write_key_value_map_jni(out);
- }
-
- // stats_write call
- argIndex = 1;
- fprintf(out, "\n int ret = android::util::%s(code",
- cpp_method_name.c_str());
- for (vector<java_type_t>::const_iterator arg = signature.begin();
- arg != signature.end(); arg++) {
- if (*arg == JAVA_TYPE_ATTRIBUTION_CHAIN) {
- for (auto chainField : attributionDecl.fields) {
- if (chainField.javaType == JAVA_TYPE_INT) {
- fprintf(out, ", (const %s*)%s_array, %s_length",
- cpp_type_name(chainField.javaType),
- chainField.name.c_str(), chainField.name.c_str());
- } else if (chainField.javaType == JAVA_TYPE_STRING) {
- fprintf(out, ", %s_vec", chainField.name.c_str());
- }
- }
- } else if (*arg == JAVA_TYPE_KEY_VALUE_PAIR) {
- fprintf(out, ", int32_t_map, int64_t_map, string_map, float_map");
- } else if (*arg == JAVA_TYPE_BYTE_ARRAY) {
- fprintf(out, ", bytesField%d", argIndex);
- } else {
- const char* argName =
- (*arg == JAVA_TYPE_STRING) ? "str" : "arg";
- fprintf(out, ", (%s)%s%d", cpp_type_name(*arg), argName, argIndex);
- }
- argIndex++;
- }
- fprintf(out, ");\n");
- fprintf(out, "\n");
-
- // Clean up strings
- argIndex = 1;
- for (vector<java_type_t>::const_iterator arg = signature.begin();
- arg != signature.end(); arg++) {
- if (*arg == JAVA_TYPE_STRING) {
- fprintf(out, " if (str%d != NULL) {\n", argIndex);
- fprintf(out, " env->ReleaseStringUTFChars(arg%d, str%d);\n",
- argIndex, argIndex);
- fprintf(out, " }\n");
- } else if (*arg == JAVA_TYPE_BYTE_ARRAY) {
- fprintf(out, " if (str%d != NULL) { \n", argIndex);
- fprintf(out,
- " env->ReleaseByteArrayElements(arg%d, "
- "jbyte_array%d, 0);\n",
- argIndex, argIndex);
- fprintf(out, " }\n");
- } else if (*arg == JAVA_TYPE_ATTRIBUTION_CHAIN) {
- for (auto chainField : attributionDecl.fields) {
- if (chainField.javaType == JAVA_TYPE_INT) {
- fprintf(out, " env->ReleaseIntArrayElements(%s, %s_array, 0);\n",
- chainField.name.c_str(), chainField.name.c_str());
- } else if (chainField.javaType == JAVA_TYPE_STRING) {
- fprintf(out, " for (size_t i = 0; i < scoped_%s_vec.size(); ++i) {\n",
- chainField.name.c_str());
- fprintf(out, " delete scoped_%s_vec[i];\n", chainField.name.c_str());
- fprintf(out, " }\n");
- }
- }
- }
- argIndex++;
- }
-
- fprintf(out, " return ret;\n");
-
- fprintf(out, "}\n");
- fprintf(out, "\n");
- }
-
-
- return 0;
-}
-
-void write_jni_registration(FILE* out, const string& java_method_name,
- const map<vector<java_type_t>, set<string>>& signatures_to_modules,
- const AtomDecl &attributionDecl) {
- for (auto signature_to_modules_it = signatures_to_modules.begin();
- signature_to_modules_it != signatures_to_modules.end(); signature_to_modules_it++) {
- vector<java_type_t> signature = signature_to_modules_it->first;
- fprintf(out, " { \"%s\", \"%s\", (void*)%s },\n",
- java_method_name.c_str(),
- jni_function_signature(signature, attributionDecl).c_str(),
- jni_function_name(java_method_name, signature).c_str());
- }
-}
-#endif // JNI helpers.
-
-static int
-#if defined(STATS_SCHEMA_LEGACY)
-write_stats_log_jni(FILE* out, const Atoms& atoms, const AtomDecl &attributionDecl)
-#else
-// Write empty JNI file that doesn't contain any JNI methods.
-// TODO(b/145100015): remove this function and all JNI autogen code once StatsEvent migration is
-// complete.
-write_stats_log_jni(FILE* out)
-#endif
-{
- // Print prelude
- fprintf(out, "// This file is autogenerated\n");
- fprintf(out, "\n");
-
-#if defined(STATS_SCHEMA_LEGACY)
- fprintf(out, "#include <statslog.h>\n");
- fprintf(out, "\n");
- fprintf(out, "#include <nativehelper/JNIHelp.h>\n");
- fprintf(out, "#include <nativehelper/ScopedUtfChars.h>\n");
- fprintf(out, "#include <utils/Vector.h>\n");
-#endif
- fprintf(out, "#include \"core_jni_helpers.h\"\n");
- fprintf(out, "#include \"jni.h\"\n");
- fprintf(out, "\n");
-#if defined(STATS_SCHEMA_LEGACY)
- fprintf(out, "#define UNUSED __attribute__((__unused__))\n");
- fprintf(out, "\n");
-#endif
-
- fprintf(out, "namespace android {\n");
- fprintf(out, "\n");
-
-#if defined(STATS_SCHEMA_LEGACY)
- write_stats_log_jni_method(out, "write", "stats_write", atoms.signatures_to_modules, attributionDecl);
- write_stats_log_jni_method(out, "write_non_chained", "stats_write_non_chained",
- atoms.non_chained_signatures_to_modules, attributionDecl);
-#endif
-
- // Print registration function table
- fprintf(out, "/*\n");
- fprintf(out, " * JNI registration.\n");
- fprintf(out, " */\n");
- fprintf(out, "static const JNINativeMethod gRegisterMethods[] = {\n");
-#if defined(STATS_SCHEMA_LEGACY)
- write_jni_registration(out, "write", atoms.signatures_to_modules, attributionDecl);
- write_jni_registration(out, "write_non_chained", atoms.non_chained_signatures_to_modules,
- attributionDecl);
-#endif
- fprintf(out, "};\n");
- fprintf(out, "\n");
-
- // Print registration function
- fprintf(out, "int register_android_util_StatsLogInternal(JNIEnv* env) {\n");
- fprintf(out, " return RegisterMethodsOrDie(\n");
- fprintf(out, " env,\n");
- fprintf(out, " \"android/util/StatsLogInternal\",\n");
- fprintf(out, " gRegisterMethods, NELEM(gRegisterMethods));\n");
- fprintf(out, "}\n");
-
- fprintf(out, "\n");
- fprintf(out, "} // namespace android\n");
- return 0;
-}
-
static void
print_usage()
{
@@ -498,7 +38,6 @@ print_usage()
fprintf(stderr, " --atomsInfoHeader FILENAME the cpp file to output for statsd metadata\n");
fprintf(stderr, " --help this message\n");
fprintf(stderr, " --java FILENAME the java file to output\n");
- fprintf(stderr, " --jni FILENAME the jni file to output\n");
fprintf(stderr, " --module NAME optional, module name to generate outputs for\n");
fprintf(stderr, " --namespace COMMA,SEP,NAMESPACE required for cpp/header with module\n");
fprintf(stderr, " comma separated namespace of the files\n");
@@ -526,16 +65,15 @@ run(int argc, char const*const* argv)
string cppFilename;
string headerFilename;
string javaFilename;
- string jniFilename;
string atomsInfoCppFilename;
string atomsInfoHeaderFilename;
+ string javaPackage;
+ string javaClass;
string moduleName = DEFAULT_MODULE_NAME;
string cppNamespace = DEFAULT_CPP_NAMESPACE;
string cppHeaderImport = DEFAULT_CPP_HEADER_IMPORT;
string atomsInfoCppHeaderImport = DEFAULT_ATOMS_INFO_CPP_HEADER_IMPORT;
- string javaPackage = DEFAULT_JAVA_PACKAGE;
- string javaClass = DEFAULT_JAVA_CLASS;
bool supportQ = false;
bool supportWorkSource = false;
bool compileQ = false;
@@ -566,13 +104,6 @@ run(int argc, char const*const* argv)
return 1;
}
javaFilename = argv[index];
- } else if (0 == strcmp("--jni", argv[index])) {
- index++;
- if (index >= argc) {
- print_usage();
- return 1;
- }
- jniFilename = argv[index];
} else if (0 == strcmp("--module", argv[index])) {
index++;
if (index >= argc) {
@@ -643,7 +174,6 @@ run(int argc, char const*const* argv)
if (cppFilename.size() == 0
&& headerFilename.size() == 0
&& javaFilename.size() == 0
- && jniFilename.size() == 0
&& atomsInfoHeaderFilename.size() == 0
&& atomsInfoCppFilename.size() == 0) {
print_usage();
@@ -682,7 +212,7 @@ run(int argc, char const*const* argv)
return 1;
}
errorCount = android::stats_log_api_gen::write_atoms_info_cpp(
- out, atoms, cppNamespace, atomsInfoCppHeaderImport, cppHeaderImport);
+ out, atoms, cppNamespace, atomsInfoCppHeaderImport);
fclose(out);
}
@@ -738,27 +268,27 @@ run(int argc, char const*const* argv)
// Write the .java file
if (javaFilename.size() != 0) {
- FILE* out = fopen(javaFilename.c_str(), "w");
- if (out == NULL) {
- fprintf(stderr, "Unable to open file for write: %s\n", javaFilename.c_str());
+ if (javaClass.size() == 0) {
+ fprintf(stderr, "Must supply --javaClass if supplying a Java filename");
return 1;
}
-#if defined(STATS_SCHEMA_LEGACY)
- if (moduleName == DEFAULT_MODULE_NAME) {
- errorCount = android::stats_log_api_gen::write_stats_log_java_q(
- out, atoms, attributionDecl, supportWorkSource);
- } else {
- errorCount = android::stats_log_api_gen::write_stats_log_java_q_for_module(
- out, atoms, attributionDecl, moduleName, javaClass, javaPackage,
- supportWorkSource);
+ if (javaPackage.size() == 0) {
+ fprintf(stderr, "Must supply --javaPackage if supplying a Java filename");
+ return 1;
+ }
+ if (moduleName.size() == 0) {
+ fprintf(stderr, "Must supply --module if supplying a Java filename");
+ return 1;
}
-#else
- if (moduleName == DEFAULT_MODULE_NAME) {
- javaClass = "StatsLogInternal";
- javaPackage = "android.util";
+
+ FILE* out = fopen(javaFilename.c_str(), "w");
+ if (out == NULL) {
+ fprintf(stderr, "Unable to open file for write: %s\n", javaFilename.c_str());
+ return 1;
}
+
if (compileQ) {
errorCount = android::stats_log_api_gen::write_stats_log_java_q_for_module(
out, atoms, attributionDecl, moduleName, javaClass, javaPackage,
@@ -768,25 +298,6 @@ run(int argc, char const*const* argv)
out, atoms, attributionDecl, moduleName, javaClass, javaPackage, supportQ,
supportWorkSource);
}
-#endif
-
- fclose(out);
- }
-
- // Write the jni file
- if (jniFilename.size() != 0) {
- FILE* out = fopen(jniFilename.c_str(), "w");
- if (out == NULL) {
- fprintf(stderr, "Unable to open file for write: %s\n", jniFilename.c_str());
- return 1;
- }
-
-#if defined(STATS_SCHEMA_LEGACY)
- errorCount = android::stats_log_api_gen::write_stats_log_jni(
- out, atoms, attributionDecl);
-#else
- errorCount = android::stats_log_api_gen::write_stats_log_jni(out);
-#endif
fclose(out);
}
diff --git a/tools/stats_log_api_gen/native_writer.cpp b/tools/stats_log_api_gen/native_writer.cpp
index 285514df5ff3..da207d665e20 100644
--- a/tools/stats_log_api_gen/native_writer.cpp
+++ b/tools/stats_log_api_gen/native_writer.cpp
@@ -15,14 +15,11 @@
*/
#include "native_writer.h"
-#include "native_writer_q.h"
#include "utils.h"
namespace android {
namespace stats_log_api_gen {
-#if !defined(STATS_SCHEMA_LEGACY)
-
static int write_native_stats_write_methods(FILE* out, const Atoms& atoms,
const AtomDecl& attributionDecl, const string& moduleName, const bool supportQ) {
fprintf(out, "\n");
@@ -175,7 +172,6 @@ static void write_native_stats_write_non_chained_methods(FILE* out, const Atoms&
}
}
-#endif
static void write_native_method_header(
FILE* out,
@@ -191,12 +187,10 @@ static void write_native_method_header(
}
vector<java_type_t> signature = signature_to_modules_it->first;
-#if !defined(STATS_SCHEMA_LEGACY)
// Key value pairs not supported in native.
if (find(signature.begin(), signature.end(), JAVA_TYPE_KEY_VALUE_PAIR) != signature.end()) {
continue;
}
-#endif
write_native_method_signature(out, methodName, signature, attributionDecl, ";");
}
}
@@ -209,33 +203,17 @@ int write_stats_log_cpp(FILE *out, const Atoms &atoms, const AtomDecl &attributi
fprintf(out, "\n");
fprintf(out, "#include <%s>\n", importHeader.c_str());
-#if defined(STATS_SCHEMA_LEGACY)
- (void)supportQ; // Workaround for unused parameter error.
- write_native_cpp_includes_q(out);
-#else
if (supportQ) {
fprintf(out, "#include <StatsEventCompat.h>\n");
} else {
fprintf(out, "#include <stats_event.h>\n");
}
-#endif
fprintf(out, "\n");
write_namespace(out, cppNamespace);
-#if defined(STATS_SCHEMA_LEGACY)
- write_native_stats_log_cpp_globals_q(out);
- write_native_get_timestamp_ns_q(out);
- write_native_try_stats_write_methods_q(out, atoms, attributionDecl, moduleName);
- write_native_stats_write_methods_q(out, "int stats_write", atoms, attributionDecl, moduleName,
- "try_stats_write");
- write_native_try_stats_write_non_chained_methods_q(out, atoms, attributionDecl, moduleName);
- write_native_stats_write_non_chained_methods_q(out, "int stats_write_non_chained", atoms,
- attributionDecl, moduleName, "try_stats_write_non_chained");
-#else
write_native_stats_write_methods(out, atoms, attributionDecl, moduleName, supportQ);
write_native_stats_write_non_chained_methods(out, atoms, attributionDecl, moduleName);
-#endif
// Print footer
fprintf(out, "\n");
diff --git a/tools/stats_log_api_gen/native_writer_q.cpp b/tools/stats_log_api_gen/native_writer_q.cpp
deleted file mode 100644
index 299873dad975..000000000000
--- a/tools/stats_log_api_gen/native_writer_q.cpp
+++ /dev/null
@@ -1,276 +0,0 @@
-/*
- * Copyright (C) 2019, The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include "native_writer_q.h"
-#include "utils.h"
-
-namespace android {
-namespace stats_log_api_gen {
-
-static void write_native_stats_write_body_q(FILE* out, const vector<java_type_t>& signature,
- const AtomDecl& attributionDecl, const string& indent, const string& tryMethodName) {
- fprintf(out, "%sint ret = 0;\n", indent.c_str());
-
- fprintf(out, "%sfor(int retry = 0; retry < 2; ++retry) {\n", indent.c_str());
- fprintf(out, "%s ret = ", indent.c_str());
- write_native_method_call(out, tryMethodName, signature, attributionDecl);
- fprintf(out, "%s if (ret >= 0) { break; }\n", indent.c_str());
-
- fprintf(out, "%s {\n", indent.c_str());
- fprintf(out, "%s std::lock_guard<std::mutex> lock(mLogdRetryMutex);\n", indent.c_str());
- fprintf(out, "%s if ((get_elapsed_realtime_ns() - lastRetryTimestampNs) <= "
- "kMinRetryIntervalNs) break;\n", indent.c_str());
- fprintf(out, "%s lastRetryTimestampNs = get_elapsed_realtime_ns();\n",
- indent.c_str());
- fprintf(out, "%s }\n", indent.c_str());
- fprintf(out, "%s std::this_thread::sleep_for(std::chrono::milliseconds(10));\n",
- indent.c_str());
- fprintf(out, "%s}\n", indent.c_str());
- fprintf(out, "%sif (ret < 0) {\n", indent.c_str());
- fprintf(out, "%s note_log_drop(ret, code);\n", indent.c_str());
- fprintf(out, "%s}\n", indent.c_str());
- fprintf(out, "%sreturn ret;\n", indent.c_str());
-}
-
-void write_native_cpp_includes_q(FILE* out) {
- fprintf(out, "#include <mutex>\n");
- fprintf(out, "#include <chrono>\n");
- fprintf(out, "#include <thread>\n");
- fprintf(out, "#ifdef __ANDROID__\n");
- fprintf(out, "#include <cutils/properties.h>\n");
- fprintf(out, "#endif\n");
- fprintf(out, "#include <stats_event_list.h>\n");
- fprintf(out, "#include <log/log.h>\n");
- fprintf(out, "#include <time.h>\n");
-}
-
-void write_native_get_timestamp_ns_q(FILE* out) {
- fprintf(out, "\n");
- fprintf(out, "static int64_t get_elapsed_realtime_ns() {\n");
- fprintf(out, " struct timespec t;\n");
- fprintf(out, " t.tv_sec = t.tv_nsec = 0;\n");
- fprintf(out, " clock_gettime(CLOCK_BOOTTIME, &t);\n");
- fprintf(out, " return (int64_t)t.tv_sec * 1000000000LL + t.tv_nsec;\n");
- fprintf(out, "}\n");
-}
-
-void write_native_stats_log_cpp_globals_q(FILE* out) {
- fprintf(out, "// the single event tag id for all stats logs\n");
- fprintf(out, "const static int kStatsEventTag = 1937006964;\n");
- fprintf(out, "#ifdef __ANDROID__\n");
- fprintf(out,
- "const static bool kStatsdEnabled = property_get_bool(\"ro.statsd.enable\", true);\n");
- fprintf(out, "#else\n");
- fprintf(out, "const static bool kStatsdEnabled = false;\n");
- fprintf(out, "#endif\n");
-
- fprintf(out, "int64_t lastRetryTimestampNs = -1;\n");
- fprintf(out, "const int64_t kMinRetryIntervalNs = NS_PER_SEC * 60 * 20; // 20 minutes\n");
- fprintf(out, "static std::mutex mLogdRetryMutex;\n");
-}
-
-void write_native_try_stats_write_methods_q(FILE* out, const Atoms& atoms,
- const AtomDecl& attributionDecl, const string& moduleName) {
- fprintf(out, "\n");
- for (auto signature_to_modules_it = atoms.signatures_to_modules.begin();
- signature_to_modules_it != atoms.signatures_to_modules.end(); signature_to_modules_it++) {
- if (!signature_needed_for_module(signature_to_modules_it->second, moduleName)) {
- continue;
- }
- vector<java_type_t> signature = signature_to_modules_it->first;
-
- write_native_method_signature(out, "static int try_stats_write", signature,
- attributionDecl, " {");
-
- int argIndex = 1;
- fprintf(out, " if (kStatsdEnabled) {\n");
- fprintf(out, " stats_event_list event(kStatsEventTag);\n");
- fprintf(out, " event << get_elapsed_realtime_ns();\n\n");
- fprintf(out, " event << code;\n\n");
- for (vector<java_type_t>::const_iterator arg = signature.begin();
- arg != signature.end(); arg++) {
- if (*arg == JAVA_TYPE_ATTRIBUTION_CHAIN) {
- for (const auto &chainField : attributionDecl.fields) {
- if (chainField.javaType == JAVA_TYPE_STRING) {
- fprintf(out, " if (%s_length != %s.size()) {\n",
- attributionDecl.fields.front().name.c_str(), chainField.name.c_str());
- fprintf(out, " return -EINVAL;\n");
- fprintf(out, " }\n");
- }
- }
- fprintf(out, "\n event.begin();\n");
- fprintf(out, " for (size_t i = 0; i < %s_length; ++i) {\n",
- attributionDecl.fields.front().name.c_str());
- fprintf(out, " event.begin();\n");
- for (const auto &chainField : attributionDecl.fields) {
- if (chainField.javaType == JAVA_TYPE_STRING) {
- fprintf(out, " if (%s[i] != NULL) {\n", chainField.name.c_str());
- fprintf(out, " event << %s[i];\n", chainField.name.c_str());
- fprintf(out, " } else {\n");
- fprintf(out, " event << \"\";\n");
- fprintf(out, " }\n");
- } else {
- fprintf(out, " event << %s[i];\n", chainField.name.c_str());
- }
- }
- fprintf(out, " event.end();\n");
- fprintf(out, " }\n");
- fprintf(out, " event.end();\n\n");
- } else if (*arg == JAVA_TYPE_KEY_VALUE_PAIR) {
- fprintf(out, " event.begin();\n\n");
- fprintf(out, " for (const auto& it : arg%d_1) {\n", argIndex);
- fprintf(out, " event.begin();\n");
- fprintf(out, " event << it.first;\n");
- fprintf(out, " event << it.second;\n");
- fprintf(out, " event.end();\n");
- fprintf(out, " }\n");
-
- fprintf(out, " for (const auto& it : arg%d_2) {\n", argIndex);
- fprintf(out, " event.begin();\n");
- fprintf(out, " event << it.first;\n");
- fprintf(out, " event << it.second;\n");
- fprintf(out, " event.end();\n");
- fprintf(out, " }\n");
-
- fprintf(out, " for (const auto& it : arg%d_3) {\n", argIndex);
- fprintf(out, " event.begin();\n");
- fprintf(out, " event << it.first;\n");
- fprintf(out, " event << it.second;\n");
- fprintf(out, " event.end();\n");
- fprintf(out, " }\n");
-
- fprintf(out, " for (const auto& it : arg%d_4) {\n", argIndex);
- fprintf(out, " event.begin();\n");
- fprintf(out, " event << it.first;\n");
- fprintf(out, " event << it.second;\n");
- fprintf(out, " event.end();\n");
- fprintf(out, " }\n");
-
- fprintf(out, " event.end();\n\n");
- } else if (*arg == JAVA_TYPE_BYTE_ARRAY) {
- fprintf(out,
- " event.AppendCharArray(arg%d.arg, "
- "arg%d.arg_length);\n",
- argIndex, argIndex);
- } else {
- if (*arg == JAVA_TYPE_STRING) {
- fprintf(out, " if (arg%d == NULL) {\n", argIndex);
- fprintf(out, " arg%d = \"\";\n", argIndex);
- fprintf(out, " }\n");
- }
- fprintf(out, " event << arg%d;\n", argIndex);
- }
- argIndex++;
- }
-
- fprintf(out, " return event.write(LOG_ID_STATS);\n");
- fprintf(out, " } else {\n");
- fprintf(out, " return 1;\n");
- fprintf(out, " }\n");
- fprintf(out, "}\n");
- fprintf(out, "\n");
- }
-
-}
-
-void write_native_stats_write_methods_q(FILE* out, const string& methodName, const Atoms& atoms,
- const AtomDecl& attributionDecl, const string& moduleName, const string& tryMethodName) {
- for (auto signature_to_modules_it = atoms.signatures_to_modules.begin();
- signature_to_modules_it != atoms.signatures_to_modules.end();
- signature_to_modules_it++) {
- if (!signature_needed_for_module(signature_to_modules_it->second, moduleName)) {
- continue;
- }
- vector<java_type_t> signature = signature_to_modules_it->first;
-
- write_native_method_signature(out, methodName, signature, attributionDecl, " {");
-
- write_native_stats_write_body_q(out, signature, attributionDecl, " ", tryMethodName);
- fprintf(out, "}\n\n");
- }
-}
-
-void write_native_stats_write_non_chained_methods_q(FILE* out, const string& methodName,
- const Atoms& atoms, const AtomDecl& attributionDecl, const string& moduleName,
- const string& tryMethodName) {
- for (auto signature_it = atoms.non_chained_signatures_to_modules.begin();
- signature_it != atoms.non_chained_signatures_to_modules.end(); signature_it++) {
- if (!signature_needed_for_module(signature_it->second, moduleName)) {
- continue;
- }
- vector<java_type_t> signature = signature_it->first;
-
- write_native_method_signature(out, methodName, signature, attributionDecl, " {");
-
- write_native_stats_write_body_q(out, signature, attributionDecl, " ", tryMethodName);
- fprintf(out, "}\n\n");
- }
-}
-
-void write_native_try_stats_write_non_chained_methods_q(FILE* out, const Atoms& atoms,
- const AtomDecl& attributionDecl, const string& moduleName) {
- for (auto signature_it = atoms.non_chained_signatures_to_modules.begin();
- signature_it != atoms.non_chained_signatures_to_modules.end(); signature_it++) {
- if (!signature_needed_for_module(signature_it->second, moduleName)) {
- continue;
- }
- vector<java_type_t> signature = signature_it->first;
-
- write_native_method_signature(out, "static int try_stats_write_non_chained", signature,
- attributionDecl, " {");
-
- int argIndex = 1;
- fprintf(out, " if (kStatsdEnabled) {\n");
- fprintf(out, " stats_event_list event(kStatsEventTag);\n");
- fprintf(out, " event << get_elapsed_realtime_ns();\n\n");
- fprintf(out, " event << code;\n\n");
- for (vector<java_type_t>::const_iterator arg = signature.begin();
- arg != signature.end(); arg++) {
- if (argIndex == 1) {
- fprintf(out, " event.begin();\n\n");
- fprintf(out, " event.begin();\n");
- }
- if (*arg == JAVA_TYPE_STRING) {
- fprintf(out, " if (arg%d == NULL) {\n", argIndex);
- fprintf(out, " arg%d = \"\";\n", argIndex);
- fprintf(out, " }\n");
- }
- if (*arg == JAVA_TYPE_BYTE_ARRAY) {
- fprintf(out,
- " event.AppendCharArray(arg%d.arg, "
- "arg%d.arg_length);\n",
- argIndex, argIndex);
- } else {
- fprintf(out, " event << arg%d;\n", argIndex);
- }
- if (argIndex == 2) {
- fprintf(out, " event.end();\n\n");
- fprintf(out, " event.end();\n\n");
- }
- argIndex++;
- }
-
- fprintf(out, " return event.write(LOG_ID_STATS);\n");
- fprintf(out, " } else {\n");
- fprintf(out, " return 1;\n");
- fprintf(out, " }\n");
- fprintf(out, "}\n");
- fprintf(out, "\n");
- }
-}
-
-} // namespace stats_log_api_gen
-} // namespace android
diff --git a/tools/stats_log_api_gen/native_writer_q.h b/tools/stats_log_api_gen/native_writer_q.h
deleted file mode 100644
index a2ab1ae5d5e2..000000000000
--- a/tools/stats_log_api_gen/native_writer_q.h
+++ /dev/null
@@ -1,49 +0,0 @@
-/*
- * Copyright (C) 2019, The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#pragma once
-
-#include "Collation.h"
-
-#include <stdio.h>
-#include <string.h>
-
-namespace android {
-namespace stats_log_api_gen {
-
-using namespace std;
-
-void write_native_cpp_includes_q(FILE* out);
-
-void write_native_stats_log_cpp_globals_q(FILE* out);
-
-void write_native_try_stats_write_methods_q(FILE* out, const Atoms& atoms,
- const AtomDecl& attributionDecl, const string& moduleName);
-
-void write_native_stats_write_methods_q(FILE* out, const string& methodName, const Atoms& atoms,
- const AtomDecl& attributionDecl, const string& moduleName, const string& tryMethodName);
-
-void write_native_try_stats_write_non_chained_methods_q(FILE* out, const Atoms& atoms,
- const AtomDecl& attributionDecl, const string& moduleName);
-
-void write_native_stats_write_non_chained_methods_q(FILE* out, const string& methodName,
- const Atoms& atoms, const AtomDecl& attributionDecl, const string& moduleName,
- const string& tryMethodName);
-
-void write_native_get_timestamp_ns_q(FILE* out);
-
-} // namespace stats_log_api_gen
-} // namespace android
diff --git a/tools/stats_log_api_gen/test.proto b/tools/stats_log_api_gen/test.proto
index b892194410ae..f6c89c22ee65 100644
--- a/tools/stats_log_api_gen/test.proto
+++ b/tools/stats_log_api_gen/test.proto
@@ -41,21 +41,20 @@ enum AnEnum {
message AllTypesAtom {
repeated android.os.statsd.AttributionNode attribution_chain = 1;
- optional double double_field = 2;
- optional float float_field = 3;
- optional int64 int64_field = 4;
- optional uint64 uint64_field = 5;
- optional int32 int32_field = 6;
- optional fixed64 fixed64_field = 7;
- optional fixed32 fixed32_field = 8;
- optional bool bool_field = 9;
- optional string string_field = 10;
- optional uint32 uint32_field = 11;
- optional AnEnum enum_field = 12;
- optional sfixed32 sfixed32_field = 13;
- optional sfixed64 sfixed64_field = 14;
- optional sint32 sint32_field = 15;
- optional sint64 sint64_field = 16;
+ optional float float_field = 2;
+ optional int64 int64_field = 3;
+ optional uint64 uint64_field = 4;
+ optional int32 int32_field = 5;
+ optional fixed64 fixed64_field = 6;
+ optional fixed32 fixed32_field = 7;
+ optional bool bool_field = 8;
+ optional string string_field = 9;
+ optional uint32 uint32_field = 10;
+ optional AnEnum enum_field = 11;
+ optional sfixed32 sfixed32_field = 12;
+ optional sfixed64 sfixed64_field = 13;
+ optional sint32 sint32_field = 14;
+ optional sint64 sint64_field = 15;
}
message Event {
@@ -70,6 +69,8 @@ message Event {
message BadTypesAtom {
optional IntAtom bad_int_atom = 1;
optional bytes bad_bytes = 2;
+ repeated int32 repeated_field = 3;
+ optional double double_field = 4;
}
message BadTypesEvent {
@@ -212,6 +213,10 @@ message ModuleTwoAtom {
optional int32 field = 1;
}
+message ModuleOneAndTwoAtom {
+ optional int32 field = 1;
+}
+
message NoModuleAtom {
optional string field = 1;
}
@@ -220,6 +225,9 @@ message ModuleAtoms {
oneof event {
ModuleOneAtom module_one_atom = 1 [(android.os.statsd.module) = "module1"];
ModuleTwoAtom module_two_atom = 2 [(android.os.statsd.module) = "module2"];
- NoModuleAtom no_module_atom = 3;
+ ModuleOneAndTwoAtom module_one_and_two_atom = 3 [
+ (android.os.statsd.module) = "module1", (android.os.statsd.module) = "module2"
+ ];
+ NoModuleAtom no_module_atom = 4;
}
}
diff --git a/tools/stats_log_api_gen/test_collation.cpp b/tools/stats_log_api_gen/test_collation.cpp
index bcf18ae8bf19..73abaef1d91b 100644
--- a/tools/stats_log_api_gen/test_collation.cpp
+++ b/tools/stats_log_api_gen/test_collation.cpp
@@ -98,7 +98,6 @@ TEST(CollationTest, CollateStats) {
EXPECT_SET_CONTAINS_SIGNATURE(
atoms.signatures_to_modules,
JAVA_TYPE_ATTRIBUTION_CHAIN, // AttributionChain
- JAVA_TYPE_DOUBLE, // double
JAVA_TYPE_FLOAT, // float
JAVA_TYPE_LONG, // int64
JAVA_TYPE_LONG, // uint64
@@ -157,13 +156,13 @@ TEST(CollationTest, NonMessageTypeFails) {
}
/**
- * Test that atoms that have non-primitive types are rejected.
+ * Test that atoms that have non-primitive types or repeated fields are rejected.
*/
TEST(CollationTest, FailOnBadTypes) {
Atoms atoms;
int errorCount = collate_atoms(BadTypesEvent::descriptor(), &atoms);
- EXPECT_EQ(2, errorCount);
+ EXPECT_EQ(4, errorCount);
}
/**
@@ -249,23 +248,27 @@ TEST(CollationTest, PassOnLogFromModuleAtom) {
Atoms atoms;
int errorCount = collate_atoms(ModuleAtoms::descriptor(), &atoms);
EXPECT_EQ(errorCount, 0);
- EXPECT_EQ(atoms.decls.size(), 3ul);
+ EXPECT_EQ(atoms.decls.size(), 4ul);
}
TEST(CollationTest, RecognizeModuleAtom) {
Atoms atoms;
int errorCount = collate_atoms(ModuleAtoms::descriptor(), &atoms);
EXPECT_EQ(errorCount, 0);
- EXPECT_EQ(atoms.decls.size(), 3ul);
+ EXPECT_EQ(atoms.decls.size(), 4ul);
for (const auto& atomDecl: atoms.decls) {
if (atomDecl.code == 1) {
- EXPECT_TRUE(atomDecl.hasModule);
- EXPECT_EQ(atomDecl.moduleName, "module1");
+ EXPECT_EQ(1ul, atomDecl.moduleNames.size());
+ EXPECT_NE(atomDecl.moduleNames.end(), atomDecl.moduleNames.find("module1"));
} else if (atomDecl.code == 2) {
- EXPECT_TRUE(atomDecl.hasModule);
- EXPECT_EQ(atomDecl.moduleName, "module2");
+ EXPECT_EQ(1ul, atomDecl.moduleNames.size());
+ EXPECT_NE(atomDecl.moduleNames.end(), atomDecl.moduleNames.find("module2"));
+ } else if (atomDecl.code == 3) {
+ EXPECT_EQ(2ul, atomDecl.moduleNames.size());
+ EXPECT_NE(atomDecl.moduleNames.end(), atomDecl.moduleNames.find("module1"));
+ EXPECT_NE(atomDecl.moduleNames.end(), atomDecl.moduleNames.find("module2"));
} else {
- EXPECT_FALSE(atomDecl.hasModule);
+ EXPECT_TRUE(atomDecl.moduleNames.empty());
}
}
@@ -287,4 +290,4 @@ TEST(CollationTest, RecognizeModuleAtom) {
}
} // namespace stats_log_api_gen
-} // namespace android \ No newline at end of file
+} // namespace android
diff --git a/tools/stats_log_api_gen/utils.cpp b/tools/stats_log_api_gen/utils.cpp
index 8c4abe43a49b..9dc4ff827380 100644
--- a/tools/stats_log_api_gen/utils.cpp
+++ b/tools/stats_log_api_gen/utils.cpp
@@ -102,7 +102,7 @@ bool atom_needed_for_module(const AtomDecl& atomDecl, const string& moduleName)
if (moduleName == DEFAULT_MODULE_NAME) {
return true;
}
- return atomDecl.hasModule && (moduleName == atomDecl.moduleName);
+ return atomDecl.moduleNames.find(moduleName) != atomDecl.moduleNames.end();
}
bool signature_needed_for_module(const set<string>& modules, const string& moduleName) {
@@ -286,9 +286,6 @@ void write_java_atom_codes(FILE* out, const Atoms& atoms, const string& moduleNa
if (non_chained_decl != atom_code_to_non_chained_decl_map.end()) {
write_java_usage(out, "write_non_chained", constant, *non_chained_decl->second);
}
- if (moduleName == DEFAULT_MODULE_NAME) {
- fprintf(out, " * @hide\n");
- }
fprintf(out, " */\n");
fprintf(out, " public static final int %s = %d;\n", constant.c_str(), atom->code);
}
@@ -310,9 +307,6 @@ void write_java_enum_values(FILE* out, const Atoms& atoms, const string& moduleN
field->name.c_str());
for (map<int, string>::const_iterator value = field->enumValues.begin();
value != field->enumValues.end(); value++) {
- if (moduleName == DEFAULT_MODULE_NAME) {
- fprintf(out, " /** @hide */\n");
- }
fprintf(out, " public static final int %s__%s__%s = %d;\n",
make_constant_name(atom->message).c_str(),
make_constant_name(field->name).c_str(),
@@ -357,9 +351,6 @@ int write_java_non_chained_methods(
}
// Print method signature.
- if (DEFAULT_MODULE_NAME == moduleName) {
- fprintf(out, " /** @hide */\n");
- }
fprintf(out, " public static void write_non_chained(int code");
vector<java_type_t> signature = signature_to_modules_it->first;
int argIndex = 1;
@@ -434,9 +425,6 @@ int write_java_work_source_methods(
fprintf(out, "\n");
// Method header (signature)
- if (DEFAULT_MODULE_NAME == moduleName) {
- fprintf(out, " /** @hide */\n");
- }
fprintf(out, " public static void write(int code");
int argIndex = 1;
for (vector<java_type_t>::const_iterator arg = signature.begin();
diff --git a/tools/stats_log_api_gen/utils.h b/tools/stats_log_api_gen/utils.h
index cd602e53359a..715d42bc160a 100644
--- a/tools/stats_log_api_gen/utils.h
+++ b/tools/stats_log_api_gen/utils.h
@@ -34,8 +34,6 @@ const string DEFAULT_MODULE_NAME = "DEFAULT";
const string DEFAULT_CPP_NAMESPACE = "android,util";
const string DEFAULT_CPP_HEADER_IMPORT = "statslog.h";
const string DEFAULT_ATOMS_INFO_CPP_HEADER_IMPORT = "atoms_info.h";
-const string DEFAULT_JAVA_PACKAGE = "android.util";
-const string DEFAULT_JAVA_CLASS = "StatsLogInternal";
const int JAVA_MODULE_REQUIRES_FLOAT = 0x01;
const int JAVA_MODULE_REQUIRES_ATTRIBUTION = 0x02;
diff --git a/wifi/java/android/net/wifi/EasyConnectStatusCallback.java b/wifi/java/android/net/wifi/EasyConnectStatusCallback.java
index 8ccf0076f0b0..de2f5d9a3fe4 100644
--- a/wifi/java/android/net/wifi/EasyConnectStatusCallback.java
+++ b/wifi/java/android/net/wifi/EasyConnectStatusCallback.java
@@ -242,6 +242,8 @@ public abstract class EasyConnectStatusCallback {
* to scan to find the network, see the "DPP Connection Status Object"
* section in the specification for the format, and Table E-4 in
* IEEE Std 802.11-2016 - Global operating classes for more details.
+ * The sparse array key is the Global Operating class, and the value
+ * is an integer array of Wi-Fi channels.
* @param operatingClassArray Array of bands the Enrollee supports as expressed as the Global
* Operating Class, see Table E-4 in IEEE Std 802.11-2016 - Global
* operating classes.
diff --git a/wifi/java/android/net/wifi/IScoreChangeCallback.aidl b/wifi/java/android/net/wifi/IScoreUpdateObserver.aidl
index d691f41b2858..775fed7d47ef 100644
--- a/wifi/java/android/net/wifi/IScoreChangeCallback.aidl
+++ b/wifi/java/android/net/wifi/IScoreUpdateObserver.aidl
@@ -21,9 +21,9 @@ package android.net.wifi;
*
* @hide
*/
-oneway interface IScoreChangeCallback
+oneway interface IScoreUpdateObserver
{
- void onScoreChange(int sessionId, int score);
+ void notifyScoreUpdate(int sessionId, int score);
- void onTriggerUpdateOfWifiUsabilityStats(int sessionId);
+ void triggerUpdateOfWifiUsabilityStats(int sessionId);
}
diff --git a/wifi/java/android/net/wifi/IWifiConnectedNetworkScorer.aidl b/wifi/java/android/net/wifi/IWifiConnectedNetworkScorer.aidl
index d9a3b0109a09..f96d037cbfea 100644
--- a/wifi/java/android/net/wifi/IWifiConnectedNetworkScorer.aidl
+++ b/wifi/java/android/net/wifi/IWifiConnectedNetworkScorer.aidl
@@ -16,7 +16,7 @@
package android.net.wifi;
-import android.net.wifi.IScoreChangeCallback;
+import android.net.wifi.IScoreUpdateObserver;
/**
* Interface for Wi-Fi connected network scorer.
@@ -25,9 +25,9 @@ import android.net.wifi.IScoreChangeCallback;
*/
oneway interface IWifiConnectedNetworkScorer
{
- void start(int sessionId);
+ void onStart(int sessionId);
- void stop(int sessionId);
+ void onStop(int sessionId);
- void setScoreChangeCallback(IScoreChangeCallback cbImpl);
+ void onSetScoreUpdateObserver(IScoreUpdateObserver observerImpl);
}
diff --git a/wifi/java/android/net/wifi/ScanResult.java b/wifi/java/android/net/wifi/ScanResult.java
index 9256c57ab4b9..70542b5d3c65 100644
--- a/wifi/java/android/net/wifi/ScanResult.java
+++ b/wifi/java/android/net/wifi/ScanResult.java
@@ -16,16 +16,15 @@
package android.net.wifi;
-import android.annotation.IntDef;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.annotation.SystemApi;
import android.compat.annotation.UnsupportedAppUsage;
+import android.net.wifi.WifiAnnotations.ChannelWidth;
+import android.net.wifi.WifiAnnotations.WifiStandard;
import android.os.Parcel;
import android.os.Parcelable;
-import java.lang.annotation.Retention;
-import java.lang.annotation.RetentionPolicy;
import java.nio.ByteBuffer;
import java.util.ArrayList;
import java.util.Arrays;
@@ -313,17 +312,6 @@ public class ScanResult implements Parcelable {
*/
public static final int WIFI_STANDARD_11AX = 6;
- /** @hide */
- @IntDef(prefix = { "WIFI_STANDARD_" }, value = {
- WIFI_STANDARD_UNKNOWN,
- WIFI_STANDARD_LEGACY,
- WIFI_STANDARD_11N,
- WIFI_STANDARD_11AC,
- WIFI_STANDARD_11AX
- })
- @Retention(RetentionPolicy.SOURCE)
- public @interface WifiStandard{}
-
/**
* AP wifi standard.
*/
@@ -368,7 +356,7 @@ public class ScanResult implements Parcelable {
* {@link #CHANNEL_WIDTH_80MHZ}, {@link #CHANNEL_WIDTH_160MHZ}
* or {@link #CHANNEL_WIDTH_80MHZ_PLUS_MHZ}.
*/
- public int channelWidth;
+ public @ChannelWidth int channelWidth;
/**
* Not used if the AP bandwidth is 20 MHz
diff --git a/wifi/java/android/net/wifi/WifiAnnotations.java b/wifi/java/android/net/wifi/WifiAnnotations.java
index 05e5b1d45684..acda7e06c95d 100644
--- a/wifi/java/android/net/wifi/WifiAnnotations.java
+++ b/wifi/java/android/net/wifi/WifiAnnotations.java
@@ -61,6 +61,26 @@ public final class WifiAnnotations {
@Retention(RetentionPolicy.SOURCE)
public @interface Bandwidth {}
+ @IntDef(prefix = { "CHANNEL_WIDTH_" }, value = {
+ ScanResult.CHANNEL_WIDTH_20MHZ,
+ ScanResult.CHANNEL_WIDTH_40MHZ,
+ ScanResult.CHANNEL_WIDTH_80MHZ,
+ ScanResult.CHANNEL_WIDTH_160MHZ,
+ ScanResult.CHANNEL_WIDTH_80MHZ_PLUS_MHZ,
+ })
+ @Retention(RetentionPolicy.SOURCE)
+ public @interface ChannelWidth{}
+
+ @IntDef(prefix = { "WIFI_STANDARD_" }, value = {
+ ScanResult.WIFI_STANDARD_UNKNOWN,
+ ScanResult.WIFI_STANDARD_LEGACY,
+ ScanResult.WIFI_STANDARD_11N,
+ ScanResult.WIFI_STANDARD_11AC,
+ ScanResult.WIFI_STANDARD_11AX,
+ })
+ @Retention(RetentionPolicy.SOURCE)
+ public @interface WifiStandard{}
+
@IntDef(prefix = { "PROTOCOL_" }, value = {
ScanResult.PROTOCOL_NONE,
ScanResult.PROTOCOL_WPA,
diff --git a/wifi/java/android/net/wifi/WifiConfiguration.java b/wifi/java/android/net/wifi/WifiConfiguration.java
index 5a7bf4b15f1a..ceb2907e7a93 100644
--- a/wifi/java/android/net/wifi/WifiConfiguration.java
+++ b/wifi/java/android/net/wifi/WifiConfiguration.java
@@ -503,6 +503,8 @@ public class WifiConfiguration implements Parcelable {
break;
case SECURITY_TYPE_EAP_SUITE_B:
allowedProtocols.set(WifiConfiguration.Protocol.RSN);
+ allowedKeyManagement.set(WifiConfiguration.KeyMgmt.WPA_EAP);
+ allowedKeyManagement.set(WifiConfiguration.KeyMgmt.IEEE8021X);
allowedKeyManagement.set(WifiConfiguration.KeyMgmt.SUITE_B_192);
allowedPairwiseCiphers.set(WifiConfiguration.PairwiseCipher.GCMP_256);
allowedGroupCiphers.set(WifiConfiguration.GroupCipher.GCMP_256);
diff --git a/wifi/java/android/net/wifi/WifiInfo.java b/wifi/java/android/net/wifi/WifiInfo.java
index 142854a9e41b..70c5e72e4e0c 100644
--- a/wifi/java/android/net/wifi/WifiInfo.java
+++ b/wifi/java/android/net/wifi/WifiInfo.java
@@ -103,7 +103,7 @@ public class WifiInfo implements Parcelable {
/**
* Wi-Fi standard for the connection
*/
- private @ScanResult.WifiStandard int mWifiStandard;
+ private @WifiAnnotations.WifiStandard int mWifiStandard;
/**
* The unit in which links speeds are expressed.
@@ -518,7 +518,7 @@ public class WifiInfo implements Parcelable {
* Sets the Wi-Fi standard
* @hide
*/
- public void setWifiStandard(@ScanResult.WifiStandard int wifiStandard) {
+ public void setWifiStandard(@WifiAnnotations.WifiStandard int wifiStandard) {
mWifiStandard = wifiStandard;
}
@@ -526,7 +526,7 @@ public class WifiInfo implements Parcelable {
* Get connection Wi-Fi standard
* @return the connection Wi-Fi standard
*/
- public @ScanResult.WifiStandard int getWifiStandard() {
+ public @WifiAnnotations.WifiStandard int getWifiStandard() {
return mWifiStandard;
}
diff --git a/wifi/java/android/net/wifi/WifiManager.java b/wifi/java/android/net/wifi/WifiManager.java
index c46cd11f7aae..382995703fff 100644
--- a/wifi/java/android/net/wifi/WifiManager.java
+++ b/wifi/java/android/net/wifi/WifiManager.java
@@ -2563,7 +2563,7 @@ public class WifiManager {
* valid values from {@link ScanResult}'s {@code WIFI_STANDARD_}
* @return {@code true} if supported, {@code false} otherwise.
*/
- public boolean isWifiStandardSupported(@ScanResult.WifiStandard int standard) {
+ public boolean isWifiStandardSupported(@WifiAnnotations.WifiStandard int standard) {
try {
return mService.isWifiStandardSupported(standard);
} catch (RemoteException e) {
@@ -2826,7 +2826,7 @@ public class WifiManager {
*/
@Nullable
@SystemApi
- @RequiresPermission(android.Manifest.permission.CONNECTIVITY_INTERNAL)
+ @RequiresPermission(android.Manifest.permission.NETWORK_SETTINGS)
public String getCountryCode() {
try {
return mService.getCountryCode();
@@ -4441,10 +4441,11 @@ public class WifiManager {
}
/**
- * Disable an ephemeral network.
- *
- * @param ssid in the format of WifiConfiguration's SSID.
+ * Temporarily disable a network. Should always trigger with user disconnect network.
*
+ * @param network Input can be SSID or FQDN. And caller must ensure that the SSID passed thru
+ * this API matched the WifiConfiguration.SSID rules, and thus be surrounded by
+ * quotes.
* @hide
*/
@SystemApi
@@ -4452,12 +4453,12 @@ public class WifiManager {
android.Manifest.permission.NETWORK_SETTINGS,
android.Manifest.permission.NETWORK_STACK
})
- public void disableEphemeralNetwork(@NonNull String ssid) {
- if (TextUtils.isEmpty(ssid)) {
+ public void disableEphemeralNetwork(@NonNull String network) {
+ if (TextUtils.isEmpty(network)) {
throw new IllegalArgumentException("SSID cannot be null or empty!");
}
try {
- mService.disableEphemeralNetwork(ssid, mContext.getOpPackageName());
+ mService.disableEphemeralNetwork(network, mContext.getOpPackageName());
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
@@ -5985,22 +5986,22 @@ public class WifiManager {
}
/**
- * Callback interface for framework to receive network status changes and trigger of updating
+ * Callback interface for framework to receive network status updates and trigger of updating
* {@link WifiUsabilityStatsEntry}.
*
* @hide
*/
@SystemApi
- public interface ScoreChangeCallback {
+ public interface ScoreUpdateObserver {
/**
* Called by applications to indicate network status.
*
* @param sessionId The ID to indicate current Wi-Fi network connection obtained from
- * {@link WifiConnectedNetworkScorer#start(int)}.
+ * {@link WifiConnectedNetworkScorer#onStart(int)}.
* @param score The score representing link quality of current Wi-Fi network connection.
* Populated by connected network scorer in applications..
*/
- void onScoreChange(int sessionId, int score);
+ void notifyScoreUpdate(int sessionId, int score);
/**
* Called by applications to trigger an update of {@link WifiUsabilityStatsEntry}.
@@ -6008,36 +6009,36 @@ public class WifiManager {
* {@link addOnWifiUsabilityStatsListener(Executor, OnWifiUsabilityStatsListener)}.
*
* @param sessionId The ID to indicate current Wi-Fi network connection obtained from
- * {@link WifiConnectedNetworkScorer#start(int)}.
+ * {@link WifiConnectedNetworkScorer#onStart(int)}.
*/
- void onTriggerUpdateOfWifiUsabilityStats(int sessionId);
+ void triggerUpdateOfWifiUsabilityStats(int sessionId);
}
/**
- * Callback proxy for {@link ScoreChangeCallback} objects.
+ * Callback proxy for {@link ScoreUpdateObserver} objects.
*
* @hide
*/
- private class ScoreChangeCallbackProxy implements ScoreChangeCallback {
- private final IScoreChangeCallback mScoreChangeCallback;
+ private class ScoreUpdateObserverProxy implements ScoreUpdateObserver {
+ private final IScoreUpdateObserver mScoreUpdateObserver;
- private ScoreChangeCallbackProxy(IScoreChangeCallback callback) {
- mScoreChangeCallback = callback;
+ private ScoreUpdateObserverProxy(IScoreUpdateObserver observer) {
+ mScoreUpdateObserver = observer;
}
@Override
- public void onScoreChange(int sessionId, int score) {
+ public void notifyScoreUpdate(int sessionId, int score) {
try {
- mScoreChangeCallback.onScoreChange(sessionId, score);
+ mScoreUpdateObserver.notifyScoreUpdate(sessionId, score);
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
}
@Override
- public void onTriggerUpdateOfWifiUsabilityStats(int sessionId) {
+ public void triggerUpdateOfWifiUsabilityStats(int sessionId) {
try {
- mScoreChangeCallback.onTriggerUpdateOfWifiUsabilityStats(sessionId);
+ mScoreUpdateObserver.triggerUpdateOfWifiUsabilityStats(sessionId);
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
@@ -6057,21 +6058,21 @@ public class WifiManager {
* Called by framework to indicate the start of a network connection.
* @param sessionId The ID to indicate current Wi-Fi network connection.
*/
- void start(int sessionId);
+ void onStart(int sessionId);
/**
* Called by framework to indicate the end of a network connection.
* @param sessionId The ID to indicate current Wi-Fi network connection obtained from
- * {@link WifiConnectedNetworkScorer#start(int)}.
+ * {@link WifiConnectedNetworkScorer#onStart(int)}.
*/
- void stop(int sessionId);
+ void onStop(int sessionId);
/**
* Framework sets callback for score change events after application sets its scorer.
- * @param cbImpl The instance for {@link WifiManager#ScoreChangeCallback}. Should be
+ * @param observerImpl The instance for {@link WifiManager#ScoreUpdateObserver}. Should be
* implemented and instantiated by framework.
*/
- void setScoreChangeCallback(@NonNull ScoreChangeCallback cbImpl);
+ void onSetScoreUpdateObserver(@NonNull ScoreUpdateObserver observerImpl);
}
/**
@@ -6089,32 +6090,32 @@ public class WifiManager {
}
@Override
- public void start(int sessionId) {
+ public void onStart(int sessionId) {
if (mVerboseLoggingEnabled) {
- Log.v(TAG, "WifiConnectedNetworkScorer: " + "start: sessionId=" + sessionId);
+ Log.v(TAG, "WifiConnectedNetworkScorer: " + "onStart: sessionId=" + sessionId);
}
Binder.clearCallingIdentity();
- mExecutor.execute(() -> mScorer.start(sessionId));
+ mExecutor.execute(() -> mScorer.onStart(sessionId));
}
@Override
- public void stop(int sessionId) {
+ public void onStop(int sessionId) {
if (mVerboseLoggingEnabled) {
- Log.v(TAG, "WifiConnectedNetworkScorer: " + "stop: sessionId=" + sessionId);
+ Log.v(TAG, "WifiConnectedNetworkScorer: " + "onStop: sessionId=" + sessionId);
}
Binder.clearCallingIdentity();
- mExecutor.execute(() -> mScorer.stop(sessionId));
+ mExecutor.execute(() -> mScorer.onStop(sessionId));
}
@Override
- public void setScoreChangeCallback(IScoreChangeCallback cbImpl) {
+ public void onSetScoreUpdateObserver(IScoreUpdateObserver observerImpl) {
if (mVerboseLoggingEnabled) {
Log.v(TAG, "WifiConnectedNetworkScorer: "
- + "setScoreChangeCallback: cbImpl=" + cbImpl);
+ + "onSetScoreUpdateObserver: observerImpl=" + observerImpl);
}
Binder.clearCallingIdentity();
- mExecutor.execute(() -> mScorer.setScoreChangeCallback(
- new ScoreChangeCallbackProxy(cbImpl)));
+ mExecutor.execute(() -> mScorer.onSetScoreUpdateObserver(
+ new ScoreUpdateObserverProxy(observerImpl)));
}
}
diff --git a/wifi/java/android/net/wifi/nl80211/DeviceWiphyCapabilities.java b/wifi/java/android/net/wifi/nl80211/DeviceWiphyCapabilities.java
index a045aad9f64c..bb0cc975a3db 100644
--- a/wifi/java/android/net/wifi/nl80211/DeviceWiphyCapabilities.java
+++ b/wifi/java/android/net/wifi/nl80211/DeviceWiphyCapabilities.java
@@ -19,6 +19,8 @@ package android.net.wifi.nl80211;
import android.annotation.NonNull;
import android.annotation.SystemApi;
import android.net.wifi.ScanResult;
+import android.net.wifi.WifiAnnotations.ChannelWidth;
+import android.net.wifi.WifiAnnotations.WifiStandard;
import android.os.Parcel;
import android.os.Parcelable;
import android.util.Log;
@@ -28,6 +30,9 @@ import java.util.Objects;
/**
* DeviceWiphyCapabilities for wificond
*
+ * Contains the WiFi physical layer attributes and capabilities of the device.
+ * It is used to collect these attributes from the device driver via wificond.
+ *
* @hide
*/
@SystemApi
@@ -61,7 +66,7 @@ public final class DeviceWiphyCapabilities implements Parcelable {
* valid values from {@link ScanResult}'s {@code WIFI_STANDARD_}
* @return {@code true} if supported, {@code false} otherwise.
*/
- public boolean isWifiStandardSupported(int standard) {
+ public boolean isWifiStandardSupported(@WifiStandard int standard) {
switch (standard) {
case ScanResult.WIFI_STANDARD_LEGACY:
return true;
@@ -84,7 +89,7 @@ public final class DeviceWiphyCapabilities implements Parcelable {
* valid values from {@link ScanResult}'s {@code WIFI_STANDARD_}
* @param support {@code true} if supported, {@code false} otherwise.
*/
- public void setWifiStandardSupport(int standard, boolean support) {
+ public void setWifiStandardSupport(@WifiStandard int standard, boolean support) {
switch (standard) {
case ScanResult.WIFI_STANDARD_11N:
m80211nSupported = support;
@@ -107,7 +112,7 @@ public final class DeviceWiphyCapabilities implements Parcelable {
*
* @return {@code true} if supported, {@code false} otherwise.
*/
- public boolean isChannelWidthSupported(int chWidth) {
+ public boolean isChannelWidthSupported(@ChannelWidth int chWidth) {
switch (chWidth) {
case ScanResult.CHANNEL_WIDTH_20MHZ:
return true;
@@ -131,8 +136,10 @@ public final class DeviceWiphyCapabilities implements Parcelable {
* @param chWidth valid values are {@link ScanResult#CHANNEL_WIDTH_160MHZ} and
* {@link ScanResult#CHANNEL_WIDTH_80MHZ_PLUS_MHZ}
* @param support {@code true} if supported, {@code false} otherwise.
+ *
+ * @hide
*/
- public void setChannelWidthSupported(int chWidth, boolean support) {
+ public void setChannelWidthSupported(@ChannelWidth int chWidth, boolean support) {
switch (chWidth) {
case ScanResult.CHANNEL_WIDTH_160MHZ:
mChannelWidth160MhzSupported = support;
@@ -159,6 +166,8 @@ public final class DeviceWiphyCapabilities implements Parcelable {
* Set maximum number of transmit spatial streams
*
* @param streams number of spatial streams
+ *
+ * @hide
*/
public void setMaxNumberTxSpatialStreams(int streams) {
mMaxNumberTxSpatialStreams = streams;
@@ -177,6 +186,8 @@ public final class DeviceWiphyCapabilities implements Parcelable {
* Set maximum number of receive spatial streams
*
* @param streams number of streams
+ *
+ * @hide
*/
public void setMaxNumberRxSpatialStreams(int streams) {
mMaxNumberRxSpatialStreams = streams;
diff --git a/wifi/tests/src/android/net/wifi/ScanResultTest.java b/wifi/tests/src/android/net/wifi/ScanResultTest.java
index b5c74d1d01b1..4c22d5d6dc7e 100644
--- a/wifi/tests/src/android/net/wifi/ScanResultTest.java
+++ b/wifi/tests/src/android/net/wifi/ScanResultTest.java
@@ -42,7 +42,7 @@ public class ScanResultTest {
public static final int TEST_LEVEL = -56;
public static final int TEST_FREQUENCY = 2412;
public static final long TEST_TSF = 04660l;
- public static final @ScanResult.WifiStandard int TEST_WIFI_STANDARD =
+ public static final @WifiAnnotations.WifiStandard int TEST_WIFI_STANDARD =
ScanResult.WIFI_STANDARD_11AC;
/**
diff --git a/wifi/tests/src/android/net/wifi/WifiConfigurationTest.java b/wifi/tests/src/android/net/wifi/WifiConfigurationTest.java
index 047a64b25733..91c74f3c2e3e 100644
--- a/wifi/tests/src/android/net/wifi/WifiConfigurationTest.java
+++ b/wifi/tests/src/android/net/wifi/WifiConfigurationTest.java
@@ -456,6 +456,8 @@ public class WifiConfigurationTest {
config.setSecurityParams(SECURITY_TYPE_EAP_SUITE_B);
assertTrue(config.allowedKeyManagement.get(WifiConfiguration.KeyMgmt.SUITE_B_192));
+ assertTrue(config.allowedKeyManagement.get(WifiConfiguration.KeyMgmt.WPA_EAP));
+ assertTrue(config.allowedKeyManagement.get(WifiConfiguration.KeyMgmt.IEEE8021X));
assertTrue(config.allowedPairwiseCiphers.get(WifiConfiguration.PairwiseCipher.GCMP_256));
assertTrue(config.allowedGroupCiphers.get(WifiConfiguration.GroupCipher.GCMP_256));
assertTrue(config.allowedGroupManagementCiphers
diff --git a/wifi/tests/src/android/net/wifi/WifiManagerTest.java b/wifi/tests/src/android/net/wifi/WifiManagerTest.java
index 76ac8373374a..90d6241aaa55 100644
--- a/wifi/tests/src/android/net/wifi/WifiManagerTest.java
+++ b/wifi/tests/src/android/net/wifi/WifiManagerTest.java
@@ -2349,23 +2349,24 @@ public class WifiManagerTest {
}
/**
- * Verify that Wi-Fi connected scorer receives score change callback after registeration.
+ * Verify that Wi-Fi connected scorer receives score update observer after registeration.
*/
@Test
- public void verifyScorerReceiveScoreChangeCallbackAfterRegistration() throws Exception {
+ public void verifyScorerReceiveScoreUpdateObserverAfterRegistration() throws Exception {
mExecutor = new SynchronousExecutor();
mWifiManager.setWifiConnectedNetworkScorer(mExecutor, mWifiConnectedNetworkScorer);
ArgumentCaptor<IWifiConnectedNetworkScorer.Stub> scorerCaptor =
ArgumentCaptor.forClass(IWifiConnectedNetworkScorer.Stub.class);
verify(mWifiService).setWifiConnectedNetworkScorer(any(IBinder.class),
scorerCaptor.capture());
- scorerCaptor.getValue().setScoreChangeCallback(any());
+ scorerCaptor.getValue().onSetScoreUpdateObserver(any());
mLooper.dispatchAll();
- verify(mWifiConnectedNetworkScorer).setScoreChangeCallback(any());
+ verify(mWifiConnectedNetworkScorer).onSetScoreUpdateObserver(any());
}
/**
- * Verify that Wi-Fi connected scorer receives session ID when start/stop methods are called.
+ * Verify that Wi-Fi connected scorer receives session ID when onStart/onStop methods
+ * are called.
*/
@Test
public void verifyScorerReceiveSessionIdWhenStartStopIsCalled() throws Exception {
@@ -2375,11 +2376,11 @@ public class WifiManagerTest {
ArgumentCaptor.forClass(IWifiConnectedNetworkScorer.Stub.class);
verify(mWifiService).setWifiConnectedNetworkScorer(any(IBinder.class),
callbackCaptor.capture());
- callbackCaptor.getValue().start(0);
- callbackCaptor.getValue().stop(10);
+ callbackCaptor.getValue().onStart(0);
+ callbackCaptor.getValue().onStop(10);
mLooper.dispatchAll();
- verify(mWifiConnectedNetworkScorer).start(0);
- verify(mWifiConnectedNetworkScorer).stop(10);
+ verify(mWifiConnectedNetworkScorer).onStart(0);
+ verify(mWifiConnectedNetworkScorer).onStop(10);
}
@Test